Skip to content

Commit

Permalink
feat(system): add cron (#897)
Browse files Browse the repository at this point in the history
  • Loading branch information
nhammond101 committed Aug 29, 2022
1 parent 7f8b871 commit 8fecd58
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 0 deletions.
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);
}
}
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`] = `"lavender_shoes.ex

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`] = `"invoice_cyclocr

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`] = `"nesciunt.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`] = `"lavender_shoes.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`] = `"invoice_cyclocross_assau

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`] = `"nesciunt.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

0 comments on commit 8fecd58

Please sign in to comment.