diff options
| author | ST-DDT <[email protected]> | 2023-01-11 19:56:25 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-01-11 18:56:25 +0000 |
| commit | 47b2cfc76b790647e398bf9883368a10b2ff5a68 (patch) | |
| tree | a7bf7f0146915258c2a18c1a825e513cb0c60291 | |
| parent | f4615e1e05a378dd5ae304543185dc7afd0fb7d8 (diff) | |
| download | faker-47b2cfc76b790647e398bf9883368a10b2ff5a68.tar.xz faker-47b2cfc76b790647e398bf9883368a10b2ff5a68.zip | |
feat(string): generate string from characters (#1717)
| -rw-r--r-- | src/modules/string/index.ts | 135 | ||||
| -rw-r--r-- | test/__snapshots__/string.spec.ts.snap | 36 | ||||
| -rw-r--r-- | test/all_functional.spec.ts | 3 | ||||
| -rw-r--r-- | test/random.spec.ts | 4 | ||||
| -rw-r--r-- | test/string.spec.ts | 108 |
5 files changed, 206 insertions, 80 deletions
diff --git a/src/modules/string/index.ts b/src/modules/string/index.ts index d48f4542..99eb8983 100644 --- a/src/modules/string/index.ts +++ b/src/modules/string/index.ts @@ -97,6 +97,49 @@ export class StringModule { } /** + * Generates a string from the given characters. + * + * @param characters The characters to use for the string. Can be a string or an array of characters. + * If it is an array, then each element is treated as a single character even if it is a string with multiple characters. + * @param length The length of the string to generate. Defaults to `1`. + * @param length.min The minimum length of the string to generate. + * @param length.max The maximum length of the string to generate. + * + * @example + * faker.string.fromCharacters('abc') // 'c' + * faker.string.fromCharacters(['a', 'b', 'c']) // 'a' + * faker.string.fromCharacters('abc', 10) // 'cbbbacbacb' + * faker.string.fromCharacters('abc', { min: 5, max: 10 }) // 'abcaaaba' + * + * @since 8.0.0 + */ + fromCharacters( + characters: string | ReadonlyArray<string>, + length: number | { min: number; max: number } = 1 + ): string { + length = this.faker.helpers.rangeToNumber(length); + if (length <= 0) { + return ''; + } + + if (typeof characters === 'string') { + characters = characters.split(''); + } + + if (characters.length === 0) { + throw new FakerError( + 'Unable to generate string: No characters to select from.' + ); + } + + return this.faker.helpers + .multiple(() => this.faker.helpers.arrayElement(characters as string[]), { + count: length, + }) + .join(''); + } + + /** * Generating a string consisting of letters in the English alphabet. * * @param options Either the number of characters or an options instance. @@ -157,15 +200,7 @@ export class StringModule { charsArray = charsArray.filter((elem) => !exclude.includes(elem)); - if (charsArray.length === 0) { - throw new FakerError( - 'Unable to generate string, because all possible characters are excluded.' - ); - } - - return Array.from({ length }, () => - this.faker.helpers.arrayElement(charsArray) - ).join(''); + return this.fromCharacters(charsArray, length); } /** @@ -230,15 +265,7 @@ export class StringModule { charsArray = charsArray.filter((elem) => !exclude.includes(elem)); - if (charsArray.length === 0) { - throw new FakerError( - 'Unable to generate string, because all possible characters are excluded.' - ); - } - - return Array.from({ length }, () => - this.faker.helpers.arrayElement(charsArray) - ).join(''); + return this.fromCharacters(charsArray, length); } /** @@ -266,18 +293,10 @@ export class StringModule { } = {} ): string { const { prefix = '0b' } = options; - const length = this.faker.helpers.rangeToNumber(options.length ?? 1); - if (length <= 0) { - return prefix; - } - - let binaryString = ''; - for (let i = 0; i < length; i++) { - binaryString += this.faker.helpers.arrayElement(['0', '1']); - } - - return `${prefix}${binaryString}`; + let result = prefix; + result += this.fromCharacters(['0', '1'], options.length ?? 1); + return result; } /** @@ -305,27 +324,13 @@ export class StringModule { } = {} ): string { const { prefix = '0o' } = options; - const length = this.faker.helpers.rangeToNumber(options.length ?? 1); - if (length <= 0) { - return prefix; - } - let octalString = ''; - - for (let i = 0; i < length; i++) { - octalString += this.faker.helpers.arrayElement([ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - ]); - } - - return `${prefix}${octalString}`; + let result = prefix; + result += this.fromCharacters( + ['0', '1', '2', '3', '4', '5', '6', '7'], + options.length ?? 1 + ); + return result; } /** @@ -362,10 +367,8 @@ export class StringModule { return prefix; } - let wholeString = ''; - - for (let i = 0; i < length; i++) { - wholeString += this.faker.helpers.arrayElement([ + let wholeString = this.fromCharacters( + [ '0', '1', '2', @@ -388,8 +391,9 @@ export class StringModule { 'D', 'E', 'F', - ]); - } + ], + length + ); if (casing === 'upper') { wholeString = wholeString.toUpperCase(); @@ -470,9 +474,7 @@ export class StringModule { ); } - while (result.length < length) { - result += this.faker.helpers.arrayElement(allowedDigits); - } + result += this.fromCharacters(allowedDigits, length - result.length); return result; } @@ -589,14 +591,8 @@ export class StringModule { * @since 8.0.0 */ special(length: number | { min: number; max: number } = 1): string { - length = this.faker.helpers.rangeToNumber(length); - if (length <= 0) { - return ''; - } - - let specialString = ''; - for (let i = 0; i < length; i++) { - specialString += this.faker.helpers.arrayElement([ + return this.fromCharacters( + [ '!', '"', '#', @@ -629,9 +625,8 @@ export class StringModule { '|', '}', '~', - ]); - } - - return specialString; + ], + length + ); } } diff --git a/test/__snapshots__/string.spec.ts.snap b/test/__snapshots__/string.spec.ts.snap index 6a3ccead..61245b7b 100644 --- a/test/__snapshots__/string.spec.ts.snap +++ b/test/__snapshots__/string.spec.ts.snap @@ -62,6 +62,18 @@ exports[`string > 42 > binary > with length and empty prefix 1`] = `"0110111"`; exports[`string > 42 > binary > with length range 1`] = `"0b11011110000001"`; +exports[`string > 42 > fromCharacters > with string characters 1`] = `"o"`; + +exports[`string > 42 > fromCharacters > with string characters and length 1`] = `"oaroa"`; + +exports[`string > 42 > fromCharacters > with string characters and length range 1`] = `"aroaabbfofffor"`; + +exports[`string > 42 > fromCharacters > with string[] characters 1`] = `"o"`; + +exports[`string > 42 > fromCharacters > with string[] characters and length 1`] = `"oaroa"`; + +exports[`string > 42 > fromCharacters > with string[] characters and length range 1`] = `"aroaabbfofffor"`; + exports[`string > 42 > hexadecimal > noArgs 1`] = `"0x8"`; exports[`string > 42 > hexadecimal > with casing = lower 1`] = `"0x8"`; @@ -224,6 +236,18 @@ exports[`string > 1211 > binary > with length and empty prefix 1`] = `"1011001"` exports[`string > 1211 > binary > with length range 1`] = `"0b01100101010100011101"`; +exports[`string > 1211 > fromCharacters > with string characters 1`] = `"r"`; + +exports[`string > 1211 > fromCharacters > with string characters and length 1`] = `"rorao"`; + +exports[`string > 1211 > fromCharacters > with string characters and length range 1`] = `"oraofrfafaoaoofaaafa"`; + +exports[`string > 1211 > fromCharacters > with string[] characters 1`] = `"r"`; + +exports[`string > 1211 > fromCharacters > with string[] characters and length 1`] = `"rorao"`; + +exports[`string > 1211 > fromCharacters > with string[] characters and length range 1`] = `"oraofrfafaoaoofaaafa"`; + exports[`string > 1211 > hexadecimal > noArgs 1`] = `"0xE"`; exports[`string > 1211 > hexadecimal > with casing = lower 1`] = `"0xe"`; @@ -386,6 +410,18 @@ exports[`string > 1337 > binary > with length and empty prefix 1`] = `"0100010"` exports[`string > 1337 > binary > with length range 1`] = `"0b100010000110"`; +exports[`string > 1337 > fromCharacters > with string characters 1`] = `"o"`; + +exports[`string > 1337 > fromCharacters > with string characters and length 1`] = `"obfoo"`; + +exports[`string > 1337 > fromCharacters > with string characters and length range 1`] = `"bfoobofoobbo"`; + +exports[`string > 1337 > fromCharacters > with string[] characters 1`] = `"o"`; + +exports[`string > 1337 > fromCharacters > with string[] characters and length 1`] = `"obfoo"`; + +exports[`string > 1337 > fromCharacters > with string[] characters and length range 1`] = `"bfoobofoobbo"`; + exports[`string > 1337 > hexadecimal > noArgs 1`] = `"0x5"`; exports[`string > 1337 > hexadecimal > with casing = lower 1`] = `"0x5"`; diff --git a/test/all_functional.spec.ts b/test/all_functional.spec.ts index cc784660..ae4ac991 100644 --- a/test/all_functional.spec.ts +++ b/test/all_functional.spec.ts @@ -29,6 +29,9 @@ const BROKEN_LOCALE_METHODS = { state: ['az', 'cz', 'nb_NO', 'sk'], stateAbbr: ['cz', 'sk'], }, + string: { + fromCharacters: '*', + }, person: { prefix: ['az', 'id_ID', 'ru', 'zh_CN', 'zh_TW'], suffix: ['az', 'it', 'mk', 'pt_PT', 'ru'], diff --git a/test/random.spec.ts b/test/random.spec.ts index 510009db..e03e7428 100644 --- a/test/random.spec.ts +++ b/test/random.spec.ts @@ -213,7 +213,7 @@ describe('random', () => { }) ).toThrowError( new FakerError( - 'Unable to generate string, because all possible characters are excluded.' + 'Unable to generate string: No characters to select from.' ) ); }); @@ -332,7 +332,7 @@ describe('random', () => { }) ).toThrowError( new FakerError( - 'Unable to generate string, because all possible characters are excluded.' + 'Unable to generate string: No characters to select from.' ) ); }); diff --git a/test/string.spec.ts b/test/string.spec.ts index 1ad429ca..5c256a32 100644 --- a/test/string.spec.ts +++ b/test/string.spec.ts @@ -7,6 +7,21 @@ const NON_SEEDED_BASED_RUN = 5; describe('string', () => { seededTests(faker, 'string', (t) => { + t.describe('fromCharacters', (t) => { + t.it('with string characters', 'foobar') + .it('with string[] characters', 'foobar'.split('')) + .it('with string characters and length', 'foobar', 5) + .it('with string[] characters and length', 'foobar'.split(''), 5) + .it('with string characters and length range', 'foobar', { + min: 10, + max: 20, + }) + .it('with string[] characters and length range', 'foobar'.split(''), { + min: 10, + max: 20, + }); + }); + t.describe('alpha', (t) => { t.it('noArgs') .itRepeated('with length parameter', 5, 5) @@ -113,6 +128,64 @@ describe('string', () => { describe(`random seeded tests for seed ${faker.seed()}`, () => { for (let i = 1; i <= NON_SEEDED_BASED_RUN; i++) { + describe('fromCharacters', () => { + it('should return single character when no length provided', () => { + const actual = faker.string.fromCharacters('foobar'); + + expect(actual).toHaveLength(1); + }); + + it('should only contain characters from provided string', () => { + const actual = faker.string.fromCharacters('foobar'); + + expect(actual).toMatch(/^[foobar]$/); + }); + + it('should generate 5 random letters', () => { + const actual = faker.string.fromCharacters('foobar', 5); + + expect(actual).toHaveLength(5); + }); + + it.each([0, -1, -100])( + 'should return empty string when length is <= 0', + (length) => { + const actual = faker.string.fromCharacters('foobar', length); + + expect(actual).toBe(''); + } + ); + + it('should return a random amount of characters', () => { + const actual = faker.string.fromCharacters('foobar', { + min: 10, + max: 20, + }); + + expect(actual).toBeTruthy(); + expect(actual).toBeTypeOf('string'); + + expect(actual.length).toBeGreaterThanOrEqual(10); + expect(actual.length).toBeLessThanOrEqual(20); + }); + + it('should throw if no characters are passed (string)', () => { + expect(() => faker.string.fromCharacters('')).toThrowError( + new FakerError( + 'Unable to generate string: No characters to select from.' + ) + ); + }); + + it('should throw if no characters are passed (string[])', () => { + expect(() => faker.string.fromCharacters([])).toThrowError( + new FakerError( + 'Unable to generate string: No characters to select from.' + ) + ); + }); + }); + describe('alpha', () => { it('should return single letter when no length provided', () => { const actual = faker.string.alpha(); @@ -193,7 +266,22 @@ describe('string', () => { expect(alphaText).toMatch(/^[b-oq-z]{5}$/); }); - it('should throw if all possible characters being excluded', () => { + it('should throw if all possible characters being excluded (string)', () => { + const exclude = 'abcdefghijklmnopqrstuvwxyz'; + expect(() => + faker.string.alpha({ + length: 5, + casing: 'lower', + exclude, + }) + ).toThrowError( + new FakerError( + 'Unable to generate string: No characters to select from.' + ) + ); + }); + + it('should throw if all possible characters being excluded (string[])', () => { const exclude = 'abcdefghijklmnopqrstuvwxyz'.split(''); expect(() => faker.string.alpha({ @@ -203,7 +291,7 @@ describe('string', () => { }) ).toThrowError( new FakerError( - 'Unable to generate string, because all possible characters are excluded.' + 'Unable to generate string: No characters to select from.' ) ); }); @@ -332,8 +420,8 @@ describe('string', () => { expect(alphaText).toMatch(/^[0-9b-oq-z]{5}$/); }); - it('should throw if all possible characters being excluded', () => { - const exclude = 'abcdefghijklmnopqrstuvwxyz0123456789'.split(''); + it('should throw if all possible characters being excluded (string)', () => { + const exclude = 'abcdefghijklmnopqrstuvwxyz0123456789'; expect(() => faker.string.alphanumeric({ length: 5, @@ -342,20 +430,24 @@ describe('string', () => { }) ).toThrowError( new FakerError( - 'Unable to generate string, because all possible characters are excluded.' + 'Unable to generate string: No characters to select from.' ) ); }); - it('should throw if all possible characters being excluded via string', () => { - const exclude = 'abcdefghijklmnopqrstuvwxyz0123456789'; + it('should throw if all possible characters being excluded (string[])', () => { + const exclude = 'abcdefghijklmnopqrstuvwxyz0123456789'.split(''); expect(() => faker.string.alphanumeric({ length: 5, casing: 'lower', exclude, }) - ).toThrowError(); + ).toThrowError( + new FakerError( + 'Unable to generate string: No characters to select from.' + ) + ); }); it('should not mutate the input object', () => { |
