Skip to content

Commit

Permalink
Do not force explicitly one parameter in frequency
Browse files Browse the repository at this point in the history
  • Loading branch information
dubzzz committed Jun 29, 2018
1 parent 1833a4b commit 4028542
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 19 deletions.
15 changes: 10 additions & 5 deletions src/check/arbitrary/FrequencyArbitrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ class FrequencyArbitrary<T> extends Arbitrary<T> {
}

/**
* For one of the values generated by `warb0` or `...warbs` - the probability of selecting the ith warb is of `warb[i].weight / sum(warb[j].weight)`
* @param warb0 One of the (Arbitrary, weight) that might be called to produce a value
* @param warbs Other possible (Arbitrary, weight)
* For one of the values generated by `...warbs` - the probability of selecting the ith warb is of `warb[i].weight / sum(warb[j].weight)`
*
* **WARNING**: It expects at least one (Arbitrary, weight)
*
* @param warbs (Arbitrary, weight)s that might be called to produce a value
*/
function frequency<T>(warb0: WeightedArbitrary<T>, ...warbs: WeightedArbitrary<T>[]): Arbitrary<T> {
return new FrequencyArbitrary([warb0, ...warbs]);
function frequency<T>(...warbs: WeightedArbitrary<T>[]): Arbitrary<T> {
if (warbs.length === 0) {
throw new Error('fc.frequency expects at least one parameter');
}
return new FrequencyArbitrary([...warbs]);
}

export { frequency };
23 changes: 9 additions & 14 deletions test/unit/check/arbitrary/FrequencyArbitrary.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,25 @@ describe('FrequencyArbitrary', () => {
const rng = (seed: number) => stubRng.mutable.fastincrease(seed);
it('Should produce the same as oneof when called on weights of 1', () =>
fc.assert(
fc.property(fc.integer(), fc.integer(), fc.array(fc.integer()), (seed, choice1, others) => {
const gFreq = frequency(
{ weight: 1, arbitrary: stubArb.counter(choice1) },
...others.map(c => Object({ weight: 1, arbitrary: stubArb.counter(c) }))
).generate(rng(seed)).value;
const gOneOf = oneof(stubArb.counter(choice1), ...others.map(stubArb.counter)).generate(rng(seed)).value;
fc.property(fc.integer(), fc.array(fc.integer(), 1, 10), (seed, choices) => {
const gFreq = frequency(...choices.map(c => Object({ weight: 1, arbitrary: stubArb.counter(c) }))).generate(
rng(seed)
).value;
const gOneOf = oneof(...choices.map(stubArb.counter)).generate(rng(seed)).value;
return gFreq == gOneOf;
})
));
it('Should produce the same as oneof with sum of weights elements', () =>
fc.assert(
fc.property(fc.integer(), weightArb(), fc.array(weightArb()), (seed, choice1, others) => {
fc.property(fc.integer(), fc.array(weightArb(), 1, 10), (seed, choices) => {
const expand = (value: number, num: number): number[] => [...Array(num)].map(() => value);

const othersOneOf = [choice1, ...others]
.reduce((p: number[], c) => p.concat(...expand(c[0], c[1])), [])
.slice(1);
const choicesOneOf = [...choices].reduce((p: number[], c) => p.concat(...expand(c[0], c[1])), []);

const gFreq = frequency(
{ weight: choice1[1], arbitrary: stubArb.counter(choice1[0]) },
...others.map(c => Object({ weight: c[1], arbitrary: stubArb.counter(c[0]) }))
...choices.map(c => Object({ weight: c[1], arbitrary: stubArb.counter(c[0]) }))
).generate(rng(seed)).value;
const gOneOf = oneof(stubArb.counter(choice1[0]), ...othersOneOf.map(stubArb.counter)).generate(rng(seed))
.value;
const gOneOf = oneof(...choicesOneOf.map(stubArb.counter)).generate(rng(seed)).value;
return gFreq == gOneOf;
})
));
Expand Down

0 comments on commit 4028542

Please sign in to comment.