aboutsummaryrefslogtreecommitdiff
path: root/test/internal
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2023-12-01 18:10:05 +0100
committerGitHub <[email protected]>2023-12-01 17:10:05 +0000
commit2eca5bc06c5f53efe9fe495577cd930620453794 (patch)
tree6a4efd5c42e7bb08261e7b11eb70f58a90fab6b3 /test/internal
parent5e0f4f7dd1497e80c2e725a7bee3887abaab25a7 (diff)
downloadfaker-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.snap13
-rw-r--r--test/internal/mersenne-test-utils.ts17
-rw-r--r--test/internal/mersenne.spec.ts136
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);
+ });
+ });
+ });
+});