Add support for Quartz features in CronExpression

This commit introduces support for Quartz-specific features in
CronExpression. This includes support for "L", "W", and "#".

Closes gh-20106
Closes gh-22436
This commit is contained in:
Arjen Poutsma
2020-07-25 15:15:07 +02:00
parent 1a8906bdc3
commit 93b53dae29
8 changed files with 1350 additions and 231 deletions

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* 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
*
* https://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 org.springframework.scheduling.support;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.scheduling.support.BitSetAssert.assertThat;
/**
* @author Arjen Poutsma
*/
public class BitsCronFieldTests {
@Test
void parse() {
assertThat(BitsCronField.parseSeconds("42").bits()).hasUnsetRange(0, 41).hasSet(42).hasUnsetRange(43, 59);
assertThat(BitsCronField.parseMinutes("1,2,5,9").bits()).hasUnset(0).hasSet(1, 2).hasUnset(3,4).hasSet(5).hasUnsetRange(6,8).hasSet(9).hasUnsetRange(10,59);
assertThat(BitsCronField.parseSeconds("0-4,8-12").bits()).hasSetRange(0, 4).hasUnsetRange(5,7).hasSetRange(8, 12).hasUnsetRange(13,59);
assertThat(BitsCronField.parseHours("0-23/2").bits()).hasSet(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22).hasUnset(1,3,5,7,9,11,13,15,17,19,21,23);
assertThat(BitsCronField.parseDaysOfWeek("0").bits()).hasUnsetRange(0, 6).hasSet(7, 7);
assertThat(BitsCronField.parseSeconds("57/2").bits()).hasUnsetRange(0, 56).hasSet(57).hasUnset(58).hasSet(59);
}
@Test
void invalidRange() {
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseSeconds(""));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseSeconds("0-12/0"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseSeconds("60"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseMinutes("60"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseDaysOfMonth("0"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseDaysOfMonth("32"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseMonth("0"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseMonth("13"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseDaysOfWeek("8"));
assertThatIllegalArgumentException().isThrownBy(() -> BitsCronField.parseSeconds("20-10"));
}
@Test
void parseWildcards() {
assertThat(BitsCronField.parseSeconds("*").bits()).hasSetRange(0, 60);
assertThat(BitsCronField.parseMinutes("*").bits()).hasSetRange(0, 60);
assertThat(BitsCronField.parseHours("*").bits()).hasSetRange(0, 23);
assertThat(BitsCronField.parseDaysOfMonth("*").bits()).hasUnset(0).hasSetRange(1, 31);
assertThat(BitsCronField.parseDaysOfMonth("?").bits()).hasUnset(0).hasSetRange(1, 31);
assertThat(BitsCronField.parseMonth("*").bits()).hasUnset(0).hasSetRange(1, 12);
assertThat(BitsCronField.parseDaysOfWeek("*").bits()).hasUnset(0).hasSetRange(1, 7);
assertThat(BitsCronField.parseDaysOfWeek("?").bits()).hasUnset(0).hasSetRange(1, 7);
}
@Test
void names() {
assertThat(((BitsCronField)CronField.parseMonth("JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC")).bits())
.hasUnset(0).hasSetRange(1, 12);
assertThat(((BitsCronField)CronField.parseDaysOfWeek("SUN,MON,TUE,WED,THU,FRI,SAT")).bits())
.hasUnset(0).hasSetRange(1, 7);
}
}

View File

@@ -22,11 +22,16 @@ import java.time.LocalTime;
import java.time.Year;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.util.Locale;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Test;
import static java.time.DayOfWeek.FRIDAY;
import static java.time.DayOfWeek.MONDAY;
import static java.time.DayOfWeek.SATURDAY;
import static java.time.DayOfWeek.SUNDAY;
import static java.time.DayOfWeek.TUESDAY;
import static java.time.DayOfWeek.WEDNESDAY;
@@ -38,6 +43,16 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class CronExpressionTests {
private static final Condition<Temporal> weekday = new Condition<Temporal>("weekday") {
@Override
public boolean matches(Temporal value) {
int dayOfWeek = value.get(ChronoField.DAY_OF_WEEK);
return dayOfWeek != 6 && dayOfWeek != 7;
}
};
@Test
void matchAll() {
CronExpression expression = CronExpression.parse("* * * * * *");
@@ -583,4 +598,504 @@ class CronExpressionTests {
}
@Test
void quartzLastDayOfMonth() {
CronExpression expression = CronExpression.parse("0 0 0 L * *");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 31, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.of(2008, 2, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.of(2008, 3, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.of(2008, 4, 30, 0, 0);
assertThat(expression.next(last)).isEqualTo(expected);
}
@Test
void quartzLastDayOfMonthOffset() {
// L-3 = third-to-last day of the month
CronExpression expression = CronExpression.parse("0 0 0 L-3 * *");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 28, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.of(2008, 2, 26, 0, 0);
actual = expression.next(last);
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.of(2008, 3, 28, 0, 0);
actual = expression.next(last);
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.of(2008, 4, 27, 0, 0);
assertThat(expression.next(last)).isEqualTo(expected);
}
@Test
void quartzLastWeekdayOfMonth() {
CronExpression expression = CronExpression.parse("0 0 0 LW * *");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 31, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 2, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 3, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 4, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 5, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 6, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 7, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 8, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 9, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 10, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 11, 28, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2008, 12, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
}
@Test
public void quartzLastDayOfWeekFirstDayMonday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.UK);
CronExpression expression = CronExpression.parse("0 0 0 * * L");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 6, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
last = actual;
expected = expected.plusWeeks(1);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
public void quartzLastDayOfWeekFirstDaySunday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.US);
CronExpression expression = CronExpression.parse("0 0 0 * * L");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 5, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
last = actual;
expected = expected.plusWeeks(1);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
public void quartzLastDayOfWeekOffset() {
// last Friday (5) of the month
CronExpression expression = CronExpression.parse("0 0 0 * * 5L");
LocalDateTime last = LocalDateTime.of(LocalDate.of(2008, 1, 4), LocalTime.now());
LocalDateTime expected = LocalDateTime.of(2008, 1, 25, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 2, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 3, 28, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 4, 25, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 5, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 6, 27, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 7, 25, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 8, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 9, 26, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 10, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 11, 28, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2008, 12, 26, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
}
@Test
void quartzWeekdayNearestTo15() {
CronExpression expression = CronExpression.parse("0 0 0 15W * ?");
LocalDateTime last = LocalDateTime.of(2020, 1, 1, 0, 0);
LocalDateTime expected = LocalDateTime.of(2020, 1, 15, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 2, 14, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 3, 16, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 4, 15, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
}
@Test
void quartzWeekdayNearestTo1() {
CronExpression expression = CronExpression.parse("0 0 0 1W * ?");
LocalDateTime last = LocalDateTime.of(2019, 12, 31, 0, 0);
LocalDateTime expected = LocalDateTime.of(2020, 1, 1, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 2, 3, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 3, 2, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 4, 1, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
}
@Test
void quartzWeekdayNearestTo31() {
CronExpression expression = CronExpression.parse("0 0 0 31W * ?");
LocalDateTime last = LocalDateTime.of(2020, 1, 1, 0, 0);
LocalDateTime expected = LocalDateTime.of(2020, 1, 31, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 3, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 7, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 8, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 10, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
last = actual;
expected = LocalDateTime.of(2020, 12, 31, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual).is(weekday);
}
@Test
void quartz2ndFridayOfTheMonth() {
CronExpression expression = CronExpression.parse("0 0 0 ? * 5#2");
LocalDateTime last = LocalDateTime.of(2020, 1, 1, 0, 0);
LocalDateTime expected = LocalDateTime.of(2020, 1, 10, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2020, 2, 14, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2020, 3, 13, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2020, 4, 10, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
}
@Test
void quartz2ndFridayOfTheMonthDayName() {
CronExpression expression = CronExpression.parse("0 0 0 ? * FRI#2");
LocalDateTime last = LocalDateTime.of(2020, 1, 1, 0, 0);
LocalDateTime expected = LocalDateTime.of(2020, 1, 10, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2020, 2, 14, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2020, 3, 13, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
last = actual;
expected = LocalDateTime.of(2020, 4, 10, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(FRIDAY);
}
@Test
void quartzFifthWednesdayOfTheMonth() {
CronExpression expression = CronExpression.parse("0 0 0 ? * 3#5");
LocalDateTime last = LocalDateTime.of(2020, 1, 1, 0, 0);
LocalDateTime expected = LocalDateTime.of(2020, 1, 29, 0, 0);
LocalDateTime actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(WEDNESDAY);
last = actual;
expected = LocalDateTime.of(2020, 4, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(WEDNESDAY);
last = actual;
expected = LocalDateTime.of(2020, 7, 29, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(WEDNESDAY);
last = actual;
expected = LocalDateTime.of(2020, 9, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(WEDNESDAY);
last = actual;
expected = LocalDateTime.of(2020, 12, 30, 0, 0);
actual = expression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(WEDNESDAY);
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* 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
*
* https://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 org.springframework.scheduling.support;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.scheduling.support.BitSetAssert.assertThat;
/**
* @author Arjen Poutsma
*/
public class CronFieldTests {
@Test
void parse() {
assertThat(CronField.parseSeconds("42").bits()).hasUnsetRange(0, 41).hasSet(42).hasUnsetRange(43, 59);
assertThat(CronField.parseMinutes("1,2,5,9").bits()).hasUnset(0).hasSet(1, 2).hasUnset(3,4).hasSet(5).hasUnsetRange(6,8).hasSet(9).hasUnsetRange(10,59);
assertThat(CronField.parseSeconds("0-4,8-12").bits()).hasSetRange(0, 4).hasUnsetRange(5,7).hasSetRange(8, 12).hasUnsetRange(13,59);
assertThat(CronField.parseHours("0-23/2").bits()).hasSet(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22).hasUnset(1,3,5,7,9,11,13,15,17,19,21,23);
assertThat(CronField.parseDaysOfWeek("0").bits()).hasUnsetRange(0, 6).hasSet(7, 7);
assertThat(CronField.parseSeconds("57/2").bits()).hasUnsetRange(0, 56).hasSet(57).hasUnset(58).hasSet(59);
}
@Test
void invalidRange() {
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseSeconds(""));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseSeconds("0-12/0"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseSeconds("60"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseMinutes("60"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseDaysOfMonth("0"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseDaysOfMonth("32"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseMonth("0"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseMonth("13"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseDaysOfWeek("8"));
assertThatIllegalArgumentException().isThrownBy(() -> CronField.parseSeconds("20-10"));
}
@Test
void parseWildcards() {
assertThat(CronField.parseSeconds("*").bits()).hasSetRange(0, 60);
assertThat(CronField.parseMinutes("*").bits()).hasSetRange(0, 60);
assertThat(CronField.parseHours("*").bits()).hasSetRange(0, 23);
assertThat(CronField.parseDaysOfMonth("*").bits()).hasUnset(0).hasSetRange(1, 31);
assertThat(CronField.parseDaysOfMonth("?").bits()).hasUnset(0).hasSetRange(1, 31);
assertThat(CronField.parseMonth("*").bits()).hasUnset(0).hasSetRange(1, 12);
assertThat(CronField.parseDaysOfWeek("*").bits()).hasUnset(0).hasSetRange(1, 7);
assertThat(CronField.parseDaysOfWeek("?").bits()).hasUnset(0).hasSetRange(1, 7);
}
@Test
void names() {
assertThat(CronField.parseMonth("JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC").bits())
.hasUnset(0).hasSetRange(1, 12);
assertThat(CronField.parseDaysOfWeek("SUN,MON,TUE,WED,THU,FRI,SAT").bits())
.hasUnset(0).hasSetRange(1, 7);
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* 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
*
* https://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 org.springframework.scheduling.support;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static java.time.DayOfWeek.SATURDAY;
import static java.time.DayOfWeek.SUNDAY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* @author Arjen Poutsma
*/
class QuartzCronFieldTests {
@Test
void lastDayOfMonth() {
QuartzCronField field = QuartzCronField.parseDaysOfMonth("L");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 30);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
}
@Test
void lastDayOfMonthOffset() {
QuartzCronField field = QuartzCronField.parseDaysOfMonth("L-3");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 27);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
}
@Test
void lastWeekdayOfMonth() {
QuartzCronField field = QuartzCronField.parseDaysOfMonth("LW");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 30);
LocalDate actual = field.nextOrSame(last);
assertThat(actual).isNotNull();
assertThat(actual.getDayOfWeek()).isEqualTo(DayOfWeek.TUESDAY);
assertThat(actual).isEqualTo(expected);
}
@Test
public void lastDayOfWeekFirstDayMonday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.UK);
QuartzCronField field = QuartzCronField.parseDaysOfWeek("L");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 21);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
LocalDate actual = field.nextOrSame(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SUNDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
public void lastDayOfWeekFirstDaySunday() {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.US);
QuartzCronField field = QuartzCronField.parseDaysOfWeek("L");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 20);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
LocalDate actual = field.nextOrSame(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
assertThat(actual.getDayOfWeek()).isEqualTo(SATURDAY);
}
finally {
Locale.setDefault(defaultLocale);
}
}
@Test
void lastDayOfWeekOffset() {
// last Thursday (4) of the month
QuartzCronField field = QuartzCronField.parseDaysOfWeek("4L");
LocalDate last = LocalDate.of(2020, 6, 16);
LocalDate expected = LocalDate.of(2020, 6, 25);
assertThat(field.nextOrSame(last)).isEqualTo(expected);
}
@Test
void invalidValues() {
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth(""));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("1L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("LL"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("4L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("0L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("W"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("W1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("WW"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfMonth("32W"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek(""));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("LL"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("-4L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("8L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("#"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("1#"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("#1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("1#L"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("L#1"));
assertThatIllegalArgumentException().isThrownBy(() -> QuartzCronField.parseDaysOfWeek("8#1"));
}
}