Skip to content

Commit

Permalink
Test
Browse files Browse the repository at this point in the history
Signed-off-by: Richie Bendall <[email protected]>
  • Loading branch information
Richienb committed Apr 21, 2022
1 parent 87c40d2 commit 2326ee0
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 105 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ jobs:
fail-fast: false
matrix:
node-version:
- 14
- 12
- 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"type-fest": "^2.12.2"
},
"devDependencies": {
"dot-prop": "^7.2.0",
"tsd": "^0.20.0",
"uvu": "^0.5.3",
"xo": "^0.48.0"
Expand Down
228 changes: 125 additions & 103 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,121 +1,143 @@
import {test} from 'uvu';
import {webcrypto} from 'node:crypto';
import {hasProperty, setProperty} from 'dot-prop';
import {suite} from 'uvu';
import {is, match, throws} from 'uvu/assert'; // eslint-disable-line node/file-extension-in-import
import cryptoRandomString, {cryptoRandomStringAsync} from './index.js';

// Probabilistic, result is always less than or equal to actual set size, chance it is less is below 1e-256 for sizes up to 32656.
const generatedCharacterSetSize = (options, targetSize) => {
const set = new Set();
const length = targetSize * 640;
const string = cryptoRandomString({...options, length});

for (let i = 0; i < length; i++) {
set.add(string[i]);
}

return set.size;
};

test('main', () => {
is(cryptoRandomString({length: 0}).length, 0);
is(cryptoRandomString({length: 10}).length, 10);
is(cryptoRandomString({length: 100}).length, 100);
match(cryptoRandomString({length: 100}), /^[a-f\d]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({}, 16), 16);
});

test('async', async () => {
/* eslint-disable unicorn/no-await-expression-member */
is((await cryptoRandomStringAsync({length: 0})).length, 0);
is((await cryptoRandomStringAsync({length: 10})).length, 10);
is((await cryptoRandomStringAsync({length: 100})).length, 100);
/* eslint-enable unicorn/no-await-expression-member */
match(await cryptoRandomStringAsync({length: 100}), /^[a-f\d]*$/); // Sanity check, probabilistic
});

test('hex', () => {
is(cryptoRandomString({length: 0, type: 'hex'}).length, 0);
is(cryptoRandomString({length: 10, type: 'hex'}).length, 10);
is(cryptoRandomString({length: 100, type: 'hex'}).length, 100);
match(cryptoRandomString({length: 100, type: 'hex'}), /^[a-f\d]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({type: 'hex'}, 16), 16);
});

test('base64', () => {
is(cryptoRandomString({length: 0, type: 'base64'}).length, 0);
is(cryptoRandomString({length: 10, type: 'base64'}).length, 10);
is(cryptoRandomString({length: 100, type: 'base64'}).length, 100);
match(cryptoRandomString({length: 100, type: 'base64'}), /^[a-zA-Z\d/+]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({type: 'base64'}, 64), 64);
});

test('url-safe', () => {
is(cryptoRandomString({length: 0, type: 'url-safe'}).length, 0);
is(cryptoRandomString({length: 10, type: 'url-safe'}).length, 10);
is(cryptoRandomString({length: 100, type: 'url-safe'}).length, 100);
match(cryptoRandomString({length: 100, type: 'url-safe'}), /^[\w.~-]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({type: 'url-safe'}, 66), 66);
});
import browserCryptoRandomString, {cryptoRandomStringAsync as browserCryptoRandomStringAsync} from './browser.js';
import nodeCryptoRandomString, {cryptoRandomStringAsync as nodeCryptoRandomStringAsync} from './index.js';

if (!hasProperty(globalThis, 'crypto.getRandomValues')) {
setProperty(globalThis, 'crypto.getRandomValues', webcrypto.getRandomValues);
}

function runTests(test) {
// Probabilistic, result is always less than or equal to actual set size, chance it is less is below 1e-256 for sizes up to 32656.
const generatedCharacterSetSize = (cryptoRandomString, options, targetSize) => {
const set = new Set();
const length = targetSize * 640;
const string = cryptoRandomString({...options, length});

for (let i = 0; i < length; i++) {
set.add(string[i]);
}

return set.size;
};

test('main', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0}).length, 0);
is(cryptoRandomString({length: 10}).length, 10);
is(cryptoRandomString({length: 100}).length, 100);
match(cryptoRandomString({length: 100}), /^[a-f\d]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {}, 16), 16);
});

