Я начну с sndBigger
- это очень простая функция, но вы можете написать некоторые свойства, которые должны храниться в ней. Например, что происходит, когда вы меняете значения в кортеже:
// Reversing values of the tuple negates the result
let swap (a, b) = (b, a)
let prop_sndBiggerSwap x =
sndBigger x = not (sndBigger (swap x))
// If two elements of the tuple are same, it should give 'false'
let prop_sndBiggerEq a =
sndBigger (a, a) = false
РЕДАКТИРОВАТЬ: Это правило prop_sndBiggerSwap
не всегда соблюдается (см. Комментарий kvb ). Однако следующее должно быть правильным:
// Reversing values of the tuple negates the result
let prop_sndBiggerSwap a b =
if a <> b then
let x = (a, b)
sndBigger x = not (sndBigger (swap x))
Относительно функции pairs
, kvb уже опубликовал несколько хороших идей. Кроме того, вы можете проверить, что преобразование преобразованного списка обратно в список элементов возвращает исходный список (вам нужно будет обработать случай, когда список ввода нечетный - в зависимости от того, что должна делать функция pairs
в этом случае ):
let prop_pairsEq (x:_ list) =
if (x.Length%2 = 0) then
x |> pairs |> List.collect (fun (a, b) -> [a; b]) = x
else true
Для splitOn
мы можем протестировать аналогичную вещь - если вы объединяете все возвращенные списки, он должен дать исходный список (это не проверяет поведение разбиения, но начинать хорошо - это с минимум гарантирует, что ни один элемент не будет потерян).
let prop_splitOnEq f x =
x |> splitOn f |> List.concat = x
Я не уверен, может ли FsCheck справиться с этим, хотя (!), Потому что свойство принимает функцию в качестве аргумента (поэтому ему нужно будет генерировать "случайные функции"). Если это не работает, вам нужно предоставить несколько более специфических свойств с помощью некоторой рукописной функции f
. Далее, реализация проверки, что f
возвращает true для всех смежных пар в разделенных списках (как предполагает kvb ), на самом деле не так сложна:
let prop_splitOnAdjacentTrue f x =
x |> splitOn f
|> List.forall (fun l ->
l |> Seq.pairwise
|> Seq.forall (fun (a, b) -> f a b))
Вероятно, единственная последняя вещь, которую вы можете проверить, это то, что f
возвращает false
, когда вы даете ему последний элемент из одного списка и первый элемент из следующего списка. Следующее не полностью завершено, но оно показывает путь:
let prop_splitOnOtherFalse f x =
x |> splitOn f
|> Seq.pairwise
|> Seq.forall (fun (a, b) -> lastElement a = firstElement b)
Последний пример также показывает, что вы должны проверить, может ли функция splitOn
возвращать пустой список как часть возвращенного списка результатов (потому что в этом случае вы не можете найти первый / последний элемент).