Skip to content

Commit 2fb1bc6

Browse files
committed
Crons make me sad.
Signed-off-by: Alexander Trauzzi <[email protected]>
1 parent fa6682f commit 2fb1bc6

File tree

2 files changed

+61
-17
lines changed

2 files changed

+61
-17
lines changed

src/types/jobs/CronExpression.type.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,14 @@ export class CronExpressionBuilder {
8585
}
8686

8787
export class CronExpression {
88-
private static readonly SecondsAndMinutesRegexText = /.*/;
89-
private static readonly HoursRegexText = /.*/;
90-
private static readonly DayOfMonthRegexText = /.*/;
91-
// (^(\*\/)?((0?\d)|(1[0-2]))$)|(^\*$)|(^((0?\d)|(1[0-2]))(-((0?\d)|(1[0-2]))?)$)|(^(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:-(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:-(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*$)
92-
private static readonly MonthRegexText = /.*/;
93-
// \*|(\*\/(0?[0-6])|(0?[0-6](-0?[0-6])?)|((,?(SUN|MON|TUE|WED|THU|FRI|SAT))+)|((SUN|MON|TUE|WED|THU|FRI|SAT)(-(SUN|MON|TUE|WED|THU|FRI|SAT))?))
94-
private static readonly DayOfWeekRegexText = /.*/;
95-
96-
private static readonly cronExpressionRegex = new RegExp(
97-
`${CronExpression.SecondsAndMinutesRegexText.source} ${CronExpression.SecondsAndMinutesRegexText.source} ${CronExpression.HoursRegexText.source} ${CronExpression.DayOfMonthRegexText.source} ${CronExpression.MonthRegexText.source} ${CronExpression.DayOfWeekRegexText.source}`,
88+
public static readonly SecondsAndMinutesRegexText = /(?:\*(?:\/[0-5]?\d)?|(?:[0-5]?\d)(?:-(?:[0-5]?\d))?(?:,(?:[0-5]?\d)(?:-(?:[0-5]?\d))?)*)/;
89+
public static readonly HoursRegexText = /(?:\*(?:\/(?:[0-1]?\d|2[0-3]))?|(?:[0-1]?\d|2[0-3])(?:-(?:[0-1]?\d|2[0-3]))?(?:,(?:[0-1]?\d|2[0-3])(?:-(?:[0-1]?\d|2[0-3]))?)*)/;
90+
public static readonly DayOfMonthRegexText = /(?:\*(?:\/(?:[1-9]|[12]\d|3[01]))?|(?:[1-9]|[12]\d|3[01])(?:-(?:[1-9]|[12]\d|3[01]))?(?:,(?:[1-9]|[12]\d|3[01])(?:-(?:[1-9]|[12]\d|3[01]))?)*)/;
91+
public static readonly MonthRegexText = /(?:\*(?:\/(?:0?[1-9]|1[0-2]))?|(?:0?[1-9]|1[0-2])(?:-(?:0?[1-9]|1[0-2]))?(?:,(?:0?[1-9]|1[0-2])(?:-(?:0?[1-9]|1[0-2]))?)*)|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:-(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:-(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*/;
92+
public static readonly DayOfWeekRegexText = /(?:\*(?:\/[0-6])?|[0-6](?:-[0-6])?(?:,[0-6](?:-[0-6])?)*)|(?:SUN|MON|TUE|WED|THU|FRI|SAT)(?:-(?:SUN|MON|TUE|WED|THU|FRI|SAT))?(?:,(?:SUN|MON|TUE|WED|THU|FRI|SAT)(?:-(?:SUN|MON|TUE|WED|THU|FRI|SAT))?)*/;
93+
94+
public static readonly cronExpressionRegex = new RegExp(
95+
`^(${CronExpression.SecondsAndMinutesRegexText.source})\\s(${CronExpression.SecondsAndMinutesRegexText.source})\\s(${CronExpression.HoursRegexText.source})\\s(${CronExpression.DayOfMonthRegexText.source})\\s(${CronExpression.MonthRegexText.source})\\s(${CronExpression.DayOfWeekRegexText.source})$`,
9896
);
9997

10098
public static isCronExpression(value: string) {

test/unit/jobs/cron.test.ts

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,66 @@ import {
2020
} from "../../../src/types/jobs/CronExpression.type";
2121

2222
describe("CRON Expressions", () => {
23+
24+
it("Seconds and minutes regexes are good", () => {
25+
expect(CronExpression.SecondsAndMinutesRegexText.test("*")).toBe(true);
26+
expect(CronExpression.SecondsAndMinutesRegexText.test("1")).toBe(true);
27+
expect(CronExpression.SecondsAndMinutesRegexText.test("0/5")).toBe(true);
28+
expect(CronExpression.SecondsAndMinutesRegexText.test("3-9")).toBe(true);
29+
expect(CronExpression.SecondsAndMinutesRegexText.test("2,6,10,14,18,22")).toBe(true);
30+
});
31+
32+
it("Hours regex is good", () => {
33+
expect(CronExpression.HoursRegexText.test("*")).toBe(true);
34+
expect(CronExpression.HoursRegexText.test("1")).toBe(true);
35+
expect(CronExpression.HoursRegexText.test("0/5")).toBe(true);
36+
expect(CronExpression.HoursRegexText.test("3-9")).toBe(true);
37+
expect(CronExpression.HoursRegexText.test("2,6,10,14,18,22")).toBe(true);
38+
});
39+
40+
it("Day of month regex is good", () => {
41+
expect(CronExpression.DayOfMonthRegexText.test("*")).toBe(true);
42+
expect(CronExpression.DayOfMonthRegexText.test("1")).toBe(true);
43+
expect(CronExpression.DayOfMonthRegexText.test("0/5")).toBe(true);
44+
expect(CronExpression.DayOfMonthRegexText.test("3-9")).toBe(true);
45+
expect(CronExpression.DayOfMonthRegexText.test("2,6,10,14,18,22")).toBe(true);
46+
});
47+
48+
it("Month regex is good", () => {
49+
expect(CronExpression.MonthRegexText.test("*")).toBe(true);
50+
expect(CronExpression.MonthRegexText.test("1")).toBe(true);
51+
expect(CronExpression.MonthRegexText.test("0/5")).toBe(true);
52+
expect(CronExpression.MonthRegexText.test("3-9")).toBe(true);
53+
expect(CronExpression.MonthRegexText.test("3-9")).toBe(true);
54+
expect(CronExpression.MonthRegexText.test("2,6,10")).toBe(true);
55+
});
56+
57+
it("Day of week regex is good", () => {
58+
expect(CronExpression.DayOfWeekRegexText.test("*")).toBe(true);
59+
expect(CronExpression.DayOfWeekRegexText.test("1")).toBe(true);
60+
expect(CronExpression.DayOfWeekRegexText.test("0/5")).toBe(true);
61+
expect(CronExpression.DayOfWeekRegexText.test("3-7")).toBe(true);
62+
expect(CronExpression.DayOfWeekRegexText.test("2,6,3")).toBe(true);
63+
});
64+
65+
it("Every second string is valid", () => {
66+
expect(CronExpression.isCronExpression("* * * * * *")).toBe(true);
67+
});
68+
2369
it("Every minute string is valid", () => {
24-
expect(CronExpression.isCronExpression("* * * * *")).toBe(true);
70+
expect(CronExpression.isCronExpression("0 * * * * *")).toBe(true);
2571
});
2672

2773
it("Every hour string is valid", () => {
28-
expect(CronExpression.isCronExpression("0 * * * *")).toBe(true);
74+
expect(CronExpression.isCronExpression("0 0 * * * *")).toBe(true);
2975
});
3076

3177
it("Every third hour on Mondays string is valid", () => {
32-
expect(CronExpression.isCronExpression("0 */3 * * 1")).toBe(true);
78+
expect(CronExpression.isCronExpression("0 0 */3 * * 1")).toBe(true);
3379
});
3480

3581
it("A fairly complicated string is valid", () => {
36-
expect(CronExpression.isCronExpression("0/5 2,6,10,14,18,22 8-14 * 1")).toBe(true);
82+
expect(CronExpression.isCronExpression("*/5 2,6,10 8-14 * 1 *")).toBe(true);
3783
});
3884

3985
it("On second results in matching cron string", () => {
@@ -94,9 +140,9 @@ describe("CRON Expressions", () => {
94140
});
95141

96142
it("Through hours should create a valid cron string", () => {
97-
const cronExpression = CronExpressionBuilder.through(CronPeriod.Hour, 13, 42).toString();
143+
const cronExpression = CronExpressionBuilder.through(CronPeriod.Hour, 13, 15).toString();
98144

99-
expect(cronExpression).toEqual("* * 13-42 * * *");
145+
expect(cronExpression).toEqual("* * 13-15 * * *");
100146
});
101147

102148
it("Through days of the month should create a valid cron string", () => {
@@ -138,7 +184,7 @@ describe("CRON Expressions", () => {
138184
});
139185

140186
it("Bad through hours order should fail", () => {
141-
const cronExpressionThrow = () => CronExpressionBuilder.through(CronPeriod.Hour, 59, 14).toString();
187+
const cronExpressionThrow = () => CronExpressionBuilder.through(CronPeriod.Hour, 23, 14).toString();
142188

143189
expect(cronExpressionThrow).toThrow();
144190
});

0 commit comments

Comments
 (0)