test('numeric', () => {
is(cryptoRandomString({length: 0, type: 'numeric'}).length, 0);
is(cryptoRandomString({length: 10, type: 'numeric'}).length, 10);
is(cryptoRandomString({length: 100, type: 'numeric'}).length, 100);
match(cryptoRandomString({length: 100, type: 'numeric'}), /^\d*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({type: 'numeric'}, 10), 10);
});
test('async', async ({cryptoRandomStringAsync}) => {
/* eslint-disable unicorn/no-await-expression-member */
is((await cryptoRandomStringAsync({length: 0})).length, 0);
is((await cryptoRandomStringAsync({length: 10})).length, 10);
is((await cryptoRandomStringAsync({length: 100})).length, 100);
/* eslint-enable unicorn/no-await-expression-member */
match(await cryptoRandomStringAsync({length: 100}), /^[a-f\d]*$/); // Sanity check, probabilistic
});

test('distinguishable', () => {
is(cryptoRandomString({length: 0, type: 'distinguishable'}).length, 0);
is(cryptoRandomString({length: 10, type: 'distinguishable'}).length, 10);
is(cryptoRandomString({length: 100, type: 'distinguishable'}).length, 100);
match(cryptoRandomString({length: 100, type: 'distinguishable'}), /^[CDEHKMPRTUWXY012458]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({type: 'distinguishable'}, 19), 19);
});
test('hex', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'hex'}).length, 0);
is(cryptoRandomString({length: 10, type: 'hex'}).length, 10);
is(cryptoRandomString({length: 100, type: 'hex'}).length, 100);
match(cryptoRandomString({length: 100, type: 'hex'}), /^[a-f\d]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {type: 'hex'}, 16), 16);
});

test('ascii-printable', () => {
is(cryptoRandomString({length: 0, type: 'ascii-printable'}).length, 0);
is(cryptoRandomString({length: 10, type: 'ascii-printable'}).length, 10);
is(cryptoRandomString({length: 100, type: 'ascii-printable'}).length, 100);
match(cryptoRandomString({length: 100, type: 'ascii-printable'}), /^[!"#$%&'()*+,-./\w:;<=>?@[\\\]^`{|}~]*$/); // Sanity check, probabilistic
});
test('base64', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'base64'}).length, 0);
is(cryptoRandomString({length: 10, type: 'base64'}).length, 10);
is(cryptoRandomString({length: 100, type: 'base64'}).length, 100);
match(cryptoRandomString({length: 100, type: 'base64'}), /^[a-zA-Z\d/+]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {type: 'base64'}, 64), 64);
});

test('alphanumeric', () => {
is(cryptoRandomString({length: 0, type: 'alphanumeric'}).length, 0);
is(cryptoRandomString({length: 10, type: 'alphanumeric'}).length, 10);
is(cryptoRandomString({length: 100, type: 'alphanumeric'}).length, 100);
match(cryptoRandomString({length: 100, type: 'alphanumeric'}), /^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({type: 'alphanumeric'}, 19), 62);
});
test('url-safe', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'url-safe'}).length, 0);
is(cryptoRandomString({length: 10, type: 'url-safe'}).length, 10);
is(cryptoRandomString({length: 100, type: 'url-safe'}).length, 100);
match(cryptoRandomString({length: 100, type: 'url-safe'}), /^[\w.~-]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {type: 'url-safe'}, 66), 66);
});

