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

feat(number): add parameter fractionDigits in float #1855

Merged
merged 30 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d1de875
refactor(datatype): legacy float implementation
xDivisionByZerox Feb 17, 2023
cb35103
refactor(number): replace precision with fractionDigits
xDivisionByZerox Feb 17, 2023
c01a82d
fix(datatype): circular deps
xDivisionByZerox Feb 17, 2023
fabc190
docs(number): fix typo in JSDocs
xDivisionByZerox Feb 17, 2023
92ec99c
test(datatype): add legacy error testcase
xDivisionByZerox Feb 17, 2023
12503b3
test(datatype): fix expectations
xDivisionByZerox Feb 17, 2023
07fc370
refactor(number): remove default for fractionalDigits
xDivisionByZerox Feb 18, 2023
efa4846
Merge remote-tracking branch 'origin/next' into refactor/float/change…
xDivisionByZerox Nov 25, 2023
83c75bd
Merge remote-tracking branch 'origin/next' into refactor/float/change…
xDivisionByZerox Jan 4, 2024
f8aafec
test: remove duplicated test case
xDivisionByZerox Jan 5, 2024
7a1f5bc
test: add case with multipleOf in combination with fractionDigits
xDivisionByZerox Jan 5, 2024
ca20b1c
refactor: more linear code flow
xDivisionByZerox Jan 5, 2024
a387b3d
revert: color module uses number fractionDigits
xDivisionByZerox Jan 5, 2024
a8bcc8e
revert: changes to datatype module
xDivisionByZerox Jan 5, 2024
b566c45
test: readd removed min, max and precision option test case
xDivisionByZerox Jan 5, 2024
3c2a839
test: add accidental removed test case
xDivisionByZerox Jan 5, 2024
2b9a74e
revert: accidental changed test name
xDivisionByZerox Jan 5, 2024
9d394bb
docs: adjust throw tags wordings
xDivisionByZerox Jan 5, 2024
89ede36
docs: rephrasing regarding excluding options properties
xDivisionByZerox Jan 5, 2024
b2af5a8
docs: reword fractionDigits description
xDivisionByZerox Jan 5, 2024
23b222c
refactor: remove default from fractionDigits
xDivisionByZerox Jan 5, 2024
a8aed91
refactor: better input validation
xDivisionByZerox Jan 10, 2024
29de20a
refactor: make input validation more linear
xDivisionByZerox Jan 10, 2024
89e8b99
refactor: rephrase error messages
xDivisionByZerox Jan 11, 2024
8557952
chore: fix minor issues
ST-DDT Jan 14, 2024
ee23583
Merge branch 'next' into refactor/float/change-precision-to-fraction-…
ST-DDT Jan 14, 2024
fe99819
chore: use consistent nullish check
ST-DDT Jan 14, 2024
e1d13a5
chore: apply suggestions
ST-DDT Jan 18, 2024
35c8996
Merge branch 'next' into refactor/float/change-precision-to-fraction-…
ST-DDT Jan 18, 2024
0e9171c
Update test/modules/datatype.spec.ts
ST-DDT Jan 18, 2024
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
2 changes: 1 addition & 1 deletion src/modules/finance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ export class FinanceModule extends ModuleBase {
const randValue = this.faker.number.float({
max,
min,
multipleOf: 10 ** -dec,
fractionDigits: dec,
});

const formattedString = autoFormat
Expand Down
8 changes: 4 additions & 4 deletions src/modules/location/index.ts
Original file line number Diff line number Diff line change
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, multipleOf: 10 ** -precision });
return this.faker.number.float({ min, max, fractionDigits: 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, multipleOf: 10 ** -precision });
return this.faker.number.float({ max, min, fractionDigits: precision });
}

