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: random numeric #797

Merged
merged 2 commits into from
Apr 24, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,64 @@ export class Random {
return wholeString;
}

/**
* Generates a given length string of digits.
*
* @param length The number of digits to generate. Defaults to `1`.
* @param options The options to use. Defaults to `{}`.
* @param options.allowLeadingZeros If true, leading zeros will be allowed. Defaults to `false`.
* @param options.bannedDigits An array of digits which should be banned in the generated string. Defaults to `[]`.
*
* @example
* faker.random.numeric() // '2'
* faker.random.numeric(5) // '31507'
* faker.random.numeric(42) // '56434563150765416546479875435481513188548'
* faker.random.numeric(42, { allowLeadingZeros: true }) // '00564846278453876543517840713421451546115'
* faker.random.numeric(6, { bannedDigits: ['0'] }) // '943228'
*/
numeric(
length: number = 1,
options: {
allowLeadingZeros?: boolean;
bannedDigits?: readonly string[];
} = {}
): string {
if (length <= 0) {
return '';
}

const { allowLeadingZeros = false, bannedDigits = [] } = options;

const allowedDigits = '0123456789'
.split('')
.filter((digit) => !bannedDigits.includes(digit));

if (
allowedDigits.length === 0 ||
(allowedDigits.length === 1 &&
!allowLeadingZeros &&
allowedDigits[0] === '0')
) {
throw new FakerError(
'Unable to generate numeric string, because all possible digits are banned.'
);
}

let result = '';

if (!allowLeadingZeros && !bannedDigits.includes('0')) {
result += this.arrayElement(
allowedDigits.filter((digit) => digit !== '0')
);
}

while (result.length < length) {
result += this.arrayElement(allowedDigits);
}

return result;
}

/**
* Returns a hexadecimal number.
*
Expand Down
78 changes: 77 additions & 1 deletion test/random.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { faker } from '../src';
import { faker, FakerError } from '../src';
import { times } from './support/times';

describe('random', () => {
Expand Down Expand Up @@ -304,6 +304,82 @@ describe('random', () => {
});
});

describe('numeric', () => {
it('should return single digit when no length provided', () => {
const actual = faker.random.numeric();

expect(actual).toHaveLength(1);
expect(actual).toMatch(/^[1-9]$/);
});

it.each(times(100))(
'should generate random value with a length of %s',
(length) => {
const actual = faker.random.numeric(length);

expect(actual).toHaveLength(length);
expect(actual).toMatch(/^[1-9][0-9]*$/);
}
);

it('should return empty string with a length of 0', () => {
const actual = faker.random.numeric(0);

expect(actual).toHaveLength(0);
});

it('should return empty string with a negative length', () => {
const actual = faker.random.numeric(-10);

expect(actual).toHaveLength(0);
});

it('should return a valid numeric string with provided length', () => {
const actual = faker.random.numeric(1000);

expect(actual).toBeTypeOf('string');
expect(actual).toHaveLength(1000);
expect(actual).toMatch(/^[1-9][0-9]+$/);
});
Shinigami92 marked this conversation as resolved.
Show resolved Hide resolved

it('should allow leading zeros via option', () => {
const actual = faker.random.numeric(15, { allowLeadingZeros: true });

expect(actual).toMatch(/^[0-9]+$/);
});

it('should allow leading zeros via option and all other digits banned', () => {
const actual = faker.random.numeric(4, {
allowLeadingZeros: true,
bannedDigits: '123456789'.split(''),
});

expect(actual).toBe('0000');
});

it('should fail on leading zeros via option and all other digits banned', () => {
expect(() =>
faker.random.numeric(4, {
allowLeadingZeros: false,
bannedDigits: '123456789'.split(''),
})
).toThrowError(
new FakerError(
'Unable to generate numeric string, because all possible digits are banned.'
)
);
});

it('should ban all digits passed via bannedDigits', () => {
const actual = faker.random.numeric(1000, {
bannedDigits: 'c84U1'.split(''),
});

expect(actual).toHaveLength(1000);
expect(actual).toMatch(/^[0235679]{1000}$/);
});
});

describe('deprecation warnings', () => {
it.each([
['number', 'datatype.number'],
Expand Down