dimanche 29 septembre 2019

Properly proptest pairs of sets related by a constraint

I want to thoroughly test an implementation of the intersection of two BTreeSets. I can write:

use self::proptest::prelude::*;
proptest! {
    #[test]
    fn intersect_this(s1: BTreeSet<i32>, s2: BTreeSet<i32>) {
        ...
    }
}

But this has poor code coverage, because the code is specialized some cases that random sets are unlikely to hit. One of the special cases is sets whose ranges of elements are almost disjoint (one set has values <= x, the other set has values >= x). In Python with hypothesis (in which I'm a little less of a newbie), I'd write:

from hypothesis import given
from hypothesis.strategies import builds, integers, sets
from typing import Set

def touching_ranges(elements: Set[int], split: int):
    return {elt for elt in elements if elt < split}.union({split}), \
           {elt for elt in elements if elt > split}.union({split})

@given(builds(touching_ranges, sets(integers()), integers()))
def test_touching_ranges(sets):
    s1, s2 = sets
    assert len(s1.intersection(s2)) == 1

In Rust, I got no further than stuffing everything inside the body:

    #[test]
    fn touching(mut s1: BTreeSet<i32>, split: i32) {
        let mut s2 = s1.split_off(&split);
        s1.insert(split);
        s2.insert(split);
        prop_assert_eq!(s1.intersection(&s2).count(), 1);
    }

How can I keep the transformation of arbitrary values out of the test case body? I couldn't understand any of the code samples I found regarding strategies and SO is almost untained with proptest (compared to quickcheck).

Aucun commentaire:

Enregistrer un commentaire