auth0-id-generator
Version:
Generates random ids with a prefix (a la Stripe)
120 lines (96 loc) • 4.67 kB
JavaScript
var expect = require('chai').expect;
var {assert} = require('chai');
var randomInteger = require('../lib/randomInteger');
describe("randomInteger", function () {
it("should throw when passed a negative value", function () {
expect(function () {
randomInteger(-10);
}).to.throw(Error, /must be a natural number/);
});
it("should throw when passed an unsafe integer", function () {
expect(function () {
randomInteger(Number.MAX_VALUE);
}).to.throw(Error, /must be a safe integer/);
});
it("should return a random number less than the specified maximum and greater than 0", function () {
var randomInts = [];
for (var i = 0; i <= 1000; i++) {
randomInts.push(randomInteger(16));
}
randomInts.forEach(e => {
assert.isAtMost(e, 16);
assert.isAtLeast(e, 0);
});
});
it("number returned should be exclusive of maximum", function () {
var randomInts = [];
for (var i = 0; i <= 1000; i++) {
randomInts.push(randomInteger(1));
}
expect(randomInts).not.to.include.members([1]);
});
it("number returned should be inclusive of 0", function () {
var randomInts = [];
for (var i = 0; i <= 1000; i++) {
randomInts.push(randomInteger(1));
}
expect(randomInts).to.include.members([0]);
});
it("probability distribution should be highly uniform for our preferred dictionary length", function () {
/*
We want to ensure that there's a fairly uniform probability distribution
across a given range, and that the generated values are not
weighted too far from the mean value.
We use the mean of the sample to determine whether there is a bias towards
the start or end of the distribution (modulo bias would introduce a bias
towards the start of the sample).
We use the variance of the probability distribution to determine the 'spread'
of probabilities from the mean - in our case, the more uniform the better - there
should be a lower variance.
*/
var SAMPLE_SIZE = 1000000;
var SAMPLE_RANGE = 1000;
// This value originates from testing the unbiased sample-discarding
// method - the mean value fluctuates by this range.
var ALLOWED_MEAN_DIVERGENCE = (SAMPLE_RANGE / 2) * 0.002;
// The tolerable variance of the probability density - what's the biggest
// difference in probability that we want to tolerate?
// This value, like mean divergence, is derived from testing - this was the variance figure's observed
// ceiling. Changing the sample size and range will likely require a change in this variance
var ALLOWED_PDF_VARIANCE = 1.67e-7
function getMeanValue(array) {
return array.reduce((acc, val) => acc + val) / array.length;
}
this.timeout(5000);
var sample = [];
// Generate a sample of randomly generated numbers within our test range
for (var i = 0; i <= SAMPLE_SIZE; i++) {
sample.push(randomInteger(SAMPLE_RANGE));
}
// Get the mean generated value, and check that there's minimal movement from the mean value
var mean = getMeanValue(sample);
expect(mean).to.lessThan((SAMPLE_RANGE / 2) + ALLOWED_MEAN_DIVERGENCE)
expect(mean).to.greaterThan((SAMPLE_RANGE / 2) - ALLOWED_MEAN_DIVERGENCE)
// Work out the probability distribution of the randomInteger function
var variance = getMeanValue(sample.map(function (num) {
return Math.pow(num - mean, 2);
}));
var stdDev = Math.sqrt(variance)
var pdfDistribution = new Array(SAMPLE_RANGE);
// Generate a sample of probability distributions
// for each value in the range, what is the probability that it will
// be generated by our randomInteger function?
for (var i = 0; i <= SAMPLE_RANGE; i++) {
// calculate the probability density
var m = stdDev * Math.sqrt(2 * Math.PI);
var e = Math.exp(-Math.pow(i - mean, 2) / (2 * variance));
pdfDistribution.push(e / m);
}
// get the variance in probabilities of our distribution
var pdfMean = getMeanValue(pdfDistribution);
var pdfVariance = getMeanValue(pdfDistribution.map(function (num) {
return Math.pow(num - pdfMean, 2);
}));
expect(pdfVariance).is.lessThan(ALLOWED_PDF_VARIANCE)
});
});