Skip to content

Commit

Permalink
feat: reimplement datatype.bigInt (#791)
Browse files Browse the repository at this point in the history
Co-authored-by: ST-DDT <ST-DDT@gmx.de>
  • Loading branch information
Shinigami92 and ST-DDT authored May 23, 2022
1 parent 73db3a7 commit 1793385
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 17 deletions.
59 changes: 49 additions & 10 deletions src/modules/datatype/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,20 +261,59 @@ export class Datatype {
/**
* Returns a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type) number.
*
* @param value When provided, this method simply converts it to `BigInt` type.
* @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`.
*
* @throws When options define `max < min`.
*
* @example
* faker.datatype.bigInt() // 8507209999914928n
* faker.datatype.bigInt('156') // 156n
* faker.datatype.bigInt(30) // 30n
* faker.datatype.bigInt(3000n) // 3000n
* faker.datatype.bigInt(true) // 1n
* faker.datatype.bigInt() // 55422n
* faker.datatype.bigInt(100n) // 52n
* faker.datatype.bigInt({ min: 1000000n }) // 431433n
* faker.datatype.bigInt({ max: 100n }) // 42n
* faker.datatype.bigInt({ min: 10n, max: 100n }) // 36n
*/
bigInt(value?: string | number | bigint | boolean): bigint {
if (value === undefined) {
value = Math.floor(this.number() * 99999999999) + 10000000000;
bigInt(
options?:
| bigint
| boolean
| number
| string
| {
min?: bigint | boolean | number | string;
max?: bigint | boolean | number | string;
}
): bigint {
let min: bigint;
let max: bigint;

if (typeof options === 'object') {
min = BigInt(options.min ?? 0);
max = BigInt(options.max ?? min + BigInt(999999999999999));
} else {
min = BigInt(0);
max = BigInt(options ?? 999999999999999);
}

return BigInt(value);
if (max === min) {
return min;
}

if (max < min) {
throw new FakerError(`Max ${max} should be larger then min ${min}.`);
}

const delta = max - min;

const offset =
BigInt(
this.faker.random.numeric(delta.toString(10).length, {
allowLeadingZeros: true,
})
) %
(delta + BigInt(1));

return min + offset;
}
}
97 changes: 90 additions & 7 deletions test/datatype.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { faker } from '../src';
import { faker, FakerError } from '../src';

const seededRuns = [
{
Expand Down Expand Up @@ -69,8 +69,8 @@ const seededRuns = [
length: [79654, '2eiXX/J/*&', 86617, 60111],
},
bigInt: {
noArgs: 3745409999962546n,
value: 42n,
noArgs: 379177551410048n,
value: 37n,
},
},
},
Expand Down Expand Up @@ -141,8 +141,8 @@ const seededRuns = [
length: [56052, 21258, 54308, 3397],
},
bigInt: {
noArgs: 2620209999973798n,
value: 42n,
noArgs: 251225403255239n,
value: 25n,
},
},
},
Expand Down Expand Up @@ -213,8 +213,8 @@ const seededRuns = [
length: ['Kti5-}$_/`', 76408, 35403, 69406],
},
bigInt: {
noArgs: 9285209999907148n,
value: 42n,
noArgs: 948721906162743n,
value: 8n,
},
},
},
Expand Down Expand Up @@ -417,6 +417,19 @@ describe('datatype', () => {
const actual = faker.datatype.bigInt(42);
expect(actual).toEqual(expectations.bigInt.value);
});

it('should throw when min > max', () => {
const min = 10000n;
const max = 999n;

faker.seed(seed);

expect(() => {
faker.datatype.bigInt({ min, max });
}).toThrowError(
new FakerError(`Max ${max} should be larger then min ${min}.`)
);
});
});
});
}
Expand Down Expand Up @@ -701,6 +714,76 @@ describe('datatype', () => {
const generateBigInt = faker.datatype.bigInt();
expect(generateBigInt).toBeTypeOf('bigint');
});

it('should generate a big bigInt value with low delta', () => {
const min = 999999999n;
const max = 1000000000n;
const generateBigInt = faker.datatype.bigInt({ min, max });
expect(generateBigInt).toBeTypeOf('bigint');
expect(generateBigInt).toBeGreaterThanOrEqual(min);
expect(generateBigInt).toBeLessThanOrEqual(max);
});

it('should return a random bigint given a maximum value as BigInt', () => {
const max = 10n;
expect(faker.datatype.bigInt(max)).toBeGreaterThanOrEqual(0n);
expect(faker.datatype.bigInt(max)).toBeLessThanOrEqual(max);
});

it('should return a random bigint given a maximum value as Object', () => {
const options = { max: 10n };
expect(faker.datatype.bigInt(options)).toBeGreaterThanOrEqual(0n);
expect(faker.datatype.bigInt(options)).toBeLessThanOrEqual(
options.max
);
});

it('should return a random bigint given a maximum value of 0', () => {
const options = { max: 0n };
expect(faker.datatype.bigInt(options)).toBe(0n);
});

it('should return a random bigint given a negative bigint minimum and maximum value of 0', () => {
const options = { min: -100n, max: 0n };
expect(faker.datatype.bigInt(options)).toBeGreaterThanOrEqual(
options.min
);
expect(faker.datatype.bigInt(options)).toBeLessThanOrEqual(
options.max
);
});

it('should return a random bigint between a range', () => {
const options = { min: 22, max: 33 };
for (let i = 0; i < 100; i++) {
const randomBigInt = faker.datatype.bigInt(options);
expect(randomBigInt).toBeGreaterThanOrEqual(options.min);
expect(randomBigInt).toBeLessThanOrEqual(options.max);
}
});

it('should succeed with success-rate', () => {
const min = 0n;
const max = 1000000000000n;
const randomBigInt = faker.datatype.bigInt({ min, max });
expect(randomBigInt).toBeGreaterThanOrEqual(min);
expect(randomBigInt).toBeLessThanOrEqual(max);
});

it('should not mutate the input object', () => {
const initialMin = 1n;
const initialOtherProperty = 'hello darkness my old friend';
const input: {
min?: bigint;
max?: bigint;
otherProperty: string;
} = Object.freeze({
min: initialMin,
otherProperty: initialOtherProperty,
});

expect(() => faker.datatype.bigInt(input)).not.toThrow();
});
});
}
});
Expand Down

0 comments on commit 1793385

Please sign in to comment.