aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Mayer <[email protected]>2024-03-13 19:32:53 +0700
committerGitHub <[email protected]>2024-03-13 12:32:53 +0000
commit5ef8ef1da13e83efc61702e64d8f75b611afb4e5 (patch)
tree4b64d666c83de96725aea38deb3650ba11ca9ade
parent1169a0576ba1469d7c05be0b8fd844bde8a1af13 (diff)
downloadfaker-5ef8ef1da13e83efc61702e64d8f75b611afb4e5.tar.xz
faker-5ef8ef1da13e83efc61702e64d8f75b611afb4e5.zip
feat(number): add multipleOf to faker.number.int (#2586)
Co-authored-by: ST-DDT <[email protected]>
-rw-r--r--src/modules/number/index.ts33
-rw-r--r--test/modules/number.spec.ts84
2 files changed, 106 insertions, 11 deletions
diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts
index d8d92c59..be5e213f 100644
--- a/src/modules/number/index.ts
+++ b/src/modules/number/index.ts
@@ -23,9 +23,11 @@ export class NumberModule extends SimpleModuleBase {
* @param options Maximum value or options object.
* @param options.min Lower bound for generated number. Defaults to `0`.
* @param options.max Upper bound for generated number. Defaults to `Number.MAX_SAFE_INTEGER`.
+ * @param options.multipleOf Generated number will be a multiple of the given integer. Defaults to `1`.
*
* @throws When `min` is greater than `max`.
- * @throws When there are no integers between `min` and `max`.
+ * @throws When there are no suitable integers between `min` and `max`.
+ * @throws When `multipleOf` is not a positive integer.
*
* @see faker.string.numeric(): For generating a `string` of digits with a given length (range).
*
@@ -35,6 +37,7 @@ export class NumberModule extends SimpleModuleBase {
* faker.number.int({ min: 1000000 }) // 2900970162509863
* faker.number.int({ max: 100 }) // 42
* faker.number.int({ min: 10, max: 100 }) // 57
+ * faker.number.int({ min: 10, max: 100, multipleOf: 10 }) // 50
*
* @since 8.0.0
*/
@@ -54,24 +57,39 @@ export class NumberModule extends SimpleModuleBase {
* @default Number.MAX_SAFE_INTEGER
*/
max?: number;
+ /**
+ * Generated number will be a multiple of the given integer.
+ *
+ * @default 1
+ */
+ multipleOf?: number;
} = {}
): number {
if (typeof options === 'number') {
options = { max: options };
}
- const { min = 0, max = Number.MAX_SAFE_INTEGER } = options;
- const effectiveMin = Math.ceil(min);
- const effectiveMax = Math.floor(max);
+ const { min = 0, max = Number.MAX_SAFE_INTEGER, multipleOf = 1 } = options;
+
+ if (!Number.isInteger(multipleOf)) {
+ throw new FakerError(`multipleOf should be an integer.`);
+ }
+
+ if (multipleOf <= 0) {
+ throw new FakerError(`multipleOf should be greater than 0.`);
+ }
+
+ const effectiveMin = Math.ceil(min / multipleOf);
+ const effectiveMax = Math.floor(max / multipleOf);
if (effectiveMin === effectiveMax) {
- return effectiveMin;
+ return effectiveMin * multipleOf;
}
if (effectiveMax < effectiveMin) {
if (max >= min) {
throw new FakerError(
- `No integer value between ${min} and ${max} found.`
+ `No suitable integer value between ${min} and ${max} found.`
);
}
@@ -81,7 +99,8 @@ export class NumberModule extends SimpleModuleBase {
// @ts-expect-error: access private member field
const randomizer = this.faker._randomizer;
const real = randomizer.next();
- return Math.floor(real * (effectiveMax + 1 - effectiveMin) + effectiveMin);
+ const delta = effectiveMax - effectiveMin + 1; // +1 for inclusive max bounds and even distribution
+ return Math.floor(real * delta + effectiveMin) * multipleOf;
}
/**
diff --git a/test/modules/number.spec.ts b/test/modules/number.spec.ts
index 475af30d..f318fc5b 100644
--- a/test/modules/number.spec.ts
+++ b/test/modules/number.spec.ts
@@ -61,6 +61,82 @@ describe('number', () => {
expect(actual).lessThanOrEqual(Number.MAX_SAFE_INTEGER);
});
+ it('should return an even integer', () => {
+ const actual = faker.number.int({ multipleOf: 2 });
+
+ expect(actual).toBeTypeOf('number');
+ expect(actual).toSatisfy(Number.isInteger);
+ expect(actual).toSatisfy((x: number) => x % 2 === 0);
+ expect(actual).toBeGreaterThanOrEqual(0);
+ expect(actual).toBeLessThanOrEqual(Number.MAX_SAFE_INTEGER);
+ });
+
+ it('provides numbers with a given multipleOf of 10 with exclusive ends', () => {
+ const results = [
+ ...new Set(
+ Array.from({ length: 100 }, () =>
+ faker.number.int({
+ min: 12,
+ max: 37,
+ multipleOf: 10,
+ })
+ )
+ ),
+ ].sort();
+ expect(results).toEqual([20, 30]);
+ });
+
+ it('provides numbers with a given multipleOf of 10 with inclusive ends', () => {
+ const results = [
+ ...new Set(
+ Array.from({ length: 100 }, () =>
+ faker.number.int({
+ min: 10,
+ max: 50,
+ multipleOf: 10,
+ })
+ )
+ ),
+ ].sort();
+ expect(results).toEqual([10, 20, 30, 40, 50]);
+ });
+
+ it('throws for float multipleOf', () => {
+ const input = {
+ min: 0,
+ max: 10,
+ multipleOf: 0.1,
+ };
+
+ expect(() => faker.number.int(input)).toThrow(
+ new FakerError('multipleOf should be an integer.')
+ );
+ });
+
+ it('throws for negative multipleOf', () => {
+ const input = {
+ min: -10,
+ max: 10,
+ multipleOf: -1,
+ };
+
+ expect(() => faker.number.int(input)).toThrow(
+ new FakerError('multipleOf should be greater than 0.')
+ );
+ });
+
+ it('throws for impossible multipleOf', () => {
+ const input = {
+ min: 11,
+ max: 19,
+ multipleOf: 10,
+ };
+
+ expect(() => faker.number.int(input)).toThrow(
+ new FakerError('No suitable integer value between 11 and 19 found.')
+ );
+ });
+
it('should return a random number given a maximum value as Number', () => {
const actual = faker.number.int(10);
@@ -167,7 +243,7 @@ describe('number', () => {
expect(() => {
faker.number.int({ min: 2.1, max: 2.9 });
}).toThrow(
- new FakerError(`No integer value between 2.1 and 2.9 found.`)
+ new FakerError(`No suitable integer value between 2.1 and 2.9 found.`)
);
});
});
@@ -368,7 +444,7 @@ describe('number', () => {
expect(() => {
faker.number.binary({ min: 2.1, max: 2.9 });
}).toThrow(
- new FakerError(`No integer value between 2.1 and 2.9 found.`)
+ new FakerError(`No suitable integer value between 2.1 and 2.9 found.`)
);
});
});
@@ -419,7 +495,7 @@ describe('number', () => {
expect(() => {
faker.number.octal({ min: 2.1, max: 2.9 });
}).toThrow(
- new FakerError(`No integer value between 2.1 and 2.9 found.`)
+ new FakerError(`No suitable integer value between 2.1 and 2.9 found.`)
);
});
});
@@ -467,7 +543,7 @@ describe('number', () => {
expect(() => {
faker.number.hex({ min: 2.1, max: 2.9 });
}).toThrow(
- new FakerError(`No integer value between 2.1 and 2.9 found.`)
+ new FakerError(`No suitable integer value between 2.1 and 2.9 found.`)
);
});
});