Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(system): add cron #897

Merged
merged 17 commits into from Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/modules/system/index.ts
Expand Up @@ -22,6 +22,16 @@ const commonInterfaceSchemas = {
pci: 'p',
} as const;

const CRON_DAY_OF_WEEK = [
'SUN',
'MON',
'TUE',
'WED',
'THU',
'FRI',
'SAT',
] as const;

/**
* Generates fake data for many computer systems properties.
*/
Expand Down Expand Up @@ -264,4 +274,67 @@ export class System {

return `${prefix}${interfaceType}${commonInterfaceSchemas[interfaceSchema]}${suffix}`;
}

/**
* Returns a random cron expression.
*
* @param options The optional options to use.
* @param options.includeYear Whether to include a year in the generated expression. Defaults to `false`.
* @param options.includeNonStandard Whether to include a @yearly, @monthly, @daily, etc text labels in the generated expression. Defaults to `false`.
*
* @example
* faker.system.cron() // '45 23 * * 6'
* faker.system.cron({ includeYear: true }) // '45 23 * * 6 2067'
* faker.system.cron({ includeYear: false }) // '45 23 * * 6'
* faker.system.cron({ includeNonStandard: false }) // '45 23 * * 6'
* faker.system.cron({ includeNonStandard: true }) // '@yearly'
*/
cron(
options: {
includeYear?: boolean;
includeNonStandard?: boolean;
} = {}
): string {
const { includeYear = false, includeNonStandard = false } = options;

// create the arrays to hold the available values for each component of the expression
const minutes = [this.faker.datatype.number({ min: 0, max: 59 }), '*'];
const hours = [this.faker.datatype.number({ min: 0, max: 23 }), '*'];
const days = [this.faker.datatype.number({ min: 1, max: 31 }), '*', '?'];
const months = [this.faker.datatype.number({ min: 1, max: 12 }), '*'];
const daysOfWeek = [
this.faker.datatype.number({ min: 0, max: 6 }),
this.faker.helpers.arrayElement(CRON_DAY_OF_WEEK),
'*',
'?',
];
const years = [this.faker.datatype.number({ min: 1970, max: 2099 }), '*'];

const minute = this.faker.helpers.arrayElement(minutes);
const hour = this.faker.helpers.arrayElement(hours);
const day = this.faker.helpers.arrayElement(days);
const month = this.faker.helpers.arrayElement(months);
const dayOfWeek = this.faker.helpers.arrayElement(daysOfWeek);
const year = this.faker.helpers.arrayElement(years);

// create and return the cron expression string
let standardExpression = `${minute} ${hour} ${day} ${month} ${dayOfWeek}`;
if (includeYear) {
standardExpression += ` ${year}`;
}

const nonStandardExpressions = [
'@annually',
'@daily',
'@hourly',
'@monthly',
'@reboot',
'@weekly',
'@yearly',
];

return !includeNonStandard || this.faker.datatype.boolean()
? standardExpression
: this.faker.helpers.arrayElement(nonStandardExpressions);
xDivisionByZerox marked this conversation as resolved.
Show resolved Hide resolved
}
}
36 changes: 36 additions & 0 deletions test/__snapshots__/system.spec.ts.snap
Expand Up @@ -8,6 +8,16 @@ exports[`system > 42 > commonFileName > with extension 1`] = `"mobile_fish.ext"`

exports[`system > 42 > commonFileType 1`] = `"audio"`;

exports[`system > 42 > cron > noArgs 1`] = `"* 19 * 3 5"`;

exports[`system > 42 > cron > with includeNonStandard false 1`] = `"* 19 * 3 5"`;

exports[`system > 42 > cron > with includeNonStandard true 1`] = `"@yearly"`;

exports[`system > 42 > cron > with includeYear false 1`] = `"* 19 * 3 5"`;

exports[`system > 42 > cron > with includeYear true 1`] = `"* 19 * 3 5 2047"`;

exports[`system > 42 > directoryPath 1`] = `"/opt/bin"`;

