jqwik пары отсортированного массива с некоторым его элементом

Следующий код направлен на создание случайного отсортированного массива и ключа как одного элемента этого массива. Но я не знаю, в чем проблема, ключей нет в массиве?

@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);

}

Почему моих ключей нет в массиве, мне нужно, чтобы ключ был одним из элементов массива Integer[].

1 ответ

Вы должны знать одну важную вещь: "Никогда не создавайте свой собственный образец. Пусть jqwik решит, когда это делать". Другими словами:Arbitrary.sample() предназначен только для тестирования генераторов, например, в JShell, или использования генераторов вне свойств jqwik.

Вместо этого вам нужно Arbitrary.flatMap(). Плоское отображение необходимо всякий раз, когда результат одного генератора необходим для питания другого генератора. Итак, ваша первая попытка может быть:

@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);
    });

}

Два примечания:

  • Я отфильтровываю пустые массивы, потому что они создадут проблемы в будущем
  • Прочтите javadoc для Arbitraries.sample()! Это не то, что вы хотите Arbitraries.of().

Однако это не так просто, потому что сгенерированный массив для карты отличается от того, который вы использовали для ключей. Вы должны убедиться, что используете точно такой же массив при создании карты. Итак, вы можете пойти с:

@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;
        });
    });
}

что довольно сложно, учитывая, что - насколько я понимаю - вам действительно не нужна карта, но нужен список пар ключей-массивов. Вот почему я бы пошел с этим:

@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();
    });
}

А вот свойство, позволяющее проверить, что он делает то, что должен:

@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);
    }
}
Другие вопросы по тегам