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..b57ae602 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 @@ -492,15 +491,20 @@ private static CronDefinition spring53() { /** * Creates CronDefinition instance matching unix crontab specification. * + *

Beyond the POSIX crontab syntax, day of month additionally accepts {@code L}, {@code L-n}, + * {@code nW} and {@code LW}, and day of week additionally accepts {@code L} and {@code nL}. + * + *

M H DoM M DoW + * * @return CronDefinition instance, never null; */ 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().withStrictRange().and() .instance(); } @@ -511,19 +515,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/Issue670Test.java b/src/test/java/com/cronutils/Issue670Test.java new file mode 100644 index 00000000..7d9f0b30 --- /dev/null +++ b/src/test/java/com/cronutils/Issue670Test.java @@ -0,0 +1,130 @@ +/* + * Copyright 2015 jmrozanec + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cronutils; + +import com.cronutils.descriptor.CronDescriptor; +import com.cronutils.model.Cron; +import com.cronutils.model.CronType; +import com.cronutils.model.definition.CronDefinitionBuilder; +import com.cronutils.model.time.ExecutionTime; +import com.cronutils.parser.CronParser; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Locale; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unix crontab support for the L, LW and W special characters. + */ +class Issue670Test { + + private final CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX)); + private final CronDescriptor descriptor = CronDescriptor.instance(Locale.UK); + + @ParameterizedTest + @ValueSource(strings = { + "0 0 L * *", + "0 0 L-3 * *", + "0 0 LW * *", + "0 13 LW * *", + "0 0 1W * *", + "0 0 15W * *", + "0 0 L,15 * *", + "0 0 * * L", + "0 0 * * 0L", + "0 0 * * 6L", + "0 0 LW * 6L" + }) + void unixParserAcceptsSpecialChars(String expression) { + final Cron cron = parser.parse(expression); + cron.validate(); + assertEquals(expression, cron.asString()); + } + + /** + * W is a day-of-month modifier ("nearest weekday to the nth"); it has no day-of-week meaning + * and no value generator implements it there, so it must not parse. + */ + @ParameterizedTest + @ValueSource(strings = {"0 0 * * 5W", "0 0 * * 0W", "0 0 * * 1W", "0 0 * * LW", "0 0 * * 1-5W"}) + void unixParserRejectsWInDayOfWeek(String expression) { + assertThrows(IllegalArgumentException.class, () -> parser.parse(expression)); + } + + @Test + void unixParserRejectsBareWInDayOfMonth() { + assertThrows(IllegalArgumentException.class, () -> parser.parse("0 0 W * *")); + } + + @ParameterizedTest + @CsvSource({ + // June 2025: 1st is a Sunday, 14th a Saturday, 30th a Monday + "0 0 L * *, 2025-06-30", + "0 0 L-3 * *, 2025-06-27", + "0 0 LW * *, 2025-06-30", + "0 0 1W * *, 2025-06-02", + "0 0 14W * *, 2025-06-13", + "0 0 15W * *, 2025-06-16", + "0 0 * * 1L, 2025-06-30", + "0 0 * * 6L, 2025-06-28", + "0 0 * * 0L, 2025-06-29", + // November 2025: 1st is a Saturday, so the nearest weekday rolls forward to Monday the 3rd + "0 0 1W 11 *, 2025-11-03", + // February 2026: last day is Saturday the 28th, so LW is Friday the 27th + "0 0 LW 2 *, 2026-02-27" + }) + void nextExecutionMatchesSpecialChar(String expression, String expectedDate) { + final ZonedDateTime from = ZonedDateTime.of(2025, 6, 1, 0, 0, 0, 0, ZoneOffset.UTC); + final ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(expression)); + final ZonedDateTime next = executionTime.nextExecution(from) + .orElseThrow(() -> new AssertionError(String.format("no next execution for [%s]", expression))); + + assertEquals(LocalDate.parse(expectedDate), next.toLocalDate()); + assertTrue(executionTime.isMatch(next), String.format("[%s] should match its own next execution", expression)); + } + + /** + * Unix day-of-month and day-of-week are OR'ed when both are restricted. + */ + @Test + void dayOfMonthAndDayOfWeekAreOred() { + final ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 LW * 6L")); + final ZonedDateTime lastSaturday = ZonedDateTime.of(2025, 6, 28, 0, 0, 0, 0, ZoneOffset.UTC); + final ZonedDateTime lastWeekday = ZonedDateTime.of(2025, 6, 30, 0, 0, 0, 0, ZoneOffset.UTC); + + assertTrue(executionTime.isMatch(lastSaturday), "last Saturday should match"); + assertTrue(executionTime.isMatch(lastWeekday), "last weekday should match"); + } + + @ParameterizedTest + @CsvSource({ + "0 0 L * *, at 00:00 last day of month", + "0 0 L-10 * *, at 00:00 10 days before the last day of the month", + "0 0 LW * *, at 00:00 last weekday of month", + "0 0 1W * *, at 00:00 the nearest weekday to the 1 of the month", + "0 0 * * 6L, at 00:00 last Saturday of every month" + }) + void descriptorDescribesSpecialChars(String expression, String expectedDescription) { + assertEquals(expectedDescription, descriptor.describe(parser.parse(expression))); + } +} diff --git a/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java b/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java index 825ed2c9..749dce67 100755 --- a/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java +++ b/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java @@ -13,66 +13,80 @@ 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 *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "0 0 L * *", "0 0 0 L * ? *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "0 0 L-3 * *", "0 0 0 L-3 * ? *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "0 13 LW * *", "0 0 13 LW * ? *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "0 1 1W * *", "0 0 1 1W * ? *"), + Arguments.of(UNIX, CronMapper.fromUnixToQuartz(), "0 0 * * 6L", "0 0 0 ? * 7L *") + ); } - @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 +94,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 +110,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()); } }