Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(number): deprecate precision in favor of multipleOf in float #2564

Merged
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/modules/color/index.ts
Expand Up @@ -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';
}

Expand Down Expand Up @@ -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');
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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 })
);
}

Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/modules/datatype/index.ts
Expand Up @@ -75,7 +75,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 });
}

/**
Expand Down Expand Up @@ -142,7 +142,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 });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/modules/finance/index.ts
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/modules/helpers/index.ts
Expand Up @@ -978,7 +978,6 @@ export class SimpleHelpersModule extends SimpleModuleBase {
const random = this.faker.number.float({
min: 0,
max: total,
precision: 1e-9,
});
let current = 0;
for (const { weight, value } of array) {
Expand Down
8 changes: 4 additions & 4 deletions src/modules/location/index.ts
Expand Up @@ -579,7 +579,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 });
}

/**
Expand Down Expand Up @@ -732,7 +732,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 });
}

/**
Expand Down Expand Up @@ -1207,15 +1207,15 @@ 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
const errorCorrection = 0.995; // avoid float issues
const distanceInKm =
this.faker.number.float({
max: radiusMetric,
precision: 0.001,
multipleOf: 0.001,
}) * errorCorrection; // in km

/**
Expand Down
41 changes: 32 additions & 9 deletions 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';

/**
Expand Down Expand Up @@ -85,14 +86,18 @@ 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.
* 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.
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
* @param options.multipleOf The generated number will be a multiple of this property.
* 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.
*
* @throws When `min` is greater than `max`.
* @throws When `precision` is negative.
Expand All @@ -102,8 +107,8 @@ export class NumberModule extends SimpleModuleBase {
* 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
*/
Expand All @@ -125,8 +130,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') {
Expand All @@ -135,7 +147,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;
Expand All @@ -145,12 +167,13 @@ 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) {
// TODO @xDivisionByZerox: Clean up in v9.0
throw new FakerError(`multipleOf/precision should be greater than 0.`);
}

const factor = 1 / precision;
const factor = 1 / multipleOf;
const int = this.int({
min: min * factor,
max: max * factor,
Expand Down
6 changes: 6 additions & 0 deletions test/modules/__snapshots__/number.spec.ts.snap
Expand Up @@ -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`;
Expand Down Expand Up @@ -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`;
Expand Down Expand Up @@ -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`;
Expand Down
8 changes: 6 additions & 2 deletions test/modules/datatype.spec.ts
Expand Up @@ -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.')
);
});
});

Expand Down Expand Up @@ -327,7 +329,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.')
);
});
});

Expand Down
64 changes: 62 additions & 2 deletions test/modules/number.spec.ts
Expand Up @@ -26,6 +26,11 @@ describe('number', () => {
min: -42,
max: 69,
precision: 0.0001,
})
.it('with min, max and multipleOf', {
min: -42,
max: 69,
multipleOf: 0.0001,
});
});

Expand Down Expand Up @@ -243,6 +248,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(
Expand All @@ -259,6 +280,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: 100 }, () =>
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({
Expand All @@ -270,15 +307,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('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 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('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 should be greater than 0.')
);
});

Expand Down