diff --git a/pom.xml b/pom.xml index 215fcb60..6d9c32b8 100644 --- a/pom.xml +++ b/pom.xml @@ -92,13 +92,31 @@ org.junit.jupiter - junit-jupiter + junit-jupiter-api ${junit.version} test + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-params + ${junit.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + org.mockito - mockito-inline + mockito-junit-jupiter ${mockito.version} test diff --git a/src/main/java/com/cronutils/model/definition/CronDefinitionBuilder.java b/src/main/java/com/cronutils/model/definition/CronDefinitionBuilder.java index 53fad50d..cf47dad2 100755 --- a/src/main/java/com/cronutils/model/definition/CronDefinitionBuilder.java +++ b/src/main/java/com/cronutils/model/definition/CronDefinitionBuilder.java @@ -240,8 +240,7 @@ public void register(final FieldDefinition definition) { * @return returns CronDefinition instance, never null */ public CronDefinition instance() { - final Set validations = new HashSet<>(); - validations.addAll(cronConstraints); + final Set validations = new HashSet<>(cronConstraints); final List values = new ArrayList<>(fields.values()); values.sort(FieldDefinition.createFieldDefinitionComparator()); return new CronDefinition(values, validations, cronNicknames, matchDayOfWeekAndDayOfMonth); @@ -323,8 +322,8 @@ private static CronDefinition cron4j() { * * *

Thus in general Quartz cron expressions are as follows: - * - *

S M H DoM M DoW [Y] + * "0 30 17 ? * 7L *" + *

S M H DoM M DoW [Y] * * @return {@link CronDefinition} instance, never {@code null} */ @@ -414,7 +413,7 @@ private static CronDefinition spring() { /** * Creates CronDefinition instance matching Spring (v5.2 onwards) specification. - * https://spring.io/blog/2020/11/10/new-in-spring-5-3-improved-cron-expressions + * ... * *

The cron expression is expected to be a string comprised of 6 * fields separated by white space. Fields can contain any of the allowed @@ -498,9 +497,9 @@ private static CronDefinition unixCrontab() { return CronDefinitionBuilder.defineCron() .withMinutes().withValidRange(0, 59).withStrictRange().and() .withHours().withValidRange(0, 23).withStrictRange().and() - .withDayOfMonth().withValidRange(1, 31).withStrictRange().and() + .withDayOfMonth().withValidRange(1, 31).supportsL().supportsLW().supportsW().withStrictRange().and() .withMonth().withValidRange(1, 12).withStrictRange().and() - .withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7, 0).withStrictRange().and() + .withDayOfWeek().withValidRange(0, 7).withMondayDoWValue(1).withIntMapping(7, 0).supportsL().supportsW().withStrictRange().and() .instance(); } @@ -511,19 +510,12 @@ private static CronDefinition unixCrontab() { * @return CronDefinition instance if definition is found; a RuntimeException otherwise. */ public static CronDefinition instanceDefinitionFor(final CronType cronType) { - switch (cronType) { - case CRON4J: - return cron4j(); - case QUARTZ: - return quartz(); - case UNIX: - return unixCrontab(); - case SPRING: - return spring(); - case SPRING53: - return spring53(); - default: - throw new IllegalArgumentException(String.format("No cron definition found for %s", cronType)); - } + return switch (cronType) { + case CRON4J -> cron4j(); + case QUARTZ -> quartz(); + case UNIX -> unixCrontab(); + case SPRING -> spring(); + case SPRING53 -> spring53(); + }; } -} \ No newline at end of file +} diff --git a/src/test/java/com/cronutils/Issue143Test.java b/src/test/java/com/cronutils/Issue143Test.java index 247fd81a..34a06191 100755 --- a/src/test/java/com/cronutils/Issue143Test.java +++ b/src/test/java/com/cronutils/Issue143Test.java @@ -28,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -public class Issue143Test { +class Issue143Test { private static final String LAST_EXECUTION_NOT_PRESENT_ERROR = "last execution was not present"; private CronParser parser; @@ -44,7 +44,7 @@ public void setUp() { } @Test - public void testCase1() { + void testCase1() { ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 31 12 ? *")); Optional olast = et.lastExecution(currentDateTime); ZonedDateTime last = olast.orElse(null); @@ -55,7 +55,7 @@ public void testCase1() { } @Test - public void testCase2() { + void testCase2() { final ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 ? 12 SAT#5 *")); final Optional lastExecution = et.lastExecution(currentDateTime); if (lastExecution.isPresent()) { @@ -67,7 +67,7 @@ public void testCase2() { } @Test - public void testCase3() { + void testCase3() { final ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 31 1/1 ? *")); final Optional lastExecution = et.lastExecution(currentDateTime); if (lastExecution.isPresent()) { @@ -79,7 +79,7 @@ public void testCase3() { } @Test - public void testCase4() { + void testCase4() { final ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 ? 1/1 SAT#5 *")); final Optional lastExecution = et.lastExecution(currentDateTime); if (lastExecution.isPresent()) { diff --git a/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java b/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java index 825ed2c9..85330415 100755 --- a/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java +++ b/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java @@ -13,66 +13,75 @@ package com.cronutils.mapper; +import com.cronutils.model.Cron; import com.cronutils.model.CronType; +import com.cronutils.model.definition.CronDefinition; import com.cronutils.model.definition.CronDefinitionBuilder; import com.cronutils.parser.CronParser; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.util.Arrays; +import java.util.stream.Stream; +import static com.cronutils.model.CronType.CRON4J; +import static com.cronutils.model.CronType.QUARTZ; +import static com.cronutils.model.CronType.SPRING; +import static com.cronutils.model.CronType.UNIX; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -public class CronMapperIntegrationTest { - - @Test - public void testSpecificTimeCron4jToQuartz() { - assertEquals("0 30 8 10 6 ? *", CronMapper.fromCron4jToQuartz().map(cron4jParser().parse("30 8 10 6 *")).asString()); - } - - @Test - public void testMoreThanOneInstanceCron4jToQuartz() { - assertEquals("0 0 11,16 * * ? *", CronMapper.fromCron4jToQuartz().map(cron4jParser().parse("0 11,16 * * *")).asString()); - } - - @Test - public void testRangeOfTimeCron4jToQuartz() { - final String expression = "0 9-18 * * 1-3"; - final String expected = "0 0 9-18 ? * 2-4 *"; - assertEquals(expected, CronMapper.fromCron4jToQuartz().map(cron4jParser().parse(expression)).asString()); - } - - @Test - public void testSpecificTimeQuartzToCron4j() { - final String expression = "5 30 8 10 6 ? 1984"; - assertEquals("30 8 10 6 *", CronMapper.fromQuartzToCron4j().map(quartzParser().parse(expression)).asString()); - } - - @Test - public void testMoreThanOneInstanceQuartzToCron4j() { - final String expression = "5 0 11,16 * * ? 1984"; - assertEquals("0 11,16 * * *", CronMapper.fromQuartzToCron4j().map(quartzParser().parse(expression)).asString()); - } - - @Test - public void testRangeOfTimeQuartzToCron4j() { - final String expected = "0 9-18 * * 0-2"; - final String expression = "5 0 9-18 ? * 1-3 1984"; - assertEquals(expected, CronMapper.fromQuartzToCron4j().map(quartzParser().parse(expression)).asString()); - } - - @Test - public void testRangeOfTimeQuartzToSpring() { - final String expected = "5 0 9-18 ? * 0-2"; - final String expression = "5 0 9-18 ? * 1-3 1984"; - assertEquals(expected, CronMapper.fromQuartzToSpring().map(quartzParser().parse(expression)).asString()); +class CronMapperIntegrationTest { + static Stream cronExpressions() { + return Stream.of( + Arguments.of(CRON4J, CronMapper.fromCron4jToQuartz(), "0 11,16 * * *", "0 0 11,16 * * ? *"), + Arguments.of(CRON4J, CronMapper.fromCron4jToQuartz(), "0 9-18 * * 1-3", "0 0 9-18 ? * 2-4 *"), + Arguments.of(CRON4J, CronMapper.fromCron4jToQuartz(), "30 8 10 6 *", "0 30 8 10 6 ? *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToCron4j(), "0 0 0 ? * 5#1", "0 0 * * 4#1"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToCron4j(), "5 0 11,16 * * ? 1984", "0 11,16 * * *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToCron4j(), "5 0 9-18 ? * 1-3 1984", "0 9-18 * * 0-2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToCron4j(), "5 30 8 10 6 ? 1984", "30 8 10 6 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToSpring(), "0 0 0 ? * 5#1", "0 0 0 ? * 4#1"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToSpring(), "5 0 9-18 ? * 1-3 1984", "5 0 9-18 ? * 0-2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 1 ? 1/3 FRI#1 *", "0 1 * 1/3 5#1"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 2 ? 1/1 SUN#2", "0 2 * 1/1 0#2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 8,12 ? * *", "0 8,12 * * *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "* * 8 ? * SAT", "* 8 * * 6"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 22 ? * MON,TUE,WED,THU,FRI *", "0 22 * * 1,2,3,4,5"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 13 LW * ?", "0 13 LW * *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 1 1-12 ? *", "0 0 1 1-12 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 1 JAN ? 2099", "0 0 1 1 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 1,15 * ? *", "0 0 1,15 * *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 19 1-12 ? *", "0 0 19 1-12 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 21 * ? 2020-2025", "0 0 21 * *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 ? * 3L *", "0 0 * * 2L"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 ? 1/1 MON#2 *", "0 0 * 1/1 1#2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0,12 ? JAN,MAY,OCT * *", "0 0,12 * 1,5,10 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 13 ? 1,4,7,10 6#2", "0 13 * 1,4,7,10 5#2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 13 ? MAR,JUN,SEP,DEC 1L", "0 13 * 3,6,9,12 0L"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 L-10 1-12 ? *", "0 0 L-10 1-12 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0/5 * ? 1-12 4#2 *", "0/5 * * 1-12 3#2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 1 1W * ?", "0 1 1W * *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 13 ? 1,4,7,10 6#2", "0 13 * 1,4,7,10 5#2"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 15 14,19 ? JAN,MAY,JUL,OCT * *", "15 14,19 * 1,5,7,10 *"), + + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 ? * 5#1", "0 0 * * 4#1"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 0 0 L-10 1-12 ? *", "0 0 L-10 1-12 *"), + Arguments.of(QUARTZ, CronMapper.fromQuartzToUnix(), "0 30 17 ? * 7L *", "30 17 * * 6L"), + Arguments.of(SPRING, CronMapper.fromSpringToQuartz(), "0 0 0 ? * 5#1", "0 0 0 ? * 6#1 *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "* * * * 3,5-6,*/2,2/3,7/4", "0 * * ? * 4,6-7,*/2,3/3,1/4 *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "0 0 * * 1", "0 0 0 ? * 2 *") + ); } - @Test - public void testDaysOfWeekUnixToQuartz() { - final String input = "* * * * 3,5-6,*/2,2/3,7/4"; - final String expected = "0 * * ? * 4,6-7,*/2,3/3,1/4 *"; - assertEquals(expected, CronMapper.fromUnixToQuartz().map(unixParser().parse(input)).asString()); + @ParameterizedTest + @MethodSource("cronExpressions") + void testCronMapping(CronType cronType, CronMapper mapper, String quartzExpression, String expectedExpression) { + Cron sourceCron = getCron(cronType, quartzExpression); + String actualCron = mapper.map(sourceCron).asString(); + assertEquals(expectedExpression, actualCron, String.format("Expected [%s] but got [%s]", expectedExpression, actualCron)); } /** @@ -80,7 +89,7 @@ public void testDaysOfWeekUnixToQuartz() { * or patterns that involve every day of month and every day of week. */ @Test - public void testEveryMinuteUnixToQuartz() { + void testEveryMinuteUnixToQuartz() { final String input = "* * * * *"; final String expected1 = "0 * * * * ? *"; final String expected2 = "0 * * ? * * *"; @@ -96,22 +105,20 @@ public void testEveryMinuteUnixToQuartz() { * or patterns that involve every day of month and every day of week. */ @Test - public void testUnixToQuartzQuestionMarkRequired() { + void testUnixToQuartzQuestionMarkRequired() { final String input = "0 0 * * 1"; final String expected = "0 0 0 ? * 2 *"; final String mapping = CronMapper.fromUnixToQuartz().map(unixParser().parse(input)).asString(); assertEquals(expected, mapping, String.format("Expected [%s] but got [%s]", expected, mapping)); } - private CronParser cron4jParser() { - return new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J)); - } - - private CronParser quartzParser() { - return new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)); + private CronParser unixParser() { + return new CronParser(CronDefinitionBuilder.instanceDefinitionFor(UNIX)); } - private CronParser unixParser() { - return new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX)); + private Cron getCron(CronType cronType, String quartzExpression) { + final CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(cronType); + final CronParser parser = new CronParser(cronDefinition); + return parser.parse(quartzExpression); } } diff --git a/src/test/java/com/cronutils/mapper/CronMapperTest.java b/src/test/java/com/cronutils/mapper/CronMapperTest.java index 6fc24508..d4ca1d62 100755 --- a/src/test/java/com/cronutils/mapper/CronMapperTest.java +++ b/src/test/java/com/cronutils/mapper/CronMapperTest.java @@ -19,56 +19,52 @@ import com.cronutils.model.field.CronFieldName; import com.cronutils.model.field.expression.Always; import com.cronutils.model.field.expression.On; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; -public class CronMapperTest { - private CronFieldName testCronFieldName; +@ExtendWith(MockitoExtension.class) +class CronMapperTest { + private static final CronFieldName TEST_CRON_FIELD_NAME = CronFieldName.SECOND; + @Mock private CronField mockCronField; - @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - testCronFieldName = CronFieldName.SECOND; - } - @Test - public void testConstructorSourceDefinitionNull() { + void testConstructorSourceDefinitionNull() { assertThrows(NullPointerException.class, () -> new CronMapper(mock(CronDefinition.class), null, null)); } @Test - public void testConstructorTargetDefinitionNull() { + void testConstructorTargetDefinitionNull() { assertThrows(NullPointerException.class, () -> new CronMapper(null, mock(CronDefinition.class), null)); } @Test - public void testReturnSameExpression() { + void testReturnSameExpression() { final Function function = CronMapper.returnSameExpression(); assertEquals(mockCronField, function.apply(mockCronField)); } @Test - public void testReturnOnZeroExpression() { - final Function function = CronMapper.returnOnZeroExpression(testCronFieldName); + void testReturnOnZeroExpression() { + final Function function = CronMapper.returnOnZeroExpression(TEST_CRON_FIELD_NAME); - assertEquals(testCronFieldName, function.apply(mockCronField).getField()); + assertEquals(TEST_CRON_FIELD_NAME, function.apply(mockCronField).getField()); final On result = (On) function.apply(mockCronField).getExpression(); assertEquals(0, (int) result.getTime().getValue()); } @Test - public void testReturnAlwaysExpression() { - final Function function = CronMapper.returnAlwaysExpression(testCronFieldName); + void testReturnAlwaysExpression() { + final Function function = CronMapper.returnAlwaysExpression(TEST_CRON_FIELD_NAME); - assertEquals(testCronFieldName, function.apply(mockCronField).getField()); + assertEquals(TEST_CRON_FIELD_NAME, function.apply(mockCronField).getField()); assertEquals(Always.class, function.apply(mockCronField).getExpression().getClass()); } }