diff options
| -rw-r--r-- | src/modules/random/index.ts | 181 | ||||
| -rw-r--r-- | src/modules/vehicle/index.ts | 10 | ||||
| -rw-r--r-- | test/random.spec.ts | 61 |
3 files changed, 153 insertions, 99 deletions
diff --git a/src/modules/random/index.ts b/src/modules/random/index.ts index e3e36ec4..a95b44ab 100644 --- a/src/modules/random/index.ts +++ b/src/modules/random/index.ts @@ -1,5 +1,12 @@ import type { Faker } from '../..'; import { FakerError } from '../../errors/faker-error'; +import { deprecated } from '../../internal/deprecated'; + +export type Casing = 'upper' | 'lower' | 'mixed'; + +const UPPER_CHARS: readonly string[] = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); +const LOWER_CHARS: readonly string[] = 'abcdefghijklmnopqrstuvwxyz'.split(''); +const DIGIT_CHARS: readonly string[] = '0123456789'.split(''); /** * Method to reduce array of characters. @@ -141,17 +148,18 @@ export class Random { } /** - * Generating a string consisting of lower/upper alpha characters based on count and upcase options. + * Generating a string consisting of letters in the English alphabet. * - * @param options Either the number of characters or an options instance. Defaults to `{ count: 1, upcase: false, bannedChars: [] }`. + * @param options Either the number of characters or an options instance. Defaults to `{ count: 1, casing: 'lower', bannedChars: [] }`. * @param options.count The number of characters to generate. Defaults to `1`. - * @param options.upcase If true, the result will be uppercase. If false, it will be lowercase. Defaults to `false`. + * @param options.casing The casing of the characters. Defaults to `'lower'`. + * @param options.upcase Deprecated, use `casing: 'upper'` instead. * @param options.bannedChars An array with characters to exclude. Defaults to `[]`. * * @example * faker.random.alpha() // 'b' * faker.random.alpha(10) // 'qccrabobaf' - * faker.random.alpha({ count: 5, upcase: true, bannedChars: ['a'] }) // 'DTCIC' + * faker.random.alpha({ count: 5, casing: 'upper', bannedChars: ['A'] }) // 'DTCIC' */ // TODO @Shinigami92 2022-02-14: Tests covered `(count, options)`, but they were never typed like that alpha( @@ -159,7 +167,11 @@ export class Random { | number | { count?: number; + /** + * @deprecated Use `casing` instead. + */ upcase?: boolean; + casing?: Casing; bannedChars?: readonly string[]; } = {} ): string { @@ -168,52 +180,59 @@ export class Random { count: options, }; } - const { count = 1, upcase = false, bannedChars = [] } = options; - - let charsArray = [ - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'i', - 'j', - 'k', - 'l', - 'm', - 'n', - 'o', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z', - ]; + const { count = 1, upcase, bannedChars = [] } = options; + + if (count <= 0) { + return ''; + } + + const { + // Switch to 'mixed' with v8.0 + casing = upcase ? 'upper' : 'lower', + } = options; + + if (upcase != null) { + deprecated({ + deprecated: 'faker.random.alpha({ upcase: true })', + proposed: "faker.random.alpha({ casing: 'upper' })", + since: 'v7.0', + until: 'v8.0', + }); + } + + let charsArray: string[]; + switch (casing) { + case 'upper': + charsArray = [...UPPER_CHARS]; + break; + case 'lower': + charsArray = [...LOWER_CHARS]; + break; + case 'mixed': + default: + charsArray = [...LOWER_CHARS, ...UPPER_CHARS]; + break; + } charsArray = arrayRemove(charsArray, bannedChars); - let wholeString = ''; - for (let i = 0; i < count; i++) { - wholeString += this.faker.helpers.arrayElement(charsArray); + if (charsArray.length === 0) { + throw new FakerError( + 'Unable to generate string, because all possible characters are banned.' + ); } - return upcase ? wholeString.toUpperCase() : wholeString; + return Array.from({ length: count }, () => + this.faker.helpers.arrayElement(charsArray) + ).join(''); } /** - * Generating a string consisting of lower/upper alpha characters and digits based on count and upcase options. + * Generating a string consisting of alpha characters and digits. * * @param count The number of characters and digits to generate. Defaults to `1`. * @param options The options to use. Defaults to `{ bannedChars: [] }`. + * @param options.casing The casing of the characters. Defaults to `'lower'`. * @param options.bannedChars An array of characters and digits which should be banned in the generated string. Defaults to `[]`. * * @example @@ -223,48 +242,35 @@ export class Random { */ alphaNumeric( count: number = 1, - options: { bannedChars?: readonly string[] } = {} + options: { + casing?: Casing; + bannedChars?: readonly string[]; + } = {} ): string { - const { bannedChars = [] } = options; - - let charsArray = [ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'i', - 'j', - 'k', - 'l', - 'm', - 'n', - 'o', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z', - ]; + if (count <= 0) { + return ''; + } + + const { + // Switch to 'mixed' with v8.0 + casing = 'lower', + bannedChars = [], + } = options; + + let charsArray = [...DIGIT_CHARS]; + + switch (casing) { + case 'upper': + charsArray.push(...UPPER_CHARS); + break; + case 'lower': + charsArray.push(...LOWER_CHARS); + break; + case 'mixed': + default: + charsArray.push(...LOWER_CHARS, ...UPPER_CHARS); + break; + } charsArray = arrayRemove(charsArray, bannedChars); @@ -274,12 +280,9 @@ export class Random { ); } - let wholeString = ''; - for (let i = 0; i < count; i++) { - wholeString += this.faker.helpers.arrayElement(charsArray); - } - - return wholeString; + return Array.from({ length: count }, () => + this.faker.helpers.arrayElement(charsArray) + ).join(''); } /** @@ -310,9 +313,9 @@ export class Random { const { allowLeadingZeros = false, bannedDigits = [] } = options; - const allowedDigits = '0123456789' - .split('') - .filter((digit) => !bannedDigits.includes(digit)); + const allowedDigits = DIGIT_CHARS.filter( + (digit) => !bannedDigits.includes(digit) + ); if ( allowedDigits.length === 0 || diff --git a/src/modules/vehicle/index.ts b/src/modules/vehicle/index.ts index ec010af9..fb5cd9f9 100644 --- a/src/modules/vehicle/index.ts +++ b/src/modules/vehicle/index.ts @@ -75,14 +75,16 @@ export class Vehicle { * faker.vehicle.vin() // 'YV1MH682762184654' */ vin(): string { - const bannedChars = ['o', 'i', 'q']; + const bannedChars = ['o', 'i', 'q', 'O', 'I', 'Q']; return `${this.faker.random.alphaNumeric(10, { + casing: 'upper', bannedChars, })}${this.faker.random.alpha({ count: 1, - upcase: true, + casing: 'upper', bannedChars, })}${this.faker.random.alphaNumeric(1, { + casing: 'upper', bannedChars, })}${this.faker.datatype.number({ min: 10000, max: 99999 })}` // return five digit # .toUpperCase(); @@ -107,14 +109,14 @@ export class Vehicle { vrm(): string { return `${this.faker.random.alpha({ count: 2, - upcase: true, + casing: 'upper', })}${this.faker.datatype.number({ min: 0, max: 9, })}${this.faker.datatype.number({ min: 0, max: 9, - })}${this.faker.random.alpha({ count: 3, upcase: true })}`.toUpperCase(); + })}${this.faker.random.alpha({ count: 3, casing: 'upper' })}`.toUpperCase(); } /** diff --git a/test/random.spec.ts b/test/random.spec.ts index d6fe3da7..3ff24ff7 100644 --- a/test/random.spec.ts +++ b/test/random.spec.ts @@ -179,9 +179,13 @@ describe('random', () => { expect(actual).toMatch(/^[a-z]$/); }); - it('should return uppercase when upcase option is true', () => { - const actual = faker.random.alpha({ upcase: true }); - expect(actual).toMatch(/^[A-Z]$/); + it.each([ + ['upper', /^[A-Z]{250}$/], + ['lower', /^[a-z]{250}$/], + ['mixed', /^[a-zA-Z]{250}$/], + ] as const)('should return %s-case', (casing, pattern) => { + const actual = faker.random.alpha({ count: 250, casing }); + expect(actual).toMatch(pattern); }); it('should generate many random letters', () => { @@ -190,6 +194,15 @@ describe('random', () => { expect(actual).toHaveLength(5); }); + it.each([0, -1, -100])( + 'should return empty string when length is <= 0', + (length) => { + const actual = faker.random.alpha(length); + + expect(actual).toBe(''); + } + ); + it('should be able to ban some characters', () => { const actual = faker.random.alpha({ count: 5, @@ -210,14 +223,28 @@ describe('random', () => { expect(alphaText).toMatch(/^[b-oq-z]{5}$/); }); + it('should throw if all possible characters being banned', () => { + const bannedChars = 'abcdefghijklmnopqrstuvwxyz'.split(''); + expect(() => + faker.random.alpha({ + count: 5, + bannedChars, + }) + ).toThrowError( + new FakerError( + 'Unable to generate string, because all possible characters are banned.' + ) + ); + }); + it('should not mutate the input object', () => { const input: { count: number; - upcase: boolean; + casing: 'mixed'; bannedChars: string[]; } = Object.freeze({ count: 5, - upcase: true, + casing: 'mixed', bannedChars: ['a', '%'], }); @@ -233,12 +260,30 @@ describe('random', () => { expect(actual).toHaveLength(1); }); + it.each([ + ['upper', /^[A-Z0-9]{250}$/], + ['lower', /^[a-z0-9]{250}$/], + ['mixed', /^[a-zA-Z0-9]{250}$/], + ] as const)('should return %s-case', (casing, pattern) => { + const actual = faker.random.alphaNumeric(250, { casing }); + expect(actual).toMatch(pattern); + }); + it('should generate many random characters', () => { const actual = faker.random.alphaNumeric(5); expect(actual).toHaveLength(5); }); + it.each([0, -1, -100])( + 'should return empty string when length is <= 0', + (length) => { + const actual = faker.random.alphaNumeric(length); + + expect(actual).toBe(''); + } + ); + it('should be able to ban all alphabetic characters', () => { const bannedChars = 'abcdefghijklmnopqrstuvwxyz'.split(''); const alphaText = faker.random.alphaNumeric(5, { @@ -278,7 +323,11 @@ describe('random', () => { faker.random.alphaNumeric(5, { bannedChars, }) - ).toThrowError(); + ).toThrowError( + new FakerError( + 'Unable to generate string, because all possible characters are banned.' + ) + ); }); it('should not mutate the input object', () => { |
