这个恕我直言的惯用测试用例无法编译:
#[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
,这是正确性所必需的。有没有更惯用的方法来测试这个?
这个
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:?}");
}
}
}
}
}
}