exports[`system > 42 > fileExt > noArgs 1`] = `"lrm"`;
Expand Down Expand Up @@ -76,6 +86,16 @@ exports[`system > 1211 > commonFileName > with extension 1`] = `"functionalities

exports[`system > 1211 > commonFileType 1`] = `"application"`;

exports[`system > 1211 > cron > noArgs 1`] = `"55 * 28 * 1"`;

exports[`system > 1211 > cron > with includeNonStandard false 1`] = `"55 * 28 * 1"`;

exports[`system > 1211 > cron > with includeNonStandard true 1`] = `"@hourly"`;

exports[`system > 1211 > cron > with includeYear false 1`] = `"55 * 28 * 1"`;

exports[`system > 1211 > cron > with includeYear true 1`] = `"55 * 28 * 1 *"`;

exports[`system > 1211 > directoryPath 1`] = `"/var/log"`;

exports[`system > 1211 > fileExt > noArgs 1`] = `"dic"`;
Expand Down Expand Up @@ -144,6 +164,16 @@ exports[`system > 1337 > commonFileName > with extension 1`] = `"delaware.ext"`;

exports[`system > 1337 > commonFileType 1`] = `"audio"`;

exports[`system > 1337 > cron > noArgs 1`] = `"15 13 5 * *"`;

exports[`system > 1337 > cron > with includeNonStandard false 1`] = `"15 13 5 * *"`;

exports[`system > 1337 > cron > with includeNonStandard true 1`] = `"@yearly"`;

exports[`system > 1337 > cron > with includeYear false 1`] = `"15 13 5 * *"`;

exports[`system > 1337 > cron > with includeYear true 1`] = `"15 13 5 * * 2029"`;

exports[`system > 1337 > directoryPath 1`] = `"/Library"`;

exports[`system > 1337 > fileExt > noArgs 1`] = `"oa3"`;
Expand Down Expand Up @@ -210,6 +240,8 @@ exports[`system > seed: 42 > commonFileName() 1`] = `"mobile_fish.mpe"`;

exports[`system > seed: 42 > commonFileType() 1`] = `"audio"`;

exports[`system > seed: 42 > cron() 1`] = `"* 19 * 3 5"`;

exports[`system > seed: 42 > directoryPath() 1`] = `"/opt/bin"`;

exports[`system > seed: 42 > fileExt() 1`] = `"lrm"`;
Expand All @@ -232,6 +264,8 @@ exports[`system > seed: 1211 > commonFileName() 1`] = `"functionalities_frozen_b

exports[`system > seed: 1211 > commonFileType() 1`] = `"application"`;

exports[`system > seed: 1211 > cron() 1`] = `"55 * 28 * 1"`;

exports[`system > seed: 1211 > directoryPath() 1`] = `"/var/log"`;

exports[`system > seed: 1211 > fileExt() 1`] = `"dic"`;
Expand All @@ -254,6 +288,8 @@ exports[`system > seed: 1337 > commonFileName() 1`] = `"delaware.mp2"`;

exports[`system > seed: 1337 > commonFileType() 1`] = `"audio"`;

exports[`system > seed: 1337 > cron() 1`] = `"15 13 5 * *"`;

exports[`system > seed: 1337 > directoryPath() 1`] = `"/Library"`;

exports[`system > seed: 1337 > fileExt() 1`] = `"oa3"`;
Expand Down
44 changes: 44 additions & 0 deletions test/system.spec.ts
Expand Up @@ -10,6 +10,7 @@ const functionNames = [
'commonFileExt',
'commonFileName',
'commonFileType',
'cron',
'directoryPath',
'fileExt',
'fileName',
Expand Down Expand Up @@ -65,6 +66,14 @@ describe('system', () => {
}
}
});

t.describe('cron', (t) => {
t.it('noArgs')
.it('with includeYear true', { includeYear: true })
.it('with includeYear false', { includeYear: false })
.it('with includeNonStandard true', { includeNonStandard: true })
.it('with includeNonStandard false', { includeNonStandard: false });
});
});

for (const seed of seededRuns) {
Expand Down Expand Up @@ -385,6 +394,41 @@ describe('system', () => {
).toMatch(/^enx[a-f\d]{12}$/);
});
});

describe('cron()', () => {
const regex =
/^([1-9]|[1-5]\d|\*) ([0-9]|1\d|2[0-3]|\*) ([1-9]|[12]\d|3[01]|\*|\?) ([1-9]|1[0-2]|\*) ([0-6]|\*|\?|[A-Z]{3}) ((19[7-9]d)|20\d{2}|\*)?/;

const regexElements = regex.toString().replace(/\//g, '').split(' ');

it.each([
[{}, 5],
[{ includeYear: false }, 5],
[{ includeYear: true }, 6],
])(
'should return cron expression with correct number of valid elements - %o, %d',
(options, count: number) => {
const cron = faker.system.cron(options).split(' ');
expect(cron).toHaveLength(count);
cron.forEach((cronElement, i) =>
expect(
cronElement,
`generated cron, ${cronElement} should match regex ${regexElements[i]}`
).toMatch(new RegExp(regexElements[i]))
);
}
);

it('should return non-standard cron expressions', () => {
const validResults = ['1', '2', '5', '*', '@'];
expect(
faker.system.cron({ includeNonStandard: true })[0],
'generated cron, string should contain non-standard cron labels'
).toSatisfy(
(value) => !!validResults.find((result) => value === result)
);
});
});
}
});

Expand Down