Skip to content

Commit c1711e5

Browse files
Shinigami92ST-DDT
andcommitted
feat: random numeric
Co-authored-by: ST-DDT <ST-DDT@gmx.de>
1 parent 1885dd0 commit c1711e5

2 files changed

Lines changed: 135 additions & 1 deletion

File tree

src/random.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,64 @@ export class Random {
527527
return wholeString;
528528
}
529529

530+
/**
531+
* Generates a given length string of digits.
532+
*
533+
* @param length The number of digits to generate. Defaults to `1`.
534+
* @param options The options to use. Defaults to `{}`.
535+
* @param options.allowLeadingZeros If true, leading zeros will be allowed. Defaults to `false`.
536+
* @param options.bannedDigits An array of digits which should be banned in the generated string. Defaults to `[]`.
537+
*
538+
* @example
539+
* faker.random.numeric() // '2'
540+
* faker.random.numeric(5) // '31507'
541+
* faker.random.numeric(42) // '56434563150765416546479875435481513188548'
542+
* faker.random.numeric(42, { allowLeadingZeros: true }) // '00564846278453876543517840713421451546115'
543+
* faker.random.numeric(6, { bannedDigits: ['0'] }) // '943228'
544+
*/
545+
numeric(
546+
length: number = 1,
547+
options: {
548+
allowLeadingZeros?: boolean;
549+
bannedDigits?: readonly string[];
550+
} = {}
551+
): string {
552+
if (length <= 0) {
553+
return '';
554+
}
555+
556+
const { allowLeadingZeros = false, bannedDigits = [] } = options;
557+
558+
const allowedDigits = '0123456789'
559+
.split('')
560+
.filter((digit) => !bannedDigits.includes(digit));
561+
562+
if (
563+
allowedDigits.length === 0 ||
564+
(allowedDigits.length === 1 &&
565+
!allowLeadingZeros &&
566+
allowedDigits[0] === '0')
567+
) {
568+
throw new FakerError(
569+
'Unable to generate numeric string, because all possible digits are banned.'
570+
);
571+
}
572+
573+
let result = '';
574+
575+
if (!allowLeadingZeros && !bannedDigits.includes('0')) {
576+
result += this.arrayElement(
577+
allowedDigits.filter((digit) => digit !== '0')
578+
);
579+
}
580+
581+
while (result.length < length) {
582+
result += this.arrayElement(allowedDigits);
583+
}
584+
585+
return result;
586+
}
587+
530588
/**
531589
* Returns a hexadecimal number.
532590
*

test/random.spec.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
2-
import { faker } from '../src';
2+
import { faker, FakerError } from '../src';
33
import { times } from './support/times';
44

55
describe('random', () => {
@@ -304,6 +304,82 @@ describe('random', () => {
304304
});
305305
});
306306

307+
describe('numeric', () => {
308+
it('should return single digit when no length provided', () => {
309+
const actual = faker.random.numeric();
310+
311+
expect(actual).toHaveLength(1);
312+
expect(actual).toMatch(/^[1-9]$/);
313+
});
314+
315+
it.each(times(100))(
316+
'should generate random value with a length of %s',
317+
(length) => {
318+
const actual = faker.random.numeric(length);
319+
320+
expect(actual).toHaveLength(length);
321+
expect(actual).toMatch(/^[1-9]/);
322+
expect(actual).toMatch(/[0-9]+$/);
323+
}
324+
);
325+
326+
it('should return empty string with a length of 0', () => {
327+
const actual = faker.random.numeric(0);
328+
329+
expect(actual).toHaveLength(0);
330+
});
331+
332+
it('should return empty string with a negative length', () => {
333+
const actual = faker.random.numeric(-10);
334+
335+
expect(actual).toHaveLength(0);
336+
});
337+
338+
it('should return a valid numeric string with provided length', () => {
339+
const actual = faker.random.numeric(1000);
340+
341+
expect(actual).toBeTypeOf('string');
342+
expect(actual).toMatch(/^[1-9][0-9]+$/);
343+
});
344+
345+
it('should allow leading zeros via option', () => {
346+
const actual = faker.random.numeric(15, { allowLeadingZeros: true });
347+
348+
expect(actual).toMatch(/^[0-9]+$/);
349+
});
350+
351+
it('should allow leading zeros via option and all other digits banned', () => {
352+
const actual = faker.random.numeric(4, {
353+
allowLeadingZeros: true,
354+
bannedDigits: '123456789'.split(''),
355+
});
356+
357+
expect(actual).toBe('0000');
358+
});
359+
360+
it('should fail on leading zeros via option and all other digits banned', () => {
361+
expect(() =>
362+
faker.random.numeric(4, {
363+
allowLeadingZeros: false,
364+
bannedDigits: '123456789'.split(''),
365+
})
366+
).toThrowError(
367+
new FakerError(
368+
'Unable to generate numeric string, because all possible digits are banned.'
369+
)
370+
);
371+
});
372+
373+
it('should ban all digits passed via bannedDigits', () => {
374+
const actual = faker.random.numeric(1000, {
375+
bannedDigits: 'c84U1'.split(''),
376+
});
377+
378+
expect(actual).toHaveLength(1000);
379+
expect(actual).toMatch(/^[0235679]{1000}$/);
380+
});
381+
});
382+
307383
describe('deprecation warnings', () => {
308384
it.each([
309385
['number', 'datatype.number'],

0 commit comments

Comments
 (0)