From 46bf5688a56c74b851e912b81ecd582ca9a66dfd Mon Sep 17 00:00:00 2001 From: Shinigami92 Date: Thu, 7 Apr 2022 13:26:22 +0200 Subject: [PATCH] feat: reimplement datatype.bigInt Co-authored-by: ST-DDT --- src/modules/datatype/index.ts | 59 +++++++++++++++++---- test/datatype.spec.ts | 97 ++++++++++++++++++++++++++++++++--- 2 files changed, 139 insertions(+), 17 deletions(-) diff --git a/src/modules/datatype/index.ts b/src/modules/datatype/index.ts index df2cac876fc..c8b9718f924 100644 --- a/src/modules/datatype/index.ts +++ b/src/modules/datatype/index.ts @@ -261,20 +261,59 @@ export class Datatype { /** * Returns a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type) number. * - * @param value When provided, this method simply converts it to `BigInt` type. + * @param options Maximum value or options object. + * @param options.min Lower bound for generated bigint. Defaults to `0n`. + * @param options.max Upper bound for generated bigint. Defaults to `min + 999999999999999n`. + * + * @throws When options define `max < min`. * * @example - * faker.datatype.bigInt() // 8507209999914928n - * faker.datatype.bigInt('156') // 156n - * faker.datatype.bigInt(30) // 30n - * faker.datatype.bigInt(3000n) // 3000n - * faker.datatype.bigInt(true) // 1n + * faker.datatype.bigInt() // 55422n + * faker.datatype.bigInt(100n) // 52n + * faker.datatype.bigInt({ min: 1000000n }) // 431433n + * faker.datatype.bigInt({ max: 100n }) // 42n + * faker.datatype.bigInt({ min: 10n, max: 100n }) // 36n */ - bigInt(value?: string | number | bigint | boolean): bigint { - if (value === undefined) { - value = Math.floor(this.number() * 99999999999) + 10000000000; + bigInt( + options?: + | bigint + | boolean + | number + | string + | { + min?: bigint | boolean | number | string; + max?: bigint | boolean | number | string; + } + ): bigint { + let min: bigint; + let max: bigint; + + if (typeof options === 'object') { + min = BigInt(options.min ?? 0); + max = BigInt(options.max ?? min + BigInt(999999999999999)); + } else { + min = BigInt(0); + max = BigInt(options ?? 999999999999999); } - return BigInt(value); + if (max === min) { + return min; + } + + if (max < min) { + throw new FakerError(`Max ${max} should be larger then min ${min}.`); + } + + const delta = max - min; + + const offset = + BigInt( + this.faker.random.numeric(delta.toString(10).length, { + allowLeadingZeros: true, + }) + ) % + (delta + BigInt(1)); + + return min + offset; } } diff --git a/test/datatype.spec.ts b/test/datatype.spec.ts index bd00c8ddf88..9b6a74b3711 100644 --- a/test/datatype.spec.ts +++ b/test/datatype.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { faker } from '../src'; +import { faker, FakerError } from '../src'; const seededRuns = [ { @@ -69,8 +69,8 @@ const seededRuns = [ length: [79654, '2eiXX/J/*&', 86617, 60111], }, bigInt: { - noArgs: 3745409999962546n, - value: 42n, + noArgs: 379177551410048n, + value: 37n, }, }, }, @@ -141,8 +141,8 @@ const seededRuns = [ length: [56052, 21258, 54308, 3397], }, bigInt: { - noArgs: 2620209999973798n, - value: 42n, + noArgs: 251225403255239n, + value: 25n, }, }, }, @@ -213,8 +213,8 @@ const seededRuns = [ length: ['Kti5-}$_/`', 76408, 35403, 69406], }, bigInt: { - noArgs: 9285209999907148n, - value: 42n, + noArgs: 948721906162743n, + value: 8n, }, }, }, @@ -417,6 +417,19 @@ describe('datatype', () => { const actual = faker.datatype.bigInt(42); expect(actual).toEqual(expectations.bigInt.value); }); + + it('should throw when min > max', () => { + const min = 10000n; + const max = 999n; + + faker.seed(seed); + + expect(() => { + faker.datatype.bigInt({ min, max }); + }).toThrowError( + new FakerError(`Max ${max} should be larger then min ${min}.`) + ); + }); }); }); } @@ -701,6 +714,76 @@ describe('datatype', () => { const generateBigInt = faker.datatype.bigInt(); expect(generateBigInt).toBeTypeOf('bigint'); }); + + it('should generate a big bigInt value with low delta', () => { + const min = 999999999n; + const max = 1000000000n; + const generateBigInt = faker.datatype.bigInt({ min, max }); + expect(generateBigInt).toBeTypeOf('bigint'); + expect(generateBigInt).toBeGreaterThanOrEqual(min); + expect(generateBigInt).toBeLessThanOrEqual(max); + }); + + it('should return a random bigint given a maximum value as BigInt', () => { + const max = 10n; + expect(faker.datatype.bigInt(max)).toBeGreaterThanOrEqual(0n); + expect(faker.datatype.bigInt(max)).toBeLessThanOrEqual(max); + }); + + it('should return a random bigint given a maximum value as Object', () => { + const options = { max: 10n }; + expect(faker.datatype.bigInt(options)).toBeGreaterThanOrEqual(0n); + expect(faker.datatype.bigInt(options)).toBeLessThanOrEqual( + options.max + ); + }); + + it('should return a random bigint given a maximum value of 0', () => { + const options = { max: 0n }; + expect(faker.datatype.bigInt(options)).toBe(0n); + }); + + it('should return a random bigint given a negative bigint minimum and maximum value of 0', () => { + const options = { min: -100n, max: 0n }; + expect(faker.datatype.bigInt(options)).toBeGreaterThanOrEqual( + options.min + ); + expect(faker.datatype.bigInt(options)).toBeLessThanOrEqual( + options.max + ); + }); + + it('should return a random bigint between a range', () => { + const options = { min: 22, max: 33 }; + for (let i = 0; i < 100; i++) { + const randomBigInt = faker.datatype.bigInt(options); + expect(randomBigInt).toBeGreaterThanOrEqual(options.min); + expect(randomBigInt).toBeLessThanOrEqual(options.max); + } + }); + + it('should succeed with success-rate', () => { + const min = 0n; + const max = 1000000000000n; + const randomBigInt = faker.datatype.bigInt({ min, max }); + expect(randomBigInt).toBeGreaterThanOrEqual(min); + expect(randomBigInt).toBeLessThanOrEqual(max); + }); + + it('should not mutate the input object', () => { + const initialMin = 1n; + const initialOtherProperty = 'hello darkness my old friend'; + const input: { + min?: bigint; + max?: bigint; + otherProperty: string; + } = Object.freeze({ + min: initialMin, + otherProperty: initialOtherProperty, + }); + + expect(() => faker.datatype.bigInt(input)).not.toThrow(); + }); }); } });