diff options
| author | ST-DDT <[email protected]> | 2023-12-01 18:10:05 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-12-01 17:10:05 +0000 |
| commit | 2eca5bc06c5f53efe9fe495577cd930620453794 (patch) | |
| tree | 6a4efd5c42e7bb08261e7b11eb70f58a90fab6b3 /test/internal | |
| parent | 5e0f4f7dd1497e80c2e725a7bee3887abaab25a7 (diff) | |
| download | faker-2eca5bc06c5f53efe9fe495577cd930620453794.tar.xz faker-2eca5bc06c5f53efe9fe495577cd930620453794.zip | |
test(mersenne): add tests for value ranges (#2470)
Diffstat (limited to 'test/internal')
| -rw-r--r-- | test/internal/__snapshots__/mersenne.spec.ts.snap | 13 | ||||
| -rw-r--r-- | test/internal/mersenne-test-utils.ts | 17 | ||||
| -rw-r--r-- | test/internal/mersenne.spec.ts | 136 |
3 files changed, 166 insertions, 0 deletions
diff --git a/test/internal/__snapshots__/mersenne.spec.ts.snap b/test/internal/__snapshots__/mersenne.spec.ts.snap new file mode 100644 index 00000000..c55b1152 --- /dev/null +++ b/test/internal/__snapshots__/mersenne.spec.ts.snap @@ -0,0 +1,13 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`generateMersenne32Randomizer() > seed: [42,1,2] > should return deterministic value for next() 1`] = `0.8562037434894592`; + +exports[`generateMersenne32Randomizer() > seed: [1211,1,2] > should return deterministic value for next() 1`] = `0.8916433283593506`; + +exports[`generateMersenne32Randomizer() > seed: [1337,1,2] > should return deterministic value for next() 1`] = `0.17990487208589911`; + +exports[`generateMersenne32Randomizer() > seed: 42 > should return deterministic value for next() 1`] = `0.37454011430963874`; + +exports[`generateMersenne32Randomizer() > seed: 1211 > should return deterministic value for next() 1`] = `0.9285201537422836`; + +exports[`generateMersenne32Randomizer() > seed: 1337 > should return deterministic value for next() 1`] = `0.2620246761944145`; diff --git a/test/internal/mersenne-test-utils.ts b/test/internal/mersenne-test-utils.ts new file mode 100644 index 00000000..ee7a43da --- /dev/null +++ b/test/internal/mersenne-test-utils.ts @@ -0,0 +1,17 @@ +// Moved to a separate file to avoid importing the tests + +/** + * The maximum value that can be returned by `MersenneTwister19937.genrandReal2()`. + * This is the max possible value with 32 bits of precision that is less than 1. + */ +export const TWISTER_32CO_MAX_VALUE = 0.9999999997671694; +/** + * The maximum value that can be returned by `MersenneTwister19937.genrandRes53()`. + * This is the max possible value with 53 bits of precision that is less than 1. + */ +export const TWISTER_53CO_MAX_VALUE = 0.9999999999999999; +// Re-exported because the value might change in the future +/** + * The maximum value that can be returned by `next()`. + */ +export const MERSENNE_MAX_VALUE = TWISTER_32CO_MAX_VALUE; diff --git a/test/internal/mersenne.spec.ts b/test/internal/mersenne.spec.ts new file mode 100644 index 00000000..bbee0502 --- /dev/null +++ b/test/internal/mersenne.spec.ts @@ -0,0 +1,136 @@ +import { beforeAll, beforeEach, describe, expect, it } from 'vitest'; +import { + generateMersenne32Randomizer, + MersenneTwister19937, +} from '../../src/internal/mersenne'; +import type { Randomizer } from '../../src/randomizer'; +import { seededRuns } from '../support/seeded-runs'; +import { times } from '../support/times'; +import { + MERSENNE_MAX_VALUE, + TWISTER_32CO_MAX_VALUE, + TWISTER_53CO_MAX_VALUE, +} from './mersenne-test-utils'; + +const NON_SEEDED_BASED_RUN = 25; + +function newTwister( + seed: number = Math.random() * Number.MAX_SAFE_INTEGER +): MersenneTwister19937 { + const twister = new MersenneTwister19937(); + twister.initGenrand(seed); + return twister; +} + +describe('MersenneTwister19937', () => { + describe('genrandInt32()', () => { + it('should be able to return 0', () => { + const twister = newTwister(257678572); + + // There is no single value seed that can produce 0 in the first call + for (let i = 0; i < 5; i++) { + twister.genrandInt32(); + } + + const actual = twister.genrandInt32(); + expect(actual).toBe(0); + }); + + it('should be able to return 2^32-1', () => { + const twister = newTwister(2855577693); + const actual = twister.genrandInt32(); + expect(actual).toBe(2 ** 32 - 1); + }); + }); + + describe('genrandReal2()', () => { + it('should be able to return 0', () => { + const twister = newTwister(); + // shortcut to return minimal value + // the test above shows that it is possible to return 0 + twister.genrandInt32 = () => 0; + const actual = twister.genrandReal2(); + expect(actual).toBe(0); + }); + + it('should be able to return almost 1', () => { + const twister = newTwister(); + // shortcut to return maximal value + // the test above shows that it is possible to return 2^32-1 + twister.genrandInt32 = () => 2 ** 32 - 1; + const actual = twister.genrandReal2(); + expect(actual).toBe(TWISTER_32CO_MAX_VALUE); + }); + }); + + describe('genrandRes53()', () => { + it('should be able to return 0', () => { + const twister = newTwister(); + // shortcut to return minimal value + // the test above shows that it is possible to return 0 + twister.genrandInt32 = () => 0; + const actual = twister.genrandRes53(); + expect(actual).toBe(0); + }); + + it('should be able to return almost 1', () => { + const twister = newTwister(); + // shortcut to return maximal value + // the test above shows that it is possible to return 2^32-1 + twister.genrandInt32 = () => 2 ** 32 - 1; + const actual = twister.genrandRes53(); + expect(actual).toBe(TWISTER_53CO_MAX_VALUE); + }); + }); +}); + +describe('generateMersenne32Randomizer()', () => { + const randomizer: Randomizer = generateMersenne32Randomizer(); + + it('should return a result matching the interface', () => { + expect(randomizer).toBeDefined(); + expect(randomizer).toBeTypeOf('object'); + expect(randomizer.next).toBeTypeOf('function'); + expect(randomizer.seed).toBeTypeOf('function'); + }); + + describe.each( + [...seededRuns, ...seededRuns.map((v) => [v, 1, 2])].map((v) => [v]) + )('seed: %j', (seed) => { + beforeEach(() => { + randomizer.seed(seed); + }); + + it('should return deterministic value for next()', () => { + const actual = randomizer.next(); + + expect(actual).toMatchSnapshot(); + }); + }); + + function randomSeed(): number { + return Math.ceil(Math.random() * 1_000_000_000); + } + + // Create and log-back the seed for debug purposes + describe.each( + times(NON_SEEDED_BASED_RUN).flatMap(() => [ + [randomSeed()], + [[randomSeed(), randomSeed()]], + ]) + )('random seeded tests %j', (seed) => { + beforeAll(() => { + randomizer.seed(seed); + }); + + describe('next', () => { + it('should return random number from interval [0, 1)', () => { + const actual = randomizer.next(); + + expect(actual).toBeGreaterThanOrEqual(0); + expect(actual).toBeLessThanOrEqual(MERSENNE_MAX_VALUE); + expect(actual).toBeLessThan(1); + }); + }); + }); +}); |
