Skip to content

Commit

Permalink
feat: random numeric (#797)
Browse files Browse the repository at this point in the history
Co-authored-by: ST-DDT <ST-DDT@gmx.de>
  • Loading branch information
Shinigami92 and ST-DDT authored Apr 24, 2022
1 parent f797b63 commit 712b1de
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 1 deletion.
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]+$/);
});

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

0 comments on commit 712b1de

Please sign in to comment.