问题
Following code aims to generate random sorted array, and key as one element of that array. But I do not know the issue, the keys are not in the array?
@Provide
Arbitrary<Map<Integer, Integer[]>> llstPairs() {
// sortedArrayGenerator is generattor that return Arbitrary<Integer[]> sorted values
// and it works fine
Arbitrary<Integer[]> vals = sortedArrayGenerator();
Integer[] sample = vals.sample();
Arbitrary<Integer> key = Arbitraries.samples(sample);
return Arbitraries.maps(key,vals);
}
Why my keys are not in the array, I need the key to be one element of the Integer[] array.
回答1:
The one important thing you should be aware of is: "Never create your own sample. Let jqwik decide when to do that." In other words: Arbitrary.sample()
is only for testing generators, e.g. in JShell, or using generators outside of jqwik properties.
What you need instead is Arbitrary.flatMap()
. Flat mapping is needed whenever the result of one generator is needed to feed another generator. So your first try could be:
@Provide
Arbitrary<Map<Integer, Integer[]>> llstPairs() {
Arbitrary<Integer[]> vals = sortedArrayGenerator().filter(array -> array.length > 0);
return vals.flatMap(array -> {
Arbitrary<Integer> keys = Arbitraries.of(array);
return Arbitraries.maps(keys, vals);
});
}
Two sidenotes:
- I filter out empty arrays because they will make problems down the road
- Read the javadoc for Arbitraries.sample()! It's not what you want which is Arbitraries.of().
However, it's not as easy because the generated array for the map is a different one than you used for the keys. You have to make sure that you use the exact same array when creating the map. So you might go with:
@Provide
Arbitrary<Map<Integer, Integer[]>> llstPairs() {
Arbitrary<Integer[]> vals = sortedArrayGenerator().filter(array -> array.length > 0);
return vals.flatMap(array -> {
Arbitrary<Integer> keys = Arbitraries.of(array);
Arbitrary<List<Integer>> listOfKeys = keys.list();
return listOfKeys.map(lok -> {
Map<Integer, Integer[]> map = new HashMap<>();
for (Integer k : lok) {
map.put(k, array);
}
return map;
});
});
}
which is quite involved given that - as I understand it - you don't really need the map but want a list of key-array-pairs. That's why I would go with this:
@Provide
Arbitrary<List<Tuple.Tuple2<Integer, Integer[]>>> listOfPairs() {
Arbitrary<Integer[]> vals = sortedArrayGenerator().filter(array -> array.length > 0);
return vals.flatMap(arrayOfInt -> {
Arbitrary<Integer> key = Arbitraries.of(arrayOfInt);
return key.map(k -> Tuple.of(k, arrayOfInt)).list();
});
}
And here's a property to check that it does what it's supposed to do:
@Property(tries = 100)
void listOfPairs_keyIsInArray(@ForAll("listOfPairs") List<Tuple.Tuple2<Integer, Integer[]>> listOfPairs) {
for (Tuple.Tuple2<Integer, Integer[]> pair : listOfPairs) {
Integer key = pair.get1();
Integer[] array = pair.get2();
Assertions.assertThat(array).contains(key);
}
}
来源:https://stackoverflow.com/questions/60028612/jqwik-pairs-of-sorted-array-with-some-element-of-it