test('characters', () => {
is(cryptoRandomString({length: 0, characters: '1234'}).length, 0);
is(cryptoRandomString({length: 10, characters: '1234'}).length, 10);
is(cryptoRandomString({length: 100, characters: '1234'}).length, 100);
match(cryptoRandomString({length: 100, characters: '1234'}), /^[1-4]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize({characters: '1234'}, 4), 4);
is(generatedCharacterSetSize({characters: '0123456789'}, 10), 10);
});
test('numeric', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'numeric'}).length, 0);
is(cryptoRandomString({length: 10, type: 'numeric'}).length, 10);
is(cryptoRandomString({length: 100, type: 'numeric'}).length, 100);
match(cryptoRandomString({length: 100, type: 'numeric'}), /^\d*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {type: 'numeric'}, 10), 10);
});

test('argument errors', () => {
throws(() => {
cryptoRandomString({length: Number.POSITIVE_INFINITY});
test('distinguishable', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'distinguishable'}).length, 0);
is(cryptoRandomString({length: 10, type: 'distinguishable'}).length, 10);
is(cryptoRandomString({length: 100, type: 'distinguishable'}).length, 100);
match(cryptoRandomString({length: 100, type: 'distinguishable'}), /^[CDEHKMPRTUWXY012458]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {type: 'distinguishable'}, 19), 19);
});

throws(() => {
cryptoRandomString({length: -1});
test('ascii-printable', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'ascii-printable'}).length, 0);
is(cryptoRandomString({length: 10, type: 'ascii-printable'}).length, 10);
is(cryptoRandomString({length: 100, type: 'ascii-printable'}).length, 100);
match(cryptoRandomString({length: 100, type: 'ascii-printable'}), /^[!"#$%&'()*+,-./\w:;<=>?@[\\\]^`{|}~]*$/); // Sanity check, probabilistic
});

throws(() => {
cryptoRandomString({length: 0, type: 'hex', characters: '1234'});
test('alphanumeric', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, type: 'alphanumeric'}).length, 0);
is(cryptoRandomString({length: 10, type: 'alphanumeric'}).length, 10);
is(cryptoRandomString({length: 100, type: 'alphanumeric'}).length, 100);
match(cryptoRandomString({length: 100, type: 'alphanumeric'}), /^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {type: 'alphanumeric'}, 19), 62);
});

throws(() => {
cryptoRandomString({length: 0, characters: 42});
test('characters', ({cryptoRandomString}) => {
is(cryptoRandomString({length: 0, characters: '1234'}).length, 0);
is(cryptoRandomString({length: 10, characters: '1234'}).length, 10);
is(cryptoRandomString({length: 100, characters: '1234'}).length, 100);
match(cryptoRandomString({length: 100, characters: '1234'}), /^[1-4]*$/); // Sanity check, probabilistic
is(generatedCharacterSetSize(cryptoRandomString, {characters: '1234'}, 4), 4);
is(generatedCharacterSetSize(cryptoRandomString, {characters: '0123456789'}, 10), 10);
});

throws(() => {
cryptoRandomString({length: 0, type: 'unknown'});
test('argument errors', ({cryptoRandomString}) => {
throws(() => {
cryptoRandomString({length: Number.POSITIVE_INFINITY});
});

throws(() => {
cryptoRandomString({length: -1});
});

throws(() => {
cryptoRandomString({length: 0, type: 'hex', characters: '1234'});
});

throws(() => {
cryptoRandomString({length: 0, characters: 42});
});

throws(() => {
cryptoRandomString({length: 0, type: 'unknown'});
});
});

test.run();
}

const nodeTests = suite('Node.js', {
cryptoRandomString: nodeCryptoRandomString,
cryptoRandomStringAsync: nodeCryptoRandomStringAsync,
});

const browserTests = suite('Browser', {
cryptoRandomString: browserCryptoRandomString,
cryptoRandomStringAsync: browserCryptoRandomStringAsync,
});

test.run();
runTests(nodeTests);
runTests(browserTests);

0 comments on commit 2326ee0

Please sign in to comment.