From 9231b8530f3f8f04e5a63ea09f621790150d78fd Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Thu, 30 Nov 2023 18:49:15 +0100 Subject: [PATCH 1/8] refactor(number): deprecate precision in favor of multipleOf in float --- src/modules/number/index.ts | 40 +++++++++--- .../modules/__snapshots__/number.spec.ts.snap | 6 ++ test/modules/number.spec.ts | 64 ++++++++++++++++++- 3 files changed, 99 insertions(+), 11 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index a20a0040fdf..b12ce1782f9 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -1,4 +1,5 @@ import { FakerError } from '../../errors/faker-error'; +import { deprecated } from '../../internal/deprecated'; import { SimpleModuleBase } from '../../internal/module-base'; /** @@ -84,22 +85,26 @@ export class NumberModule extends SimpleModuleBase { } /** - * Returns a single random floating-point number for a given precision or range and precision. - * The lower bound is inclusive, the upper bound is exclusive, unless precision is passed. + * Returns a single random floating-point number for a given multipleOf or range and multipleOf. + * The lower bound is inclusive, the upper bound is exclusive, unless multipleOf is passed. * * @param options Upper bound or options object. * @param options.min Lower bound for generated number. Defaults to `0.0`. * @param options.max Upper bound for generated number. Defaults to `1.0`. * @param options.precision Precision of the generated number, for example `0.01` will round to 2 decimal points. * If precision is passed, the upper bound is inclusive. + * @param options.multipleOf The generated number will be a multiple of this property. + * This property can be used to achieve specific decimal points. + * For example `0.01` will round to 2 decimal points. + * If multipleOf is passed, the upper bound is inclusive. * * @example * faker.number.float() // 0.5688541042618454 * faker.number.float(3) // 2.367973240558058 * faker.number.float({ min: -1000000 }) //-780678.849672846 * faker.number.float({ max: 100 }) // 17.3687307164073 - * faker.number.float({ precision: 0.1 }) // 0.9 - * faker.number.float({ min: 10, max: 100, precision: 0.001 }) // 35.415 + * faker.number.float({ multipleOf: 0.25 }) // 3.75 + * faker.number.float({ min: 10, max: 100, multipleOf: 0.001 }) // 35.415 * * @since 8.0.0 */ @@ -121,8 +126,15 @@ export class NumberModule extends SimpleModuleBase { max?: number; /** * Precision of the generated number. + * + * @deprecated Use `multipleOf` instead. */ precision?: number; + /** + * The generated number will be a multiple of this property. + * If multipleOf is passed, the upper bound is inclusive. + */ + multipleOf?: number; } = {} ): number { if (typeof options === 'number') { @@ -131,7 +143,17 @@ export class NumberModule extends SimpleModuleBase { }; } - const { min = 0, max = 1, precision } = options; + // eslint-disable-next-line deprecation/deprecation + const { min = 0, max = 1, precision, multipleOf = precision } = options; + + if (precision !== undefined) { + deprecated({ + deprecated: 'faker.number.float({ precision })', + proposed: 'faker.number.float({ multipleOf })', + since: '8.4', + until: '9.0', + }); + } if (max === min) { return min; @@ -141,12 +163,12 @@ export class NumberModule extends SimpleModuleBase { throw new FakerError(`Max ${max} should be greater than min ${min}.`); } - if (precision !== undefined) { - if (precision <= 0) { - throw new FakerError(`Precision should be greater than 0.`); + if (multipleOf !== undefined) { + if (multipleOf <= 0) { + throw new FakerError(`Multiple of should be greater than 0.`); } - const factor = 1 / precision; + const factor = 1 / multipleOf; const int = this.int({ min: min * factor, max: max * factor, diff --git a/test/modules/__snapshots__/number.spec.ts.snap b/test/modules/__snapshots__/number.spec.ts.snap index 3d10ddb4477..c04b4fe561e 100644 --- a/test/modules/__snapshots__/number.spec.ts.snap +++ b/test/modules/__snapshots__/number.spec.ts.snap @@ -26,6 +26,8 @@ exports[`number > 42 > float > with min 1`] = `-25.894775084685534`; exports[`number > 42 > float > with min and max 1`] = `-0.4260473116301`; +exports[`number > 42 > float > with min, max and multipleOf 1`] = `-0.4261`; + exports[`number > 42 > float > with min, max and precision 1`] = `-0.4261`; exports[`number > 42 > float > with plain number 1`] = `1.498160457238555`; @@ -74,6 +76,8 @@ exports[`number > 1211 > float > with min 1`] = `-2.073633389081806`; exports[`number > 1211 > float > with min and max 1`] = `61.06573706539348`; +exports[`number > 1211 > float > with min, max and multipleOf 1`] = `61.0658`; + exports[`number > 1211 > float > with min, max and precision 1`] = `61.0658`; exports[`number > 1211 > float > with plain number 1`] = `3.7140806149691343`; @@ -122,6 +126,8 @@ exports[`number > 1337 > float > with min 1`] = `-30.732938923640177`; exports[`number > 1337 > float > with min and max 1`] = `-12.915260942419991`; +exports[`number > 1337 > float > with min, max and multipleOf 1`] = `-12.9153`; + exports[`number > 1337 > float > with min, max and precision 1`] = `-12.9153`; exports[`number > 1337 > float > with plain number 1`] = `1.048098704777658`; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 66018ee61bd..b3d9f069b6b 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -25,6 +25,11 @@ describe('number', () => { min: -42, max: 69, precision: 0.0001, + }) + .it('with min, max and multipleOf', { + min: -42, + max: 69, + multipleOf: 0.0001, }); }); @@ -242,6 +247,22 @@ describe('number', () => { expect(results).toEqual([0, 0.5, 1, 1.5]); }); + it('provides numbers with a given multipleOf of 0.5 steps', () => { + const results = [ + ...new Set( + Array.from({ length: 50 }, () => + faker.number.float({ + min: 0, + max: 1.5, + multipleOf: 0.5, + }) + ) + ), + ].sort(); + + expect(results).toEqual([0, 0.5, 1, 1.5]); + }); + it('provides numbers with a given precision of 0.4 steps', () => { const results = [ ...new Set( @@ -258,6 +279,22 @@ describe('number', () => { expect(results).toEqual([0, 0.4, 0.8, 1.2, 1.6]); }); + it('provides numbers with a given multipleOf of 0.4 steps', () => { + const results = [ + ...new Set( + Array.from({ length: 50 }, () => + faker.number.float({ + min: 0, + max: 1.9, + multipleOf: 0.4, + }) + ) + ), + ].sort(); + + expect(results).toEqual([0, 0.4, 0.8, 1.2, 1.6]); + }); + it('provides numbers with an exact precision', () => { for (let i = 0; i < 100; i++) { const actual = faker.number.float({ @@ -269,15 +306,38 @@ describe('number', () => { } }); + it('provides numbers with an exact precision via multipleOf', () => { + for (let i = 0; i < 100; i++) { + const actual = faker.number.float({ + min: 0.5, + max: 0.99, + multipleOf: 0.01, + }); + expect(actual).toBe(Number(actual.toFixed(2))); + } + }); + it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( - new FakerError('Precision should be greater than 0.') + new FakerError('Multiple of should be greater than 0.') + ); + }); + + it('throws an error for multipleOf 0', () => { + expect(() => faker.number.float({ multipleOf: 0 })).toThrow( + new FakerError('Multiple of should be greater than 0.') ); }); it('throws an error for negative precision', () => { expect(() => faker.number.float({ precision: -0.01 })).toThrow( - new FakerError('Precision should be greater than 0.') + new FakerError('Multiple of should be greater than 0.') + ); + }); + + it('throws an error for negative multipleOf', () => { + expect(() => faker.number.float({ multipleOf: -0.01 })).toThrow( + new FakerError('Multiple of should be greater than 0.') ); }); From a0bcf59acf8556ceb6adcfd2afb988181adc47ab Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Sun, 10 Dec 2023 14:38:24 +0100 Subject: [PATCH 2/8] refactor: replace precision to multipleOf --- src/modules/color/index.ts | 18 +++++++++--------- src/modules/datatype/index.ts | 4 ++-- src/modules/finance/index.ts | 2 +- src/modules/helpers/index.ts | 2 +- src/modules/location/index.ts | 8 ++++---- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/modules/color/index.ts b/src/modules/color/index.ts index 57b906a376d..a9b39377668 100644 --- a/src/modules/color/index.ts +++ b/src/modules/color/index.ts @@ -389,7 +389,7 @@ export class ColorModule extends ModuleBase { color = Array.from({ length: 3 }, () => this.faker.number.int(255)); if (includeAlpha) { - color.push(this.faker.number.float({ precision: 0.01 })); + color.push(this.faker.number.float({ multipleOf: 0.01 })); cssFunction = 'rgba'; } @@ -470,7 +470,7 @@ export class ColorModule extends ModuleBase { }): string | number[]; cmyk(options?: { format?: ColorFormat }): string | number[] { const color: string | number[] = Array.from({ length: 4 }, () => - this.faker.number.float({ precision: 0.01 }) + this.faker.number.float({ multipleOf: 0.01 }) ); return toColorFormat(color, options?.format || 'decimal', 'cmyk'); } @@ -580,7 +580,7 @@ export class ColorModule extends ModuleBase { }): string | number[] { const hsl: number[] = [this.faker.number.int(360)]; for (let i = 0; i < (options?.includeAlpha ? 3 : 2); i++) { - hsl.push(this.faker.number.float({ precision: 0.01 })); + hsl.push(this.faker.number.float({ multipleOf: 0.01 })); } return toColorFormat( @@ -686,7 +686,7 @@ export class ColorModule extends ModuleBase { }): string | number[] { const hsl: number[] = [this.faker.number.int(360)]; for (let i = 0; i < 2; i++) { - hsl.push(this.faker.number.float({ precision: 0.01 })); + hsl.push(this.faker.number.float({ multipleOf: 0.01 })); } return toColorFormat(hsl, options?.format || 'decimal', 'hwb'); @@ -765,10 +765,10 @@ export class ColorModule extends ModuleBase { format?: ColorFormat; }): string | number[]; lab(options?: { format?: ColorFormat }): string | number[] { - const lab = [this.faker.number.float({ precision: 0.000001 })]; + const lab = [this.faker.number.float({ multipleOf: 0.000001 })]; for (let i = 0; i < 2; i++) { lab.push( - this.faker.number.float({ min: -100, max: 100, precision: 0.0001 }) + this.faker.number.float({ min: -100, max: 100, multipleOf: 0.0001 }) ); } @@ -860,9 +860,9 @@ export class ColorModule extends ModuleBase { format?: ColorFormat; }): string | number[]; lch(options?: { format?: ColorFormat }): string | number[] { - const lch = [this.faker.number.float({ precision: 0.000001 })]; + const lch = [this.faker.number.float({ multipleOf: 0.000001 })]; for (let i = 0; i < 2; i++) { - lch.push(this.faker.number.float({ max: 230, precision: 0.1 })); + lch.push(this.faker.number.float({ max: 230, multipleOf: 0.1 })); } return toColorFormat(lch, options?.format || 'decimal', 'lch'); @@ -970,7 +970,7 @@ export class ColorModule extends ModuleBase { } const color = Array.from({ length: 3 }, () => - this.faker.number.float({ precision: 0.0001 }) + this.faker.number.float({ multipleOf: 0.0001 }) ); return toColorFormat( color, diff --git a/src/modules/datatype/index.ts b/src/modules/datatype/index.ts index f46cfc0b80a..0e33217353d 100644 --- a/src/modules/datatype/index.ts +++ b/src/modules/datatype/index.ts @@ -74,7 +74,7 @@ export class DatatypeModule extends SimpleModuleBase { const { min = 0, max = min + 99999, precision = 1 } = options; - return this.faker.number.float({ min, max, precision }); + return this.faker.number.float({ min, max, multipleOf: precision }); } /** @@ -138,7 +138,7 @@ export class DatatypeModule extends SimpleModuleBase { const { min = 0, max = min + 99999, precision = 0.01 } = options; - return this.faker.number.float({ min, max, precision }); + return this.faker.number.float({ min, max, multipleOf: precision }); } /** diff --git a/src/modules/finance/index.ts b/src/modules/finance/index.ts index 576ca0dbc92..4caa77b028c 100644 --- a/src/modules/finance/index.ts +++ b/src/modules/finance/index.ts @@ -601,7 +601,7 @@ export class FinanceModule extends ModuleBase { const randValue = this.faker.number.float({ max, min, - precision: 10 ** -dec, + multipleOf: 10 ** -dec, }); const formattedString = autoFormat diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 9a681da9641..eba0b45697f 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -976,7 +976,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { const random = this.faker.number.float({ min: 0, max: total, - precision: 1e-9, + multipleOf: 1e-9, }); let current = 0; for (const { weight, value } of array) { diff --git a/src/modules/location/index.ts b/src/modules/location/index.ts index e7bde32e1a6..b741dbc9f89 100644 --- a/src/modules/location/index.ts +++ b/src/modules/location/index.ts @@ -576,7 +576,7 @@ export class LocationModule extends ModuleBase { const { max = 90, min = legacyMin, precision = legacyPrecision } = options; - return this.faker.number.float({ min, max, precision: 10 ** -precision }); + return this.faker.number.float({ min, max, multipleOf: 10 ** -precision }); } /** @@ -729,7 +729,7 @@ export class LocationModule extends ModuleBase { const { max = 180, min = legacyMin, precision = legacyPrecision } = options; - return this.faker.number.float({ max, min, precision: 10 ** -precision }); + return this.faker.number.float({ max, min, multipleOf: 10 ** -precision }); } /** @@ -1204,7 +1204,7 @@ export class LocationModule extends ModuleBase { const angleRadians = this.faker.number.float({ max: 2 * Math.PI, - precision: 0.00001, + multipleOf: 0.00001, }); // in ° radians const radiusMetric = isMetric ? radius : radius * 1.60934; // in km @@ -1212,7 +1212,7 @@ export class LocationModule extends ModuleBase { const distanceInKm = this.faker.number.float({ max: radiusMetric, - precision: 0.001, + multipleOf: 0.001, }) * errorCorrection; // in km /** From a4b88c3625ab733bbd387e6b088912150f609915 Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Sun, 10 Dec 2023 14:47:10 +0100 Subject: [PATCH 3/8] docs: rephrase JSDocs --- src/modules/number/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index b12ce1782f9..f6cce9d0c89 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -85,8 +85,8 @@ export class NumberModule extends SimpleModuleBase { } /** - * Returns a single random floating-point number for a given multipleOf or range and multipleOf. - * The lower bound is inclusive, the upper bound is exclusive, unless multipleOf is passed. + * Returns a single random floating-point number. + * The lower bound is inclusive, the upper bound is exclusive, unless `multipleOf` is passed. * * @param options Upper bound or options object. * @param options.min Lower bound for generated number. Defaults to `0.0`. @@ -94,7 +94,7 @@ export class NumberModule extends SimpleModuleBase { * @param options.precision Precision of the generated number, for example `0.01` will round to 2 decimal points. * If precision is passed, the upper bound is inclusive. * @param options.multipleOf The generated number will be a multiple of this property. - * This property can be used to achieve specific decimal points. + * This property can be used to limit the result to a specific number of decimal digits. * For example `0.01` will round to 2 decimal points. * If multipleOf is passed, the upper bound is inclusive. * From 45c63cd5f949a1b71b0697481e185fcda440f61b Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Sun, 10 Dec 2023 14:49:23 +0100 Subject: [PATCH 4/8] test: extends set range --- 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 b3d9f069b6b..3f024c0950d 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -282,7 +282,7 @@ describe('number', () => { it('provides numbers with a given multipleOf of 0.4 steps', () => { const results = [ ...new Set( - Array.from({ length: 50 }, () => + Array.from({ length: 100 }, () => faker.number.float({ min: 0, max: 1.9, From 84238d420e053625505c89fcc4291a81bfaadc56 Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Thu, 14 Dec 2023 15:08:10 +0100 Subject: [PATCH 5/8] refactor: rephrase error message --- src/modules/number/index.ts | 3 ++- test/modules/number.spec.ts | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index ce241a96977..ee9bf2462ac 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -169,7 +169,8 @@ export class NumberModule extends SimpleModuleBase { if (multipleOf !== undefined) { if (multipleOf <= 0) { - throw new FakerError(`Multiple of should be greater than 0.`); + // TODO @xDivisionByZerox: Clean up in v9.0 + throw new FakerError(`multipleOf/precision be greater than 0.`); } const factor = 1 / multipleOf; diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 25693b49b3b..907ddc84a8f 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -320,25 +320,25 @@ describe('number', () => { it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( - new FakerError('Multiple of should be greater than 0.') + new FakerError('multipleOf/precision be greater than 0.') ); }); it('throws an error for multipleOf 0', () => { expect(() => faker.number.float({ multipleOf: 0 })).toThrow( - new FakerError('Multiple of should be greater than 0.') + new FakerError('multipleOf/precision be greater than 0.') ); }); it('throws an error for negative precision', () => { expect(() => faker.number.float({ precision: -0.01 })).toThrow( - new FakerError('Multiple of should be greater than 0.') + new FakerError('multipleOf/precision be greater than 0.') ); }); it('throws an error for negative multipleOf', () => { expect(() => faker.number.float({ multipleOf: -0.01 })).toThrow( - new FakerError('Multiple of should be greater than 0.') + new FakerError('multipleOf/precision be greater than 0.') ); }); From 1266b83f9ec59d374db82d0489043c31f2338fb4 Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Thu, 14 Dec 2023 15:37:21 +0100 Subject: [PATCH 6/8] refactor: rephrase error message 2 --- src/modules/number/index.ts | 2 +- test/modules/datatype.spec.ts | 4 +++- test/modules/number.spec.ts | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts index ee9bf2462ac..59d3e5c0011 100644 --- a/src/modules/number/index.ts +++ b/src/modules/number/index.ts @@ -170,7 +170,7 @@ export class NumberModule extends SimpleModuleBase { if (multipleOf !== undefined) { if (multipleOf <= 0) { // TODO @xDivisionByZerox: Clean up in v9.0 - throw new FakerError(`multipleOf/precision be greater than 0.`); + throw new FakerError(`multipleOf/precision should be greater than 0.`); } const factor = 1 / multipleOf; diff --git a/test/modules/datatype.spec.ts b/test/modules/datatype.spec.ts index 3d65797d780..3d5afab62e9 100644 --- a/test/modules/datatype.spec.ts +++ b/test/modules/datatype.spec.ts @@ -327,7 +327,9 @@ describe('datatype', () => { it('should throw when precision is negative', () => { expect(() => { faker.datatype.float({ precision: -0.01 }); - }).toThrow(new FakerError('Precision should be greater than 0.')); + }).toThrow( + new FakerError('multipleOf/precision should be greater than 0.') + ); }); }); diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts index 907ddc84a8f..5b809da24e1 100644 --- a/test/modules/number.spec.ts +++ b/test/modules/number.spec.ts @@ -320,25 +320,25 @@ describe('number', () => { it('throws an error for precision 0', () => { expect(() => faker.number.float({ precision: 0 })).toThrow( - new FakerError('multipleOf/precision be greater than 0.') + new FakerError('multipleOf/precision should be greater than 0.') ); }); it('throws an error for multipleOf 0', () => { expect(() => faker.number.float({ multipleOf: 0 })).toThrow( - new FakerError('multipleOf/precision be greater than 0.') + new FakerError('multipleOf/precision should be greater than 0.') ); }); it('throws an error for negative precision', () => { expect(() => faker.number.float({ precision: -0.01 })).toThrow( - new FakerError('multipleOf/precision be greater than 0.') + new FakerError('multipleOf/precision should be greater than 0.') ); }); it('throws an error for negative multipleOf', () => { expect(() => faker.number.float({ multipleOf: -0.01 })).toThrow( - new FakerError('multipleOf/precision be greater than 0.') + new FakerError('multipleOf/precision should be greater than 0.') ); }); From d293b86a329e53458f698b5be0ce74b28ce83b6c Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Thu, 14 Dec 2023 15:48:40 +0100 Subject: [PATCH 7/8] test: fix failing datatype cases --- test/modules/datatype.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/modules/datatype.spec.ts b/test/modules/datatype.spec.ts index 3d5afab62e9..75f2897cf28 100644 --- a/test/modules/datatype.spec.ts +++ b/test/modules/datatype.spec.ts @@ -236,7 +236,9 @@ describe('datatype', () => { it('should throw when precision is negative', () => { expect(() => { faker.datatype.number({ precision: -0.01 }); - }).toThrow(new FakerError('Precision should be greater than 0.')); + }).toThrow( + new FakerError('multipleOf/precision should be greater than 0.') + ); }); }); From 623f9f0c68866a11cac2cbf1794735ad66688f0e Mon Sep 17 00:00:00 2001 From: xDivisionByZerox Date: Tue, 19 Dec 2023 16:16:38 +0100 Subject: [PATCH 8/8] refactor: remove custom multipleOf in weightedArrayElement --- src/modules/helpers/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 4bba45ab492..78beb94f90f 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -978,7 +978,6 @@ export class SimpleHelpersModule extends SimpleModuleBase { const random = this.faker.number.float({ min: 0, max: total, - multipleOf: 1e-9, }); let current = 0; for (const { weight, value } of array) {