aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2023-01-11 19:56:25 +0100
committerGitHub <[email protected]>2023-01-11 18:56:25 +0000
commit47b2cfc76b790647e398bf9883368a10b2ff5a68 (patch)
treea7bf7f0146915258c2a18c1a825e513cb0c60291
parentf4615e1e05a378dd5ae304543185dc7afd0fb7d8 (diff)
downloadfaker-47b2cfc76b790647e398bf9883368a10b2ff5a68.tar.xz
faker-47b2cfc76b790647e398bf9883368a10b2ff5a68.zip
feat(string): generate string from characters (#1717)
-rw-r--r--src/modules/string/index.ts135
-rw-r--r--test/__snapshots__/string.spec.ts.snap36
-rw-r--r--test/all_functional.spec.ts3
-rw-r--r--test/random.spec.ts4
-rw-r--r--test/string.spec.ts108
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', () => {