From 29fdabc12a40eacc9756524c88d40a5d2f958f1f Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 12:05:06 +0800 Subject: [PATCH 01/24] feat(number): bigInt multipleOf - has option --- src/modules/number/index.ts | 6 ++++++ test/modules/number.spec.ts | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index f5f5c27fab6..086d9a62bde 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -406,6 +406,12 @@ export class NumberModule extends SimpleModuleBase { * @default min + 999999999999999n */ max?: bigint | number | string | boolean; + /** + * The generated number will be a multiple of this parameter. + * + * @default 1n + */ + multipleOf?: bigint | number | string | boolean; } = {} ): bigint { if ( diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index d2762cf467c..560c2f1c7df 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -634,6 +634,11 @@ describe('number', () => { new FakerError(`Max ${max} should be larger then min ${min}.`) ); }); + + it('should generate a random bigint with a given multipleOf of 1n', () => { + const generateBigInt = faker.number.bigInt({ multipleOf: 1n }); + expect(generateBigInt).toBeTypeOf('bigint'); + }); }); describe('romanNumeral', () => { From 7fc7c9de1b5ea3501df191d88b42479fccf32752 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 12:08:41 +0800 Subject: [PATCH 02/24] refactor: fix typo --- src/modules/number/index.ts | 2 +- test/modules/number.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 086d9a62bde..bc74fb92f08 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -433,7 +433,7 @@ export class NumberModule extends SimpleModuleBase { } if (max < min) { - throw new FakerError(`Max ${max} should be larger then min ${min}.`); + throw new FakerError(`Max ${max} should be larger than min ${min}.`); } const delta = max - min; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 560c2f1c7df..7c38b2eee1a 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -631,7 +631,7 @@ describe('number', () => { expect(() => { faker.number.bigInt({ min, max }); }).toThrow( - new FakerError(`Max ${max} should be larger then min ${min}.`) + new FakerError(`Max ${max} should be larger than min ${min}.`) ); }); From a3352e0095d2d62821856c8ff5194cb469433150 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 12:17:07 +0800 Subject: [PATCH 03/24] feat(number): bigInt multipleOf - must be positive --- src/modules/number/index.ts | 5 +++++ test/modules/number.spec.ts | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index bc74fb92f08..8415a1f7a65 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -427,6 +427,7 @@ export class NumberModule extends SimpleModuleBase { const min = BigInt(options.min ?? 0); const max = BigInt(options.max ?? min + BigInt(999999999999999)); + const multipleOf = BigInt(options.multipleOf ?? 1); if (max === min) { return min; @@ -436,6 +437,10 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`Max ${max} should be larger than min ${min}.`); } + if (multipleOf <= 0n) { + throw new FakerError(`multipleOf should be greater than 0n.`); + } + const delta = max - min; const offset = diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 7c38b2eee1a..d429efec7bc 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -639,6 +639,12 @@ describe('number', () => { const generateBigInt = faker.number.bigInt({ multipleOf: 1n }); expect(generateBigInt).toBeTypeOf('bigint'); }); + + it('should throw for negative multipleOf', () => { + expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( + new FakerError('multipleOf should be greater than 0n.') + ); + }); }); describe('romanNumeral', () => { From d86859243fab2cd624a073e0d6a48a25602cd978 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 12:28:02 +0800 Subject: [PATCH 04/24] feat(number): bigInt multipleOf - larger than the given max --- src/modules/number/index.ts | 7 +++++++ test/modules/number.spec.ts | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 8415a1f7a65..f2456d69f52 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -440,6 +440,13 @@ export class NumberModule extends SimpleModuleBase { if (multipleOf <= 0n) { throw new FakerError(`multipleOf should be greater than 0n.`); } + if (1n < multipleOf) { + if (max < multipleOf) { + throw new FakerError( + `Multiple of ${multipleOf}n should be less than or equal to max ${max}n.` + ); + } + } const delta = max - min; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index d429efec7bc..55e0e535af1 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -645,6 +645,16 @@ describe('number', () => { new FakerError('multipleOf should be greater than 0n.') ); }); + + it('should throw when multipleOf is larger than the given max', () => { + expect(() => + faker.number.bigInt({ max: 10n, multipleOf: 20n }) + ).toThrow( + new FakerError( + 'Multiple of 20n should be less than or equal to max 10n.' + ) + ); + }); }); describe('romanNumeral', () => { From a2b3dd24d1f22ffb67fa56ec5f8a740c589216b9 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 12:31:35 +0800 Subject: [PATCH 05/24] feat(number): bigInt multipleOf - update description --- src/modules/number/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index f2456d69f52..1bcc1db9508 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -407,7 +407,7 @@ export class NumberModule extends SimpleModuleBase { */ max?: bigint | number | string | boolean; /** - * The generated number will be a multiple of this parameter. + * The generated bigint will be a multiple of this parameter. * * @default 1n */ From 6100bf55596dbed63506caa43ffc4c4992c9fd5e Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 13:23:55 +0800 Subject: [PATCH 06/24] feat(number): bigInt multipleOf - implement --- src/modules/number/index.ts | 7 +-- .../modules/__snapshots__/number.spec.ts.snap | 44 +++++++++++-------- test/modules/number.spec.ts | 7 +++ 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 1bcc1db9508..e3f14317320 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -456,10 +456,11 @@ export class NumberModule extends SimpleModuleBase { length: delta.toString(10).length, allowLeadingZeros: true, }) - ) % - (delta + BigInt(1)); + ) % delta; - return min + offset; + const remaining = multipleOf - ((min + offset) % multipleOf); + + return min + offset + remaining; } /** diff --git a/test/modules/__snapshots__/number.spec.ts.snap b/test/modules/__snapshots__/number.spec.ts.snap index 516abc9ffa8..6450a9375c6 100644 --- a/test/modules/__snapshots__/number.spec.ts.snap +++ b/test/modules/__snapshots__/number.spec.ts.snap @@ -1,18 +1,20 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`number > 42 > bigInt > noArgs 1`] = `397511086709821n`; +exports[`number > 42 > bigInt > noArgs 1`] = `397511086709822n`; -exports[`number > 42 > bigInt > with big options 1`] = `19556777749482489605814694n`; +exports[`number > 42 > bigInt > with big options 1`] = `19556777749482489605814696n`; -exports[`number > 42 > bigInt > with bigint value 1`] = `25n`; +exports[`number > 42 > bigInt > with bigint value 1`] = `29n`; exports[`number > 42 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 42 > bigInt > with number value 1`] = `39n`; +exports[`number > 42 > bigInt > with multipleOf 1`] = `397511086716281n`; -exports[`number > 42 > bigInt > with options 1`] = `19n`; +exports[`number > 42 > bigInt > with number value 1`] = `40n`; -exports[`number > 42 > bigInt > with string value 1`] = `39n`; +exports[`number > 42 > bigInt > with options 1`] = `23n`; + +exports[`number > 42 > bigInt > with string value 1`] = `40n`; exports[`number > 42 > binary > noArgs 1`] = `"0"`; @@ -64,19 +66,21 @@ exports[`number > 42 > romanNumeral > with only max 1`] = `"LXII"`; exports[`number > 42 > romanNumeral > with only min 1`] = `"MDI"`; -exports[`number > 1211 > bigInt > noArgs 1`] = `982966736876848n`; +exports[`number > 1211 > bigInt > noArgs 1`] = `982966736876849n`; -exports[`number > 1211 > bigInt > with big options 1`] = `25442250580110979794946298n`; +exports[`number > 1211 > bigInt > with big options 1`] = `25442250580110979794946302n`; -exports[`number > 1211 > bigInt > with bigint value 1`] = `114n`; +exports[`number > 1211 > bigInt > with bigint value 1`] = `122n`; exports[`number > 1211 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 1211 > bigInt > with number value 1`] = `12n`; +exports[`number > 1211 > bigInt > with multipleOf 1`] = `982966736876952n`; + +exports[`number > 1211 > bigInt > with number value 1`] = `15n`; -exports[`number > 1211 > bigInt > with options 1`] = `44n`; +exports[`number > 1211 > bigInt > with options 1`] = `53n`; -exports[`number > 1211 > bigInt > with string value 1`] = `28n`; +exports[`number > 1211 > bigInt > with string value 1`] = `30n`; exports[`number > 1211 > binary > noArgs 1`] = `"1"`; @@ -128,19 +132,21 @@ exports[`number > 1211 > romanNumeral > with only max 1`] = `"CLIV"`; exports[`number > 1211 > romanNumeral > with only min 1`] = `"MMMDCCXIV"`; -exports[`number > 1337 > bigInt > noArgs 1`] = `212435297136194n`; +exports[`number > 1337 > bigInt > noArgs 1`] = `212435297136195n`; + +exports[`number > 1337 > bigInt > with big options 1`] = `27379244885156992800029993n`; -exports[`number > 1337 > bigInt > with big options 1`] = `27379244885156992800029992n`; +exports[`number > 1337 > bigInt > with bigint value 1`] = `90n`; -exports[`number > 1337 > bigInt > with bigint value 1`] = `88n`; +exports[`number > 1337 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 1337 > bigInt > with boolean value 1`] = `0n`; +exports[`number > 1337 > bigInt > with multipleOf 1`] = `212435297138188n`; -exports[`number > 1337 > bigInt > with number value 1`] = `21n`; +exports[`number > 1337 > bigInt > with number value 1`] = `22n`; -exports[`number > 1337 > bigInt > with options 1`] = `58n`; +exports[`number > 1337 > bigInt > with options 1`] = `60n`; -exports[`number > 1337 > bigInt > with string value 1`] = `21n`; +exports[`number > 1337 > bigInt > with string value 1`] = `22n`; exports[`number > 1337 > binary > noArgs 1`] = `"0"`; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 55e0e535af1..6258742b887 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -50,6 +50,7 @@ describe('number', () => { .it('with boolean value', true) .it('with bigint value', 123n) .it('with options', { min: -42, max: 69 }) + .it('with multipleOf', { multipleOf: 7919n }) .it('with big options', { min: 6135715171537515454317351n, max: 32465761264574654845432354n, @@ -640,6 +641,12 @@ describe('number', () => { expect(generateBigInt).toBeTypeOf('bigint'); }); + it('should generate a random bigint with a given multipleOf of 7919n', () => { + const generateBigInt = faker.number.bigInt({ multipleOf: 7919n }); + expect(generateBigInt).toBeTypeOf('bigint'); + expect(generateBigInt % 7919n).toBe(0n); + }); + it('should throw for negative multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( new FakerError('multipleOf should be greater than 0n.') From 1cb6b03f3e3902f55d091c404c1a620abeb34e73 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 13:37:39 +0800 Subject: [PATCH 07/24] test: fix test name --- test/modules/number.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 6258742b887..c9f0177a3ac 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -647,7 +647,7 @@ describe('number', () => { expect(generateBigInt % 7919n).toBe(0n); }); - it('should throw for negative multipleOf', () => { + it('should throw for non-positive multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( new FakerError('multipleOf should be greater than 0n.') ); From c28fda7b0da93a02f47a078838dd828c338420c0 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 17:19:16 +0800 Subject: [PATCH 08/24] style: lint --- src/modules/number/index.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index e3f14317320..7ebe8741ba0 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -440,12 +440,11 @@ export class NumberModule extends SimpleModuleBase { if (multipleOf <= 0n) { throw new FakerError(`multipleOf should be greater than 0n.`); } - if (1n < multipleOf) { - if (max < multipleOf) { - throw new FakerError( - `Multiple of ${multipleOf}n should be less than or equal to max ${max}n.` - ); - } + + if (1n < multipleOf && max < multipleOf) { + throw new FakerError( + `Multiple of ${multipleOf}n should be less than or equal to max ${max}n.` + ); } const delta = max - min; From 82fa428f077bdf10a03d7b87481e87734b85a5c2 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 17:40:39 +0800 Subject: [PATCH 09/24] feat: add param and example --- src/modules/number/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 7ebe8741ba0..5dfb85a8b8c 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -375,6 +375,7 @@ export class NumberModule extends SimpleModuleBase { * @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`. + * @param options.multipleOf The generated bigint will be a multiple of this parameter. Defaults to `1n`. * * @throws When `min` is greater than `max`. * @@ -383,6 +384,7 @@ export class NumberModule extends SimpleModuleBase { * faker.number.bigInt(100n) // 52n * faker.number.bigInt({ min: 1000000n }) // 431433n * faker.number.bigInt({ max: 100n }) // 42n + * faker.number.bigInt({ multipleOf: 7n }) // 35n * faker.number.bigInt({ min: 10n, max: 100n }) // 36n * * @since 8.0.0 From 2aa02702fd478367c943331d51d2613a82441c42 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sun, 16 Feb 2025 17:44:29 +0800 Subject: [PATCH 10/24] feat: add throws --- src/modules/number/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 5dfb85a8b8c..c0d3e1c02ee 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -378,6 +378,8 @@ export class NumberModule extends SimpleModuleBase { * @param options.multipleOf The generated bigint will be a multiple of this parameter. Defaults to `1n`. * * @throws When `min` is greater than `max`. + * @throws When `multipleOf` is not a positive bigint. + * @throws When `multipleOf` is greater than `max`. * * @example * faker.number.bigInt() // 55422n From 0db440d28d9163b2d62a9a00e3051fe71d99f30c Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 11:41:39 +0800 Subject: [PATCH 11/24] test: it should throw if there is no suitable bigint value between min and max --- test/modules/number.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index c9f0177a3ac..6e8d0cf62a3 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -662,6 +662,14 @@ describe('number', () => { ) ); }); + + it('should throw if there is no suitable bigint value between min and max', () => { + expect(() => + faker.number.bigInt({ min: 6, max: 9, multipleOf: 5 }) + ).toThrow( + new FakerError('No suitable bigint value between 6n and 9n found.') + ); + }); }); describe('romanNumeral', () => { From 98b18d59a3e6ecc3090ae9f02694389b7b28d497 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 11:41:10 +0800 Subject: [PATCH 12/24] test: should generate a random bigint with a given max value less than multipleOf --- test/modules/number.spec.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 6e8d0cf62a3..4b708e1dbc5 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -647,22 +647,21 @@ describe('number', () => { expect(generateBigInt % 7919n).toBe(0n); }); + it('should generate a random bigint with a given max value less than multipleOf', () => { + const generatedBigInt = faker.number.bigInt({ + max: 10n, + multipleOf: 20n, + }); + expect(generatedBigInt).toBeTypeOf('bigint'); + expect(generatedBigInt % 20n).toBe(0n); + }); + it('should throw for non-positive multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( new FakerError('multipleOf should be greater than 0n.') ); }); - it('should throw when multipleOf is larger than the given max', () => { - expect(() => - faker.number.bigInt({ max: 10n, multipleOf: 20n }) - ).toThrow( - new FakerError( - 'Multiple of 20n should be less than or equal to max 10n.' - ) - ); - }); - it('should throw if there is no suitable bigint value between min and max', () => { expect(() => faker.number.bigInt({ min: 6, max: 9, multipleOf: 5 }) From bce50d2926250f6afd62e782556612ea0baae694 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 11:34:17 +0800 Subject: [PATCH 13/24] test: it should generate a suitable bigint value between negative min and max --- test/modules/number.spec.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 4b708e1dbc5..3519f299fa2 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -656,6 +656,16 @@ describe('number', () => { expect(generatedBigInt % 20n).toBe(0n); }); + it('should generate a suitable bigint value between negative min and max', () => { + const generateBigInt = faker.number.bigInt({ + min: -9, + max: 0, + multipleOf: 5, + }); + expect(generateBigInt).toBeTypeOf('bigint'); + expect(generateBigInt % 5n).toBe(0n); + }); + it('should throw for non-positive multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( new FakerError('multipleOf should be greater than 0n.') From c9cfa2b559543cf3bd3891b04ca26ebb2d9914a7 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 12:21:00 +0800 Subject: [PATCH 14/24] fix: bigint --- src/modules/number/index.ts | 21 ++++++++++++------- .../modules/__snapshots__/number.spec.ts.snap | 6 +++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index c0d3e1c02ee..b6bc7b952aa 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -445,14 +445,20 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`multipleOf should be greater than 0n.`); } - if (1n < multipleOf && max < multipleOf) { + const effectiveMin = min / multipleOf + (min % multipleOf === 0n ? 0n : 1n); + const effectiveMax = max / multipleOf; + + if (effectiveMin === effectiveMax) { + return effectiveMin * multipleOf; + } + + if (effectiveMax < effectiveMin) { throw new FakerError( - `Multiple of ${multipleOf}n should be less than or equal to max ${max}n.` + `No suitable bigint value between ${min}n and ${max}n found.` ); } - const delta = max - min; - + const delta = effectiveMax - effectiveMin; const offset = BigInt( this.faker.string.numeric({ @@ -460,10 +466,9 @@ export class NumberModule extends SimpleModuleBase { allowLeadingZeros: true, }) ) % delta; - - const remaining = multipleOf - ((min + offset) % multipleOf); - - return min + offset + remaining; + const random = effectiveMin * multipleOf + offset; + const remaining = multipleOf - (random % multipleOf); + return random + remaining; } /** diff --git a/test/modules/__snapshots__/number.spec.ts.snap b/test/modules/__snapshots__/number.spec.ts.snap index 6450a9375c6..783bdbb005f 100644 --- a/test/modules/__snapshots__/number.spec.ts.snap +++ b/test/modules/__snapshots__/number.spec.ts.snap @@ -8,7 +8,7 @@ exports[`number > 42 > bigInt > with bigint value 1`] = `29n`; exports[`number > 42 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 42 > bigInt > with multipleOf 1`] = `397511086716281n`; +exports[`number > 42 > bigInt > with multipleOf 1`] = `18675377700n`; exports[`number > 42 > bigInt > with number value 1`] = `40n`; @@ -74,7 +74,7 @@ exports[`number > 1211 > bigInt > with bigint value 1`] = `122n`; exports[`number > 1211 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 1211 > bigInt > with multipleOf 1`] = `982966736876952n`; +exports[`number > 1211 > bigInt > with multipleOf 1`] = `99016744867n`; exports[`number > 1211 > bigInt > with number value 1`] = `15n`; @@ -140,7 +140,7 @@ exports[`number > 1337 > bigInt > with bigint value 1`] = `90n`; exports[`number > 1337 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 1337 > bigInt > with multipleOf 1`] = `212435297138188n`; +exports[`number > 1337 > bigInt > with multipleOf 1`] = `86156732331n`; exports[`number > 1337 > bigInt > with number value 1`] = `22n`; From 1f3add858e58ae01c31a344017bb05b12fbfdff5 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 12:36:21 +0800 Subject: [PATCH 15/24] feat: ensure error messages follow the same format --- src/modules/number/index.ts | 4 ++-- test/modules/number.spec.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index b6bc7b952aa..107779e8887 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -442,7 +442,7 @@ export class NumberModule extends SimpleModuleBase { } if (multipleOf <= 0n) { - throw new FakerError(`multipleOf should be greater than 0n.`); + throw new FakerError(`multipleOf should be greater than 0.`); } const effectiveMin = min / multipleOf + (min % multipleOf === 0n ? 0n : 1n); @@ -454,7 +454,7 @@ export class NumberModule extends SimpleModuleBase { if (effectiveMax < effectiveMin) { throw new FakerError( - `No suitable bigint value between ${min}n and ${max}n found.` + `No suitable bigint value between ${min} and ${max} found.` ); } diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 3519f299fa2..15f4b96cc02 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -668,7 +668,7 @@ describe('number', () => { it('should throw for non-positive multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( - new FakerError('multipleOf should be greater than 0n.') + new FakerError('multipleOf should be greater than 0.') ); }); @@ -676,7 +676,7 @@ describe('number', () => { expect(() => faker.number.bigInt({ min: 6, max: 9, multipleOf: 5 }) ).toThrow( - new FakerError('No suitable bigint value between 6n and 9n found.') + new FakerError('No suitable bigint value between 6 and 9 found.') ); }); }); From 66f7a455e9ad51038d423c2d374aacb55def3b44 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 12:40:11 +0800 Subject: [PATCH 16/24] test: it should throw if there is no suitable bigint value between same min and max --- src/modules/number/index.ts | 4 ---- test/modules/number.spec.ts | 8 ++++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 107779e8887..a68627da42c 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -433,10 +433,6 @@ export class NumberModule extends SimpleModuleBase { const max = BigInt(options.max ?? min + BigInt(999999999999999)); const multipleOf = BigInt(options.multipleOf ?? 1); - if (max === min) { - return min; - } - if (max < min) { throw new FakerError(`Max ${max} should be larger than min ${min}.`); } diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 15f4b96cc02..e9d113ac023 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -679,6 +679,14 @@ describe('number', () => { new FakerError('No suitable bigint value between 6 and 9 found.') ); }); + + it('should throw if there is no suitable bigint value between same min and max', () => { + expect(() => + faker.number.bigInt({ min: 1, max: 1, multipleOf: 5 }) + ).toThrow( + new FakerError('No suitable bigint value between 1 and 1 found.') + ); + }) }); describe('romanNumeral', () => { From 7af04579e7e053a4fe70378f800506bf1ca2c269 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 12:48:27 +0800 Subject: [PATCH 17/24] style: format --- test/modules/number.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index e9d113ac023..00483a20cf9 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -686,7 +686,7 @@ describe('number', () => { ).toThrow( new FakerError('No suitable bigint value between 1 and 1 found.') ); - }) + }); }); describe('romanNumeral', () => { From fd245e9a5ae4fe884e775c8f7bf935da73e7de88 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 13:41:24 +0800 Subject: [PATCH 18/24] fix: it should generate a suitable bigint value between negative min and negative max --- src/modules/number/index.ts | 14 ++++++++++++-- test/modules/number.spec.ts | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index a68627da42c..5e02175bec1 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -441,8 +441,18 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`multipleOf should be greater than 0.`); } - const effectiveMin = min / multipleOf + (min % multipleOf === 0n ? 0n : 1n); - const effectiveMax = max / multipleOf; + const effectiveMin = + min % multipleOf === 0n + ? min / multipleOf + : 0n <= min + ? min / multipleOf + 1n + : min / multipleOf; + const effectiveMax = + max % multipleOf === 0n + ? max / multipleOf + : 0n <= max + ? max / multipleOf + : max / multipleOf - 1n; if (effectiveMin === effectiveMax) { return effectiveMin * multipleOf; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 00483a20cf9..cce5d6e8e44 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -666,6 +666,26 @@ describe('number', () => { expect(generateBigInt % 5n).toBe(0n); }); + it('should generate a suitable bigint value between negative min and negative max', () => { + const generateBigInt = faker.number.bigInt({ + min: -9, + max: -1, + multipleOf: 5, + }); + expect(generateBigInt).toBeTypeOf('bigint'); + expect(generateBigInt).toBe(-5n); + }); + + it('should generate a suitable bigint value between negative min and negative max (edge case)', () => { + const generateBigInt = faker.number.bigInt({ + min: -9, + max: -1, + multipleOf: 9, + }); + expect(generateBigInt).toBeTypeOf('bigint'); + expect(generateBigInt).toBe(-9n); + }); + it('should throw for non-positive multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( new FakerError('multipleOf should be greater than 0.') From a900efb1d551e36317fdbec0f8f73b8343611969 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 14:27:45 +0800 Subject: [PATCH 19/24] fix: it should returns inclusive bounds --- src/modules/number/index.ts | 7 +-- .../modules/__snapshots__/number.spec.ts.snap | 44 ++++++------- test/modules/number.spec.ts | 62 +++++++++++++++++++ 3 files changed, 87 insertions(+), 26 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 5e02175bec1..561683e7c6e 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -471,10 +471,9 @@ export class NumberModule extends SimpleModuleBase { length: delta.toString(10).length, allowLeadingZeros: true, }) - ) % delta; - const random = effectiveMin * multipleOf + offset; - const remaining = multipleOf - (random % multipleOf); - return random + remaining; + ) % + (delta + 1n); + return (effectiveMin + offset) * multipleOf; } /** diff --git a/test/modules/__snapshots__/number.spec.ts.snap b/test/modules/__snapshots__/number.spec.ts.snap index 783bdbb005f..52c54964625 100644 --- a/test/modules/__snapshots__/number.spec.ts.snap +++ b/test/modules/__snapshots__/number.spec.ts.snap @@ -1,20 +1,20 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`number > 42 > bigInt > noArgs 1`] = `397511086709822n`; +exports[`number > 42 > bigInt > noArgs 1`] = `397511086709821n`; -exports[`number > 42 > bigInt > with big options 1`] = `19556777749482489605814696n`; +exports[`number > 42 > bigInt > with big options 1`] = `19556777749482489605814694n`; -exports[`number > 42 > bigInt > with bigint value 1`] = `29n`; +exports[`number > 42 > bigInt > with bigint value 1`] = `25n`; exports[`number > 42 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 42 > bigInt > with multipleOf 1`] = `18675377700n`; +exports[`number > 42 > bigInt > with multipleOf 1`] = `147890295638632n`; -exports[`number > 42 > bigInt > with number value 1`] = `40n`; +exports[`number > 42 > bigInt > with number value 1`] = `39n`; -exports[`number > 42 > bigInt > with options 1`] = `23n`; +exports[`number > 42 > bigInt > with options 1`] = `19n`; -exports[`number > 42 > bigInt > with string value 1`] = `40n`; +exports[`number > 42 > bigInt > with string value 1`] = `39n`; exports[`number > 42 > binary > noArgs 1`] = `"0"`; @@ -66,21 +66,21 @@ exports[`number > 42 > romanNumeral > with only max 1`] = `"LXII"`; exports[`number > 42 > romanNumeral > with only min 1`] = `"MDI"`; -exports[`number > 1211 > bigInt > noArgs 1`] = `982966736876849n`; +exports[`number > 1211 > bigInt > noArgs 1`] = `982966736876848n`; -exports[`number > 1211 > bigInt > with big options 1`] = `25442250580110979794946302n`; +exports[`number > 1211 > bigInt > with big options 1`] = `25442250580110979794946298n`; -exports[`number > 1211 > bigInt > with bigint value 1`] = `122n`; +exports[`number > 1211 > bigInt > with bigint value 1`] = `114n`; exports[`number > 1211 > bigInt > with boolean value 1`] = `1n`; -exports[`number > 1211 > bigInt > with multipleOf 1`] = `99016744867n`; +exports[`number > 1211 > bigInt > with multipleOf 1`] = `784113589297853n`; -exports[`number > 1211 > bigInt > with number value 1`] = `15n`; +exports[`number > 1211 > bigInt > with number value 1`] = `12n`; -exports[`number > 1211 > bigInt > with options 1`] = `53n`; +exports[`number > 1211 > bigInt > with options 1`] = `44n`; -exports[`number > 1211 > bigInt > with string value 1`] = `30n`; +exports[`number > 1211 > bigInt > with string value 1`] = `28n`; exports[`number > 1211 > binary > noArgs 1`] = `"1"`; @@ -132,21 +132,21 @@ exports[`number > 1211 > romanNumeral > with only max 1`] = `"CLIV"`; exports[`number > 1211 > romanNumeral > with only min 1`] = `"MMMDCCXIV"`; -exports[`number > 1337 > bigInt > noArgs 1`] = `212435297136195n`; +exports[`number > 1337 > bigInt > noArgs 1`] = `212435297136194n`; -exports[`number > 1337 > bigInt > with big options 1`] = `27379244885156992800029993n`; +exports[`number > 1337 > bigInt > with big options 1`] = `27379244885156992800029992n`; -exports[`number > 1337 > bigInt > with bigint value 1`] = `90n`; +exports[`number > 1337 > bigInt > with bigint value 1`] = `88n`; -exports[`number > 1337 > bigInt > with boolean value 1`] = `1n`; +exports[`number > 1337 > bigInt > with boolean value 1`] = `0n`; -exports[`number > 1337 > bigInt > with multipleOf 1`] = `86156732331n`; +exports[`number > 1337 > bigInt > with multipleOf 1`] = `682275118016671n`; -exports[`number > 1337 > bigInt > with number value 1`] = `22n`; +exports[`number > 1337 > bigInt > with number value 1`] = `21n`; -exports[`number > 1337 > bigInt > with options 1`] = `60n`; +exports[`number > 1337 > bigInt > with options 1`] = `58n`; -exports[`number > 1337 > bigInt > with string value 1`] = `22n`; +exports[`number > 1337 > bigInt > with string value 1`] = `21n`; exports[`number > 1337 > binary > noArgs 1`] = `"0"`; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index cce5d6e8e44..278baadb1df 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -686,6 +686,68 @@ describe('number', () => { expect(generateBigInt).toBe(-9n); }); + it('should return inclusive positive min/max value', () => { + const positive4 = 4n; + const positive5 = 5n; + let foundPositive4 = false; + let foundPositive5 = false; + + for (let iter = 0; iter < 1000; iter++) { + const actual = faker.number.bigInt({ + min: positive4, + max: positive5, + }); + + if (actual === positive4) { + foundPositive4 = true; + } else if (actual === positive5) { + foundPositive5 = true; + } + + expect(actual).toBeTypeOf('bigint'); + expect(actual).toBeGreaterThanOrEqual(positive4); + expect(actual).toBeLessThanOrEqual(positive5); + + if (foundPositive4 && foundPositive5) { + break; + } + } + + expect(foundPositive4).toBeTruthy(); + expect(foundPositive5).toBeTruthy(); + }); + + it('should return inclusive negative min/max value', () => { + const negative4 = -4n; + const negative5 = -5n; + let foundNegative4 = false; + let foundNegative5 = false; + + for (let iter = 0; iter < 1000; iter++) { + const actual = faker.number.bigInt({ + min: negative5, + max: negative4, + }); + + if (actual === negative4) { + foundNegative4 = true; + } else if (actual === negative5) { + foundNegative5 = true; + } + + expect(actual).toBeTypeOf('bigint'); + expect(actual).toBeGreaterThanOrEqual(negative5); + expect(actual).toBeLessThanOrEqual(negative4); + + if (foundNegative4 && foundNegative5) { + break; + } + } + + expect(foundNegative4).toBeTruthy(); + expect(foundNegative5).toBeTruthy(); + }); + it('should throw for non-positive multipleOf', () => { expect(() => faker.number.bigInt({ multipleOf: 0n })).toThrow( new FakerError('multipleOf should be greater than 0.') From 659fa090b63c22e638672cbe18746a632c1b1d01 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 22 Feb 2025 14:35:56 +0800 Subject: [PATCH 20/24] refactor: use BigInt --- src/modules/number/index.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 561683e7c6e..09eb53db303 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -437,22 +437,22 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`Max ${max} should be larger than min ${min}.`); } - if (multipleOf <= 0n) { + if (multipleOf <= BigInt(0)) { throw new FakerError(`multipleOf should be greater than 0.`); } const effectiveMin = - min % multipleOf === 0n + min % multipleOf === BigInt(0) ? min / multipleOf - : 0n <= min - ? min / multipleOf + 1n + : BigInt(0) <= min + ? min / multipleOf + BigInt(1) : min / multipleOf; const effectiveMax = - max % multipleOf === 0n + max % multipleOf === BigInt(0) ? max / multipleOf - : 0n <= max + : BigInt(0) <= max ? max / multipleOf - : max / multipleOf - 1n; + : max / multipleOf - BigInt(1); if (effectiveMin === effectiveMax) { return effectiveMin * multipleOf; @@ -472,7 +472,7 @@ export class NumberModule extends SimpleModuleBase { allowLeadingZeros: true, }) ) % - (delta + 1n); + (delta + BigInt(1)); return (effectiveMin + offset) * multipleOf; } From 54afb886642ffaa8d08238cb31be1832e938d029 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 1 Mar 2025 10:33:04 +0800 Subject: [PATCH 21/24] refactor: #discussion_r1976176202 --- src/modules/number/index.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 09eb53db303..b095729868a 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -441,18 +441,8 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`multipleOf should be greater than 0.`); } - const effectiveMin = - min % multipleOf === BigInt(0) - ? min / multipleOf - : BigInt(0) <= min - ? min / multipleOf + BigInt(1) - : min / multipleOf; - const effectiveMax = - max % multipleOf === BigInt(0) - ? max / multipleOf - : BigInt(0) <= max - ? max / multipleOf - : max / multipleOf - BigInt(1); + const effectiveMin = min / multipleOf + (min % multipleOf > 0n ? 1n : 0n); // Math.ceil(min / multipleOf) + const effectiveMax = max / multipleOf - (max % multipleOf < 0n ? 1n : 0n); // Math.floor(max / multipleOf) if (effectiveMin === effectiveMax) { return effectiveMin * multipleOf; From 042c058011fbe106f3fbc3d6dd1db2ebf9b7e24a Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 1 Mar 2025 10:34:59 +0800 Subject: [PATCH 22/24] refactor: #discussion_r1976178977, #discussion_r1976179961 --- src/modules/number/index.ts | 5 ++--- test/modules/__snapshots__/number.spec.ts.snap | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index b095729868a..ea95c1b5282 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -454,15 +454,14 @@ export class NumberModule extends SimpleModuleBase { ); } - const delta = effectiveMax - effectiveMin; + const delta = effectiveMax - effectiveMin + 1n; // +1 for inclusive max bounds and even distribution const offset = BigInt( this.faker.string.numeric({ length: delta.toString(10).length, allowLeadingZeros: true, }) - ) % - (delta + BigInt(1)); + ) % delta; return (effectiveMin + offset) * multipleOf; } diff --git a/test/modules/__snapshots__/number.spec.ts.snap b/test/modules/__snapshots__/number.spec.ts.snap index 52c54964625..521fc0566e5 100644 --- a/test/modules/__snapshots__/number.spec.ts.snap +++ b/test/modules/__snapshots__/number.spec.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`number > 42 > bigInt > noArgs 1`] = `397511086709821n`; +exports[`number > 42 > bigInt > noArgs 1`] = `975110867098211n`; exports[`number > 42 > bigInt > with big options 1`] = `19556777749482489605814694n`; @@ -66,7 +66,7 @@ exports[`number > 42 > romanNumeral > with only max 1`] = `"LXII"`; exports[`number > 42 > romanNumeral > with only min 1`] = `"MDI"`; -exports[`number > 1211 > bigInt > noArgs 1`] = `982966736876848n`; +exports[`number > 1211 > bigInt > noArgs 1`] = `829667368768488n`; exports[`number > 1211 > bigInt > with big options 1`] = `25442250580110979794946298n`; @@ -132,7 +132,7 @@ exports[`number > 1211 > romanNumeral > with only max 1`] = `"CLIV"`; exports[`number > 1211 > romanNumeral > with only min 1`] = `"MMMDCCXIV"`; -exports[`number > 1337 > bigInt > noArgs 1`] = `212435297136194n`; +exports[`number > 1337 > bigInt > noArgs 1`] = `124352971361947n`; exports[`number > 1337 > bigInt > with big options 1`] = `27379244885156992800029992n`; From a8ab42d5c6afddd7d90cda76dbb0e5f20d8e1223 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 1 Mar 2025 10:41:09 +0800 Subject: [PATCH 23/24] fix: #discussion_r1976181511 --- src/modules/number/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index ea95c1b5282..108f6c8c4fa 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -379,7 +379,6 @@ export class NumberModule extends SimpleModuleBase { * * @throws When `min` is greater than `max`. * @throws When `multipleOf` is not a positive bigint. - * @throws When `multipleOf` is greater than `max`. * * @example * faker.number.bigInt() // 55422n From bc6deac70fa7d89cb9b9670a6652e3a44257d355 Mon Sep 17 00:00:00 2001 From: Ernest Date: Sat, 1 Mar 2025 10:46:19 +0800 Subject: [PATCH 24/24] fix: add throws --- src/modules/number/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index 108f6c8c4fa..f1dce04fb45 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -378,6 +378,7 @@ export class NumberModule extends SimpleModuleBase { * @param options.multipleOf The generated bigint will be a multiple of this parameter. Defaults to `1n`. * * @throws When `min` is greater than `max`. + * @throws When there are no suitable bigint between `min` and `max`. * @throws When `multipleOf` is not a positive bigint. * * @example