diff --git a/src/lib/types/object.js b/src/lib/types/object.js index 697334731cc42db58517959d77790d0711f6f9d5..4eee65290c2b533fbfc3faeec5a9476accb43ab7 100644 --- a/src/lib/types/object.js +++ b/src/lib/types/object.js @@ -73,7 +73,8 @@ function objectType(value, path, resolve, traverseCallback) { }); // properties are read from right-to-left - const _props = requiredProperties.concat(extraProperties).slice(0, max); + const _limit = optionalsProbability !== false ? max : random.number(0, max); + const _props = requiredProperties.concat(extraProperties.slice(0, _limit)); const _defns = []; if (value.dependencies) { diff --git a/tests/schema/core/issues/issue-514.json b/tests/schema/core/issues/issue-514.json new file mode 100644 index 0000000000000000000000000000000000000000..e2fca5cb4fefe78bd8b22dd7c285e4f631503f02 --- /dev/null +++ b/tests/schema/core/issues/issue-514.json @@ -0,0 +1,48 @@ +[ + { + "description": "requiredOnly option being ignored", + "tests": [ + { + "description": "should omit non-required props if enabled", + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + }, + "b": { + "type": "number" + } + }, + "required": [ + "a" + ] + }, + "onlyProps": ["a"], + "set": { + "requiredOnly": true + }, + "valid": true + }, + { + "description": "should generate randomly otherwise", + "schema": { + "type": "object", + "properties": { + "a": { + "type": "string" + }, + "b": { + "type": "number" + } + }, + "required": [ + "a" + ] + }, + "minProps": [1, 2], + "valid": true + } + ] + } +] diff --git a/tests/schema/core/option/random.json b/tests/schema/core/option/random.json index 6ee53c6ed8b189ad7d5d64780835b3d6dffe1356..eb60a5c3d1cb1b3327319bd07de650ad775c77cb 100644 --- a/tests/schema/core/option/random.json +++ b/tests/schema/core/option/random.json @@ -23,9 +23,9 @@ }, "valid": true, "equal": { - "a": 54, - "b": "minim amet in dolor laborum", - "c": "pf922" + "a": 44, + "b": "in culpa proident amet", + "c": "fe228" }, "repeat": 1, "require": "core/option/random" diff --git a/tests/schema/helpers.js b/tests/schema/helpers.js index 897cfaa03dcc65251b42691aee2d6c40b4f2fe09..bab015b560693bf8b883160481b08219ba1b9352 100644 --- a/tests/schema/helpers.js +++ b/tests/schema/helpers.js @@ -59,7 +59,7 @@ export function getTests(srcDir) { return { only, all }; } -export function tryTest(nth, max, test, refs, schema) { +export function tryTest(nth, max, test, refs, schema, callback) { return _jsf.resolve(schema, refs).then(sample => { if (test.dump) { console.log(JSON.stringify(sample, null, 2)); @@ -123,6 +123,10 @@ export function tryTest(nth, max, test, refs, schema) { if ('equal' in test) { expect(sample).to.eql(test.equal); } + + if (callback) { + callback(sample); + } }).catch(error => { if (typeof test.throws === 'string') { expect(error).to.match(new RegExp(test.throws, 'im')); diff --git a/tests/schema/main.spec.js b/tests/schema/main.spec.js index 9b7a67b5f58ac91110aedd80b3a1b639617963af..a8d0979f2f304b0d8ad0d371f496a13b4908e09e 100644 --- a/tests/schema/main.spec.js +++ b/tests/schema/main.spec.js @@ -60,9 +60,25 @@ function seed() { const tasks = []; + // count prescence of props... + const props = test.minProps ? test.minProps.reduce((prev, cur) => { + prev[String(cur)] = 0; + return prev; + }, {}) : null; + while (nth) { if (!test.skip) { - tasks.push(tryTest(nth, max, test, refs, schema)); + tasks.push(tryTest(nth, max, test, refs, schema, sample => { + if (props) { + const length = String(Object.keys(sample).length); + + if (typeof props[length] === 'undefined') { + throw new Error(`Unexpected length(${length}), given '${test.minProps.join(', ')}'`); + } + + props[length] += 1; + } + })); } nth -= 1; @@ -78,6 +94,10 @@ function seed() { // FIXME: find a way to debug this console.log('---> Used seeds:', seeds.slice(-10).join(', ') || test.seed); throw e; + }).then(() => { + if (props && Object.values(props).some(x => x === 0)) { + throw new Error(`minProps failed, got: ${JSON.stringify(props)}`); + } }); }).timeout(suite.timeout || test.timeout || (process.CI ? 30000 : 10000)); });