@alwatr/random
Version:
A lightweight utility library for generating random numbers, strings, UUIDs and more
378 lines (317 loc) • 11.3 kB
JavaScript
import {
randNumber,
randInteger,
randFloat,
randString,
randStep,
randShuffle,
randPick,
randBoolean,
randColor,
randUuid,
randArray,
bytesToHex,
} from '@alwatr/random';
describe('@alwatr/random', () => {
describe('number generation', () => {
test('randNumber() returns a number between 0 and 1', () => {
const value = randNumber();
expect(typeof value).toBe('number');
expect(value).toBeGreaterThanOrEqual(0);
expect(value).toBeLessThan(1);
});
});
describe('integer generation', () => {
test('randInteger() returns an integer within the specified range', () => {
const min = 5;
const max = 10;
for (let i = 0; i < 100; i++) {
const value = randInteger(min, max);
expect(Number.isInteger(value)).toBe(true);
expect(value).toBeGreaterThanOrEqual(min);
expect(value).toBeLessThanOrEqual(max);
}
});
test('randInteger() with min equal to max', () => {
const value = randInteger(5, 5);
expect(value).toBe(5);
});
test('randInteger() with negative numbers', () => {
const min = -10;
const max = -5;
for (let i = 0; i < 100; i++) {
const value = randInteger(min, max);
expect(Number.isInteger(value)).toBe(true);
expect(value).toBeGreaterThanOrEqual(min);
expect(value).toBeLessThanOrEqual(max);
}
});
});
describe('float generation', () => {
test('randFloat() returns a float within the specified range', () => {
const min = 5;
const max = 10;
for (let i = 0; i < 100; i++) {
const value = randFloat(min, max);
expect(typeof value).toBe('number');
expect(value).toBeGreaterThanOrEqual(min);
expect(value).toBeLessThan(max);
}
});
test('randFloat() with min equal to max', () => {
const value = randFloat(5, 5);
expect(value).toBe(5);
});
test('randFloat() with negative numbers', () => {
const min = -10;
const max = -5;
for (let i = 0; i < 100; i++) {
const value = randFloat(min, max);
expect(typeof value).toBe('number');
expect(value).toBeGreaterThanOrEqual(min);
expect(value).toBeLessThan(max);
}
});
});
describe('string generation', () => {
test('randString() with fixed length', () => {
const length = 8;
const str = randString(length);
expect(str.length).toBe(length);
expect(typeof str).toBe('string');
});
test('randString() with variable length', () => {
const min = 5;
const max = 10;
const str = randString(min, max);
expect(str.length).toBeGreaterThanOrEqual(min);
expect(str.length).toBeLessThanOrEqual(max);
});
test('randString() with min equal to max', () => {
const length = 5;
const str = randString(length, length);
expect(str.length).toBe(length);
});
test('randString() returns empty string when min is 0', () => {
const str = randString(0);
expect(str.length).toBe(0);
});
test('randString() with custom character set', () => {
const length = 10;
const chars = '01'; // Binary characters
const str = randString(length, undefined, chars);
expect(str.length).toBe(length);
// Verify that only characters from the custom set are used
expect(str.split('').every(char => chars.includes(char))).toBe(true);
});
test('randString() with custom character set and variable length', () => {
const min = 5;
const max = 10;
const chars = 'ABC123';
const str = randString(min, max, chars);
expect(str.length).toBeGreaterThanOrEqual(min);
expect(str.length).toBeLessThanOrEqual(max);
// Verify that only characters from the custom set are used
expect(str.split('').every(char => chars.includes(char))).toBe(true);
});
test('randString() optimizes for short strings', () => {
// This test just ensures the code path for short strings works
const str = randString(10);
expect(str.length).toBe(10);
});
test('randString() handles longer strings with array join', () => {
// This test ensures the code path for longer strings works
const str = randString(20);
expect(str.length).toBe(20);
});
});
describe('step generation', () => {
test('randStep() returns a value with the correct step', () => {
const min = 0;
const max = 10;
const step = 2;
const validValues = [0, 2, 4, 6, 8, 10];
for (let i = 0; i < 100; i++) {
const value = randStep(min, max, step);
expect(validValues).toContain(value);
}
});
test('randStep() with min equal to max', () => {
const value = randStep(5, 5, 2);
expect(value).toBe(5);
});
test('randStep() with step 0', () => {
const value = randStep(5, 10, 0);
expect(value).toBe(5);
});
test('randStep() with negative numbers', () => {
const min = -10;
const max = -2;
const step = 2;
const validValues = [-10, -8, -6, -4, -2];
for (let i = 0; i < 100; i++) {
const value = randStep(min, max, step);
expect(validValues).toContain(value);
}
});
});
describe('array manipulation', () => {
test('randShuffle() shuffles an array', () => {
const original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const shuffled = [...original];
randShuffle(shuffled);
// Test the arrays are not identical (with very high probability)
// Note: there's a tiny chance this could fail even if randShuffle works correctly
let isDifferent = false;
for (let i = 0; i < original.length; i++) {
if (original[i] !== shuffled[i]) {
isDifferent = true;
break;
}
}
expect(isDifferent).toBe(true);
// Make sure it contains all the same elements
expect(original.sort()).toEqual(shuffled.sort());
});
test('randShuffle() does not modify an empty array', () => {
const original = [];
const shuffled = [...original];
randShuffle(shuffled);
expect(shuffled).toEqual(original);
});
test('randShuffle() returns the same array reference for chaining', () => {
const array = [1, 2, 3, 4, 5];
const result = randShuffle(array);
expect(result).toBe(array); // Same reference
});
test('randPick() selects a valid array element', () => {
const array = [1, 2, 3, 4, 5];
for (let i = 0; i < 100; i++) {
expect(array).toContain(randPick(array));
}
});
test('randPick() throws on empty array', () => {
expect(() => randPick([])).toThrow();
});
});
describe('uuid generation', () => {
test('randUuid() returns a valid UUID string', () => {
const uuid = randUuid();
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
expect(uuidRegex.test(uuid)).toBe(true);
});
test('randUuid() creates properly formatted UUID v4', () => {
const uuid = randUuid();
const parts = uuid.split('-');
expect(parts.length).toBe(5);
expect(parts[0].length).toBe(8);
expect(parts[1].length).toBe(4);
expect(parts[2].length).toBe(4);
expect(parts[3].length).toBe(4);
expect(parts[4].length).toBe(12);
// Version 4 UUID has the 13th character as '4'
expect(uuid.charAt(14)).toBe('4');
// Variant should be binary 10xx (8, 9, a, or b)
const variantChar = uuid.charAt(19);
expect(['8', '9', 'a', 'b', 'A', 'B']).toContain(variantChar);
});
});
describe('boolean generation', () => {
test('randBoolean() returns a boolean', () => {
expect(typeof randBoolean()).toBe('boolean');
});
test('randBoolean() with probability 0', () => {
let trueCount = 0;
const samples = 20;
for (let i = 0; i < samples; i++) {
if (randBoolean(0)) trueCount++;
}
expect(trueCount).toBe(0);
});
test('randBoolean() with probability 1', () => {
let trueCount = 0;
const samples = 20;
for (let i = 0; i < samples; i++) {
if (randBoolean(1)) trueCount++;
}
expect(trueCount).toBe(samples);
});
test('randBoolean() with default probability', () => {
// This just checks that the function runs with default parameters
// Statistical testing would be unreliable in unit tests
const result = randBoolean();
expect(typeof result).toBe('boolean');
});
});
describe('color generation', () => {
test('randColor() returns a valid hex color', () => {
const color = randColor();
const colorRegex = /^#[0-9a-f]{6}$/i;
expect(colorRegex.test(color)).toBe(true);
});
});
describe('random array filling', () => {
test('randArray() fills typed array with random values', () => {
const array = new Uint8Array(10);
const emptyArray = new Uint8Array(10);
randArray(array);
// Extremely unlikely that a randomly filled array would equal an empty one
expect(array).not.toEqual(emptyArray);
});
test('randArray() fills different typed arrays', () => {
const array8 = new Uint8Array(10);
const array16 = new Uint16Array(5);
const array32 = new Uint32Array(2);
randArray(array8);
randArray(array16);
randArray(array32);
expect(array8.every(Number.isInteger)).toBe(true);
expect(array16.every(Number.isInteger)).toBe(true);
expect(array32.every(Number.isInteger)).toBe(true);
});
test('randArray() respects min and max parameters', () => {
const array = new Uint8Array(100);
const min = 10;
const max = 20;
randArray(array, min, max);
// Check that all values are in range
for (const value of array) {
expect(value).toBeGreaterThanOrEqual(min);
expect(value).toBeLessThanOrEqual(max);
}
});
test('randArray() returns the same array for chaining', () => {
const array = new Uint8Array(10);
const result = randArray(array);
expect(result).toBe(array); // Same reference
});
test('randArray() works with regular number arrays', () => {
const array = new Array(5);
randArray(array, -10, 10);
expect(array.length).toBe(5);
for (const value of array) {
expect(typeof value).toBe('number');
expect(value).toBeGreaterThanOrEqual(-10);
expect(value).toBeLessThanOrEqual(10);
}
});
});
describe('bytesToHex', () => {
test('converts Uint8Array to hex string', () => {
const bytes = new Uint8Array([10, 255, 0, 16]);
expect(bytesToHex(bytes)).toBe('0aff0010');
});
test('converts number array to hex string', () => {
const array = [171, 205, 3];
expect(bytesToHex(array)).toBe('abcd03');
});
test('handles empty array', () => {
expect(bytesToHex([])).toBe('');
expect(bytesToHex(new Uint8Array(0))).toBe('');
});
test('pads single-digit hex values with leading zero', () => {
const bytes = new Uint8Array([0, 1, 2, 3, 10, 15]);
expect(bytesToHex(bytes)).toBe('000102030a0f');
});
});
});