From 2b84b3389a2719e0f365055990a51673acd07ac9 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Tue, 24 Jan 2023 23:00:07 +0100 Subject: [PATCH] fix(helpers): uniform distribution in helpers.arrayElements (#1770) --- src/modules/helpers/index.ts | 3 +- test/__snapshots__/helpers.spec.ts.snap | 10 +++---- test/helpers.spec.ts | 39 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 8d10ced9639..8492a096ee4 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -594,8 +594,9 @@ export class HelpersModule { let temp: T; let index: number; + // Shuffle the last `count` elements of the array while (i-- > min) { - index = Math.floor((i + 1) * this.faker.number.float({ max: 0.99 })); + index = this.faker.number.int(i); temp = arrayCopy[index]; arrayCopy[index] = arrayCopy[i]; arrayCopy[i] = temp; diff --git a/test/__snapshots__/helpers.spec.ts.snap b/test/__snapshots__/helpers.spec.ts.snap index c5714ea91a3..ca5ae30a031 100644 --- a/test/__snapshots__/helpers.spec.ts.snap +++ b/test/__snapshots__/helpers.spec.ts.snap @@ -195,15 +195,15 @@ exports[`helpers > 1211 > arrayElements > noArgs 1`] = ` exports[`helpers > 1211 > arrayElements > with array 1`] = ` [ - "r", + "d", "o", - "l", + "r", "!", "l", - "d", - "W", "H", + "W", "e", + "l", "o", "l", " ", @@ -213,7 +213,7 @@ exports[`helpers > 1211 > arrayElements > with array 1`] = ` exports[`helpers > 1211 > arrayElements > with array and count 1`] = ` [ "r", - "o", + " ", "!", ] `; diff --git a/test/helpers.spec.ts b/test/helpers.spec.ts index 6ef7c374eff..0e75e10fa80 100644 --- a/test/helpers.spec.ts +++ b/test/helpers.spec.ts @@ -292,6 +292,45 @@ describe('helpers', () => { expect(result).toHaveLength(0); }); + + it('should return the only element in the array when there is only 1', () => { + const testArray = ['hello']; + const actual = faker.helpers.arrayElements(testArray); + expect(actual).toEqual(testArray); + }); + + it('should return each element with a somewhat equal distribution with 2 elements', () => { + const input = Array.from({ length: 2 }, (_, i) => i); + const occurrences = Array.from({ length: 2 }, () => 0); + + for (let i = 0; i < 1000; i++) { + const [result] = faker.helpers.arrayElements(input, 1); + occurrences[result]++; + } + + for (const occurrence of occurrences) { + expect(occurrence).toBeGreaterThanOrEqual(400); + expect(occurrence).toBeLessThanOrEqual(600); + } + }); + + it.each([10, 100, 1000])( + 'should return each element with a somewhat equal distribution with %s elements', + (length) => { + const input = Array.from({ length }, (_, i) => i % 10); + const occurrences = Array.from({ length: 10 }, () => 0); + + for (let i = 0; i < 1000; i++) { + const [result] = faker.helpers.arrayElements(input, 1); + occurrences[result]++; + } + + for (const occurrence of occurrences) { + expect(occurrence).toBeGreaterThanOrEqual(70); + expect(occurrence).toBeLessThanOrEqual(130); + } + } + ); }); describe('slugify()', () => {