测试一个“范围”是否包含另一个“范围”的惯用方法

问题描述 投票:0回答:1

这个恕我直言的惯用测试用例无法编译:

#[test]
fn test_rangyness() {
    let a = 0..42;
    let b = 1..41;
    assert!(a.contains(&b)); // compiler error
}

我可以做

#[test]
fn test_rangyness() {
    let a = 0..42;
    let b = 1..42;
    assert!(a.contains(&b.start) && a.contains(&b.end - 1));
}

但是有一个丑陋的

- 1
,这是正确性所必需的。有没有更惯用的方法来测试这个?

rust
1个回答
0
投票

这个

ContainsRange
特征扩展了惯用的定义,并且需要每晚 Rust 来实现
Step
特征,但涵盖了所有类型的范围:

#![feature(step_trait)]

use std::iter::Step;
use std::ops::{Bound, RangeBounds};

trait ContainsRange<T> {
    fn contains_range(&self, other: &impl RangeBounds<T>) -> bool;
}

impl<T: Step, R: RangeBounds<T>> ContainsRange<T> for R {
    fn contains_range(&self, other: &impl RangeBounds<T>) -> bool {
        fn check<T: Step>(left: Bound<&T>, right: Bound<&T>, end: bool) -> bool {
            match (left, right, end) {
                (Bound::Unbounded, _, false) | (_, Bound::Unbounded, true) => true,
                (_, Bound::Unbounded, false) | (Bound::Unbounded, _, true) => false,
                (Bound::Included(l), Bound::Included(r), _)
                | (Bound::Excluded(l), Bound::Excluded(r), _) => l <= r,
                (Bound::Excluded(l), Bound::Included(r), false)
                | (Bound::Included(l), Bound::Excluded(r), true) => l < r,
                (Bound::Included(l), Bound::Excluded(r), false)
                | (Bound::Excluded(l), Bound::Included(r), true) => {
                    l <= r || l == &Step::forward(r.clone(), 1)
                }
            }
        }
        check(self.start_bound(), other.start_bound(), false)
            && check(other.end_bound(), self.end_bound(), true)
    }
}

#[test]
fn test_rangyness() {
    let a = 0..42;
    let b = 1..41;
    assert!(a.contains_range(&b));

    fn bound_permutations(x: i8) -> impl Iterator<Item = Bound<i8>> {
        [Bound::Unbounded, Bound::Included(x), Bound::Excluded(x)].into_iter()
    }
    fn effective_bound(b: Bound<i8>, end: bool) -> i8 {
        match (b, end) {
            (Bound::Included(x), _) => x,
            (Bound::Excluded(x), false) => x + 1,
            (Bound::Excluded(x), true) => x - 1,
            (Bound::Unbounded, false) => i8::MIN,
            (Bound::Unbounded, true) => i8::MAX,
        }
    }
    use itertools::Itertools;
    for permutation in (-3..=3).permutations(4) {
        for a in bound_permutations(permutation[0]) {
            for b in bound_permutations(permutation[1]) {
                for c in bound_permutations(permutation[2]) {
                    for d in bound_permutations(permutation[3]) {
                        let left = (a, b);
                        let right = (c, d);

                        if (effective_bound(c, false)..=effective_bound(d, true)).is_empty() {
                            continue;
                        }

                        let expected = effective_bound(a, false) <= effective_bound(c, false)
                            && effective_bound(b, true) >= effective_bound(d, true);
                        let actual = left.contains_range(&right);

                        assert_eq!(expected, actual, "{a:?} {b:?} - {c:?} {d:?}");
                    }
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.