4 个版本 (稳定)

2.0.0 2023年8月27日
1.0.1 2023年3月9日
1.0.0 2023年3月8日
0.1.0 2023年3月8日

#5#ord

每月下载量 30 次

MIT 许可证

33KB
404

Reltester

Crates.io docs.rs GitHub Workflow Status Crates.io min-rustc

Relation tester 是一个用于自动检查 [Partial]Eq[Partial]OrdHash[DoubleEnded|Fused]Iterator 特性实现的测试工具。它在与 quickcheck 或其他基于属性的测试框架一起使用时非常有用。

访问 文档

动机

想象一下,你有一个类型 Foo,它有自定义实现的 PartialEqEqPartialOrdOrd。这里的“自定义”指的是手工编写,而不是继承。Rust 编译器本身无法验证这些实现的正确性,因此必须由你,程序员,来维护关于你所实现的特定 二元关系 的一些不变性。例如,如果你为 Foo 实现 PartialEq,你必须保证 foo1 == foo2 意味着 foo2 == foo1对称性)。

其他特性如 HashIterator 也要求遵守几个不变性——其中一些是非常直观的,而 其他 则不是。在实现 std::iter 系列特性的代码库中,引入不完美的实现是非常常见的,这可能导致诸如 ^1^3 等错误。

想法是,当你手动在代码库中实现这些特性之一时,你可以将这些不变性保存在脑海中,并在测试套件中添加 Reltester 检查,从而有更高的信心保证你的实现是正确的。

如何使用

  1. 编写一些测试用例,生成您希望测试的类型随机值。您可以通过手动或使用类似 quickcheckproptest 的 crate 来实现。

  2. 根据您的类型实现的特质,调用相应的检查器。

    • reltester::eq 用于 Eq

      ;
    • reltester::ord 用于 Ord

      ;
    • reltester::partial_eq 用于 PartialEq

      ;
    • reltester::partial_ord 用于 PartialOrd

      ;
    • reltester::hash 用于 Hash

      ;
    • reltester::iterator 用于 Iterator

      ;
    • reltester::fused_iterator 用于 FusedIterator

      ;
    • reltester::double_ended_iterator 用于 DoubleEndedIterator

    一些这些函数接受多个(两个或三个)相同类型的值。这是因为测试某些不变量可能需要三个值。

有关更多信息,请参阅文档。如果无法满足主函数的类型界限,则 reltester::invariants 模块可用于更细粒度的检查。

示例

f32(《PartialEq》,PartialOrd

;

use reltester;
use quickcheck_macros::quickcheck;

#[quickcheck]
fn test_f32(a: f32, b: f32, c: f32) -> bool {
    // Let's check if `f32` implements `PartialEq` and `PartialOrd` correctly
    // (spoiler: it does).
    reltester::partial_eq(&a, &b, &c).is_ok()
        && reltester::partial_ord(&a, &b, &c).is_ok()
}

u32(《Hash

use reltester;
use quickcheck_macros::quickcheck;

#[quickcheck]
fn test_u32(a: u32, b: u32) -> bool {
    // Unlike `f32`, `u32` implements both `Eq` and `Hash`, which allows us to
    // test `Hash` invariants.
    reltester::hash(&a, &b).is_ok()
}

Vec<u32>(《DoubleEndedIterator

use reltester;
use quickcheck_macros::quickcheck;

#[quickcheck]
fn test_vec_u32(nums: Vec<u32>) -> bool {
    // `Iterator` is implied and checked by both `DoubleEndedIterator` and
    // `FusedIterator`.
    reltester::double_ended_iterator(nums.iter()).is_ok()
        && reltester::fused_iterator(nums.iter()).is_ok()
}

Reltester 在 MIT 许可证下可用。

外部参考和脚注

依赖关系

~0.5–1MB
~23K SLoC