diff --git a/README.md b/README.md index d60b334f7fd92594664db56cba013cac0a68d2f6..de3406fd2b37fe6aae65ce891c6d95e5b3728690 100644 --- a/README.md +++ b/README.md @@ -415,6 +415,7 @@ You may define following options for `jsf` that alter its behavior: - `defaultInvalidTypeProduct`: - default value generated for a schema with invalid type (works only if `failOnInvalidTypes` is set to `false`) - `maxItems`: number - Configure a maximum amount of items to generate in an array. This will override the maximum items found inside a JSON Schema. - `maxLength`: number - Configure a maximum length to allow generating strings for. This will override the maximum length found inside a JSON Schema. +- `random`: Function - a replacement for `Math.random` to support pseudorandom number generation. Set options just as below: diff --git a/package.json b/package.json index e6b8d6954d119582c9aca3b116b054be8e06749c..e4fce3614271b6a58169e516b181f8fa9b60ec68 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "jasmine-node": "2.0.0-beta4", "jayschema": "^0.3.1", "lodash.template": "^4.4.0", + "seedrandom": "^2.4.3", "semver": "^5.3.0", "tslint": "^4.0.2", "tv4": "^1.2.7", diff --git a/spec/schema/core/option/random.js b/spec/schema/core/option/random.js new file mode 100644 index 0000000000000000000000000000000000000000..d53558ac0f372d382957bcfec7e68358f079f1c2 --- /dev/null +++ b/spec/schema/core/option/random.js @@ -0,0 +1,9 @@ +const seedrandom = require('seedrandom'); + +module.exports = { + register: function(jsf) { + return jsf.option({ + random: seedrandom('some seed') + }); + } +}; diff --git a/spec/schema/core/option/random.json b/spec/schema/core/option/random.json new file mode 100644 index 0000000000000000000000000000000000000000..6670a3013b1663252db1b9176da625f189bfcca8 --- /dev/null +++ b/spec/schema/core/option/random.json @@ -0,0 +1,35 @@ +[ + { + "description": "random option", + "tests": [ + { + "description": "should allow pseudorandom value generation", + "schema": { + "type": "object", + "properties": { + "a": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "b": { + "type": "string" + }, + "c": { + "pattern": "^[a-z]{2}[0-9]{3}$" + } + }, + "required": ["a", "b", "c"] + }, + "valid": true, + "equal": { + "a": 39, + "b": "dolore et qui ex", + "c": "hv837" + }, + "repeat": 1, + "require": "core/option/random" + } + ] + } +] diff --git a/ts/class/Container.ts b/ts/class/Container.ts index af41152ebf4eed7ed1a59b2d0d4d6002270f6847..58bfb96b354ad5d91353053af849dda07cecee8b 100644 --- a/ts/class/Container.ts +++ b/ts/class/Container.ts @@ -4,6 +4,10 @@ import option = require('../api/option'); // set maximum default, see #193 RandExp.prototype.max = 10; +// same implementation as the original except using our random +RandExp.prototype.randInt = (a, b) => + a + Math.floor(option('random')() * (1 + b - a)); + type Dependency = any; /** diff --git a/ts/class/OptionRegistry.ts b/ts/class/OptionRegistry.ts index e1dd9f8727e79739b75ace57a00ffb364b9c311c..ee2ade10a27999f5761672607e0078d33d760f12 100644 --- a/ts/class/OptionRegistry.ts +++ b/ts/class/OptionRegistry.ts @@ -1,6 +1,6 @@ import Registry = require('./Registry'); -type Option = boolean|number; +type Option = boolean|number|Function; /** * This class defines a registry for custom formats used within JSF. @@ -18,6 +18,7 @@ class OptionRegistry extends Registry<Option> { this.data['defaultMinItems'] = 0; this.data['defaultRandExpMax'] = 10; this.data['alwaysFakeOptionals'] = false; + this.data['random'] = Math.random; } } diff --git a/ts/core/random.ts b/ts/core/random.ts index 7332f3faf6fab2ac66bcf8e8e631598b2dc1d836..e67dbe3f52bc30b737f1d32c37309ebf39c3b464 100644 --- a/ts/core/random.ts +++ b/ts/core/random.ts @@ -1,5 +1,7 @@ /// <reference path="../index.d.ts" /> +var option = require('../api/option'); + /** * Returns random element of a collection * @@ -7,7 +9,7 @@ * @returns {T} */ function pick<T>(collection: T[]): T { - return collection[Math.floor(Math.random() * collection.length)]; + return collection[Math.floor(option('random')() * collection.length)]; } /** @@ -23,7 +25,7 @@ function shuffle<T>(collection: T[]): T[] { length: number = collection.length; for (; length > 0;) { - key = Math.floor(Math.random() * length); + key = Math.floor(option('random')() * length); // swap tmp = copy[--length]; copy[length] = copy[key]; @@ -48,7 +50,7 @@ var MIN_NUMBER = -100, * @see http://stackoverflow.com/a/1527820/769384 */ function getRandomInt(min: number, max: number): number { - return Math.floor(Math.random() * (max - min + 1)) + min; + return Math.floor(option('random')() * (max - min + 1)) + min; } /** diff --git a/ts/generators/boolean.ts b/ts/generators/boolean.ts index 499800606e5aa0513b4c08a2bfc211de3c33c8c0..9c74a156a89b1c242578950aec1a099080b8afc2 100644 --- a/ts/generators/boolean.ts +++ b/ts/generators/boolean.ts @@ -1,10 +1,12 @@ +var option = require('../api/option'); + /** * Generates randomized boolean value. * * @returns {boolean} */ function booleanGenerator(): boolean { - return Math.random() > 0.5; + return option('random')() > 0.5; } export = booleanGenerator; diff --git a/ts/types/string.ts b/ts/types/string.ts index 39d5f7ec3fc4f368364b88298770ee37c2910856..2dfa3cab7a671a9f2033d798f281b90ec5efaf4a 100644 --- a/ts/types/string.ts +++ b/ts/types/string.ts @@ -55,7 +55,7 @@ var stringType: FTypeGenerator = function stringType(value: IStringSchema): stri } while (output.length < minLength) { - output += Math.random() > 0.7 ? thunk() : randexp('.+'); + output += option('random')() > 0.7 ? thunk() : randexp('.+'); } if (output.length > maxLength) {