/**
Expand Down Expand Up @@ -1207,15 +1207,15 @@ export class LocationModule extends ModuleBase {

const angleRadians = this.faker.number.float({
max: 2 * Math.PI,
multipleOf: 0.00001,
fractionDigits: 5,
}); // 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,
multipleOf: 0.001,
fractionDigits: 3,
}) * errorCorrection; // in km

/**
Expand Down
48 changes: 42 additions & 6 deletions src/modules/number/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,25 @@ export class NumberModule extends SimpleModuleBase {
* @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.
* If multipleOf is passed, the upper bound is inclusive and the `fractionDigits` option has to be excluded.
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
* @param options.fractionDigits The maximum number of digits to appear after the decimal point.
* This parameter has to be excluded if `multipleOf` is provided.
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
*
* @throws When `min` is greater than `max`.
* @throws When `precision` is negative.
* @throws When `multipleOf` is negative.
* @throws When `fractionDigits` is negative.
* @throws When `fractionDigits` and `multipleOf` is passed in the same options object.
*
* @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({ multipleOf: 0.25 }) // 3.75
* faker.number.float({ min: 10, max: 100, multipleOf: 0.001 }) // 35.415
* faker.number.float({ fractionDigits: 1 }) // 0.9
* faker.number.float({ min: 10, max: 100, multipleOf: 0.02 }) // 35.42
* faker.number.float({ min: 10, max: 100, fractionDigits: 3 }) // 65.716
*
* @since 8.0.0
*/
Expand All @@ -129,6 +136,10 @@ export class NumberModule extends SimpleModuleBase {
*/
max?: number;
/**
* The number of digits to appear after the decimal point.
*/
fractionDigits?: number;
/*
* Precision of the generated number.
*
* @deprecated Use `multipleOf` instead.
Expand All @@ -147,10 +158,17 @@ export class NumberModule extends SimpleModuleBase {
};
}

// eslint-disable-next-line deprecation/deprecation
const { min = 0, max = 1, precision, multipleOf = precision } = options;
const {
min = 0,
max = 1,
fractionDigits,
precision,
multipleOf: originalMultipleOf = precision,
multipleOf = precision ??
(fractionDigits == null ? undefined : 10 ** -fractionDigits),
} = options;

if (precision !== undefined) {
if (precision != null) {
deprecated({
deprecated: 'faker.number.float({ precision })',
proposed: 'faker.number.float({ multipleOf })',
Expand All @@ -167,7 +185,25 @@ export class NumberModule extends SimpleModuleBase {
throw new FakerError(`Max ${max} should be greater than min ${min}.`);
}

if (multipleOf !== undefined) {
if (fractionDigits != null) {
if (originalMultipleOf != null) {
throw new FakerError(
'multipleOf and fractionDigits cannot be set at the same time.'
);
}

if (!Number.isInteger(fractionDigits)) {
throw new FakerError('fractionDigits should be an integer.');
}

if (fractionDigits < 0) {
throw new FakerError(
'fractionDigits should be greater than or equal to 0.'
);
}
}

if (multipleOf != null) {
if (multipleOf <= 0) {
// TODO @xDivisionByZerox: Clean up in v9.0
throw new FakerError(`multipleOf/precision should be greater than 0.`);
Expand Down
6 changes: 6 additions & 0 deletions test/modules/__snapshots__/number.spec.ts.snap
Original file line number Diff line number Diff line change
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 fractionDigits 1`] = `-0.4261`;

exports[`number > 42 > float > with min, max and multipleOf 1`] = `-0.4261`;

exports[`number > 42 > float > with min, max and precision 1`] = `-0.4261`;
Expand Down Expand Up @@ -76,6 +78,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 fractionDigits 1`] = `61.0658`;

exports[`number > 1211 > float > with min, max and multipleOf 1`] = `61.0658`;

exports[`number > 1211 > float > with min, max and precision 1`] = `61.0658`;
Expand Down Expand Up @@ -126,6 +130,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 fractionDigits 1`] = `-12.9153`;

exports[`number > 1337 > float > with min, max and multipleOf 1`] = `-12.9153`;

exports[`number > 1337 > float > with min, max and precision 1`] = `-12.9153`;
Expand Down
24 changes: 13 additions & 11 deletions test/modules/datatype.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,22 +316,24 @@ describe('datatype', () => {
});

it('should throw when min > max', () => {
const min = 10;
const max = 9;
const min = 2;
const max = 1;
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved

expect(() => {
faker.datatype.number({ min, max });
}).toThrow(
new FakerError(`Max ${max} should be greater than min ${min}.`)
);
faker.datatype.float({ min, max });
}).toThrowError(`Max ${max} should be greater than min ${min}.`);
});
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved

it('should throw when precision is negative', () => {
it('should throw when precision <= 0', () => {
const min = 1;
const max = 2;

expect(() => {
faker.datatype.float({ precision: -0.01 });
}).toThrow(
new FakerError('multipleOf/precision should be greater than 0.')
);
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
faker.datatype.float({ min, max, precision: 0 });
}).toThrowError('multipleOf/precision should be greater than 0.');
expect(() => {
faker.datatype.float({ min, max, precision: -1 });
}).toThrowError('multipleOf/precision should be greater than 0.');
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
});
});

Expand Down
43 changes: 43 additions & 0 deletions test/modules/number.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ describe('number', () => {
max: 69,
precision: 0.0001,
})
.it('with min, max and fractionDigits', {
min: -42,
max: 69,
fractionDigits: 4,
})
.it('with min, max and multipleOf', {
min: -42,
max: 69,
Expand Down Expand Up @@ -281,6 +286,44 @@ describe('number', () => {
expect(results).toEqual([0, 0.4, 0.8, 1.2, 1.6]);
});

it('provides numbers with an exact fractional digits', () => {
for (let i = 0; i < 100; i++) {
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
const actual = faker.number.float({
min: 0.5,
max: 0.99,
fractionDigits: 2,
});
expect(actual).toBe(Number(actual.toFixed(2)));
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
}
});

it('throws an error if fractionDigits and multipleOf is provided at the same time', () => {
expect(() =>
faker.number.float({
min: 0,
max: 10,
multipleOf: 0.25,
fractionDigits: 6,
})
).toThrow(
new FakerError(
'multipleOf and fractionDigits cannot be set at the same time.'
)
);
});

it('throws an error for non integer fractionDigits numbers', () => {
expect(() => faker.number.float({ fractionDigits: 1.337 })).toThrow(
new FakerError('fractionDigits should be an integer.')
);
});

it('throws an error for negative fractionDigits', () => {
expect(() => faker.number.float({ fractionDigits: -2 })).toThrow(
new FakerError('fractionDigits should be greater than or equal to 0.')
);
});

it('provides numbers with a given precision of 0.2', () => {
const results = [
...new Set(
Expand Down