From cb860dc28f4dee51f8793fa7c0a7cf4c64e9bf4d Mon Sep 17 00:00:00 2001 From: Nicolas DUBIEN Date: Tue, 19 Jun 2018 08:35:39 +0200 Subject: [PATCH] Do not force explicitly one parameter in constantFrom Related to #122 --- documentation/Arbitraries.md | 2 +- src/check/arbitrary/ConstantArbitrary.ts | 15 ++++++++++----- test/e2e/GenerateAllValues.spec.ts | 4 +--- .../check/arbitrary/ConstantArbitrary.spec.ts | 9 ++++++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/documentation/Arbitraries.md b/documentation/Arbitraries.md index 9e67839e2f6..47dab8c630a 100644 --- a/documentation/Arbitraries.md +++ b/documentation/Arbitraries.md @@ -61,7 +61,7 @@ Strings that mimic real strings, with words and sentences: ## Combinors of arbitraries (:T) - `fc.constant(value: T): Arbitrary` constant arbitrary only able to produce `value: T` -- `fc.constantFrom(...values: T[]): Arbitrary` randomly chooses among the values provided. It considers the first value as the default value so that in case of failure it will shrink to it +- `fc.constantFrom(...values: T[]): Arbitrary` randomly chooses among the values provided. It considers the first value as the default value so that in case of failure it will shrink to it. It expects a minimum of one value and throws whether it receives no value as parameters. It can easily be used on arrays with `fc.constantFrom(...myArray)` (or `fc.constantFrom.apply(null, myArray)` for older versions of TypeScript/JavaScript) - `fc.oneof(...arbs: Arbitrary[]): Arbitrary` randomly chooses an arbitrary at each new generation. Should be provided with at least one arbitrary. All arbitraries are equally probable and shrink is still working for the selected arbitrary. `fc.oneof` is able to shrink inside the failing arbitrary but not accross arbitraries (contrary to `fc.constantFrom` when dealing with constant arbitraries) - `fc.option(arb: Arbitrary): Arbitrary` or `fc.option(arb: Arbitrary, freq: number): Arbitrary` arbitrary able to nullify its generated value. When provided a custom `freq` value it changes the frequency of `null` values so that they occur one time over `freq` tries (eg.: `freq=5` means that 20% of generated values will be `null` and 80% would be produced through `arb`). By default: `freq=5` - `fc.array(arb: Arbitrary): Arbitrary`, `fc.array(arb: Arbitrary, maxLength: number): Arbitrary` or `fc.array(arb: Arbitrary, minLength: number, maxLength: number): Arbitrary` array of random length containing values generated by `arb`. By setting the parameters `minLength` and/or `maxLength`, the user can change the minimal (resp. maximal) size allowed for the generated array. By default: `minLength=0` and `maxLength=10` diff --git a/src/check/arbitrary/ConstantArbitrary.ts b/src/check/arbitrary/ConstantArbitrary.ts index a19285af813..4085ac79ee6 100644 --- a/src/check/arbitrary/ConstantArbitrary.ts +++ b/src/check/arbitrary/ConstantArbitrary.ts @@ -31,12 +31,17 @@ function constant(value: T): Arbitrary { } /** - * For one of `v0` or `...values` values - all equiprobable - * @param v0 One of the value to produce (all values shrink to this one) - * @param values Other possible values + * For one `...values` values - all equiprobable + * + * **WARNING**: It expects at least one value, otherwise it should throw + * + * @param values Constant values to be produced (all values shrink to the first one) */ -function constantFrom(v0: T, ...values: T[]): Arbitrary { - return new ConstantArbitrary([v0, ...values]); +function constantFrom(...values: T[]): Arbitrary { + if (values.length === 0) { + throw new Error('fc.constantFrom expects at least one parameter'); + } + return new ConstantArbitrary([...values]); } export { constant, constantFrom }; diff --git a/test/e2e/GenerateAllValues.spec.ts b/test/e2e/GenerateAllValues.spec.ts index a09d836bb3b..bcd92b0b8b0 100644 --- a/test/e2e/GenerateAllValues.spec.ts +++ b/test/e2e/GenerateAllValues.spec.ts @@ -50,9 +50,7 @@ describe(`Generate all values (seed: ${seed})`, () => { describe('fc.constantFrom()', () => { it('Should be able to produce all the constants', () => fc.assert( - fc.property(fc.set(fc.string(), 0, 40), csts => - lookForMissing(fc.constantFrom(csts[0], ...csts.slice(1)), csts.length) - ) + fc.property(fc.set(fc.string(), 1, 40), csts => lookForMissing(fc.constantFrom(...csts), csts.length)) )); }); }); diff --git a/test/unit/check/arbitrary/ConstantArbitrary.spec.ts b/test/unit/check/arbitrary/ConstantArbitrary.spec.ts index 17feeb95db7..ac1903973c1 100644 --- a/test/unit/check/arbitrary/ConstantArbitrary.spec.ts +++ b/test/unit/check/arbitrary/ConstantArbitrary.spec.ts @@ -22,11 +22,14 @@ describe('ConstantArbitrary', () => { }); }); describe('constantFrom', () => { + it('Should throw when no parameters', () => { + assert.throws(() => constantFrom()); + }); it('Should always return one of the constants', () => fc.assert( fc.property(fc.array(fc.string(), 1, 10), fc.integer(), (data, seed) => { const mrng = stubRng.mutable.fastincrease(seed); - const g = constantFrom(data[0], ...data.slice(1)).generate(mrng).value; + const g = constantFrom(...data).generate(mrng).value; return data.indexOf(g) !== -1; }) )); @@ -34,7 +37,7 @@ describe('ConstantArbitrary', () => { fc.assert( fc.property(fc.array(fc.string(), 1, 10), fc.integer(), fc.nat(), (data, seed, idx) => { const mrng = stubRng.mutable.fastincrease(seed); - const arb = constantFrom(data[0], ...data.slice(1)); + const arb = constantFrom(...data); for (let id = 0; id != 10000; ++id) { const g = arb.generate(mrng).value; if (g === data[idx % data.length]) return true; @@ -46,7 +49,7 @@ describe('ConstantArbitrary', () => { fc.assert( fc.property(fc.set(fc.string(), 1, 10), fc.integer(), (data, seed) => { const mrng = stubRng.mutable.fastincrease(seed); - const shrinkable = constantFrom(data[0], ...data.slice(1)).generate(mrng); + const shrinkable = constantFrom(...data).generate(mrng); if (data.indexOf(shrinkable.value) === 0) assert.deepStrictEqual([...shrinkable.shrink()], []); else assert.deepStrictEqual([...shrinkable.shrink()].map(s => s.value), [data[0]]); })