4 个版本

0.2.1 2024 年 4 月 5 日
0.2.0 2024 年 4 月 5 日
0.1.1 2024 年 4 月 5 日
0.1.0 2024 年 4 月 5 日

#944Rust 模式

每月 25 次下载
用于 prism-compiler

MIT 许可证

15KB
260

彻底遍历

生成类型所有值的特性和基于属性的测试宏。

关于

此包提供了一个特性行为,用于生成类型(在一定深度内)的所有值。它还提供了一个派生宏,该宏会为您派生此特性。最后,它提供了一个测试宏,该宏会对类型的所有值运行基于属性的测试。

示例

#[derive(Debug, Exhaustive)]
enum Test1 { A, B, }
#[derive(Debug, Exhaustive)]
struct Test2 { a: bool }

#[exhaustive_test]
fn test(v: Test1, w: Test2) {
    println!("{v:?} {w:?}");
}
A Test2 { a: false }
A Test2 { a: true }
B Test2 { a: false }
B Test2 { a: true }

任意长度的类型(递归类型,容器类型)

为了为递归类型或如 Vec 这样的任意长度类型实现 Exhaustive,此包支持限制类型的大小。这是通过限制在类型生成过程中所做的选择数量来实现的。

在使用 exhaustive_test 宏时,您可以使用以下方式限制选择数量:

#[exhaustive_test(20)]

在生成类型时所做的选择数量不保证在版本之间保持稳定,尽管它始终保证与内存中类型的大小呈线性关系。这意味着对于大多数类型,选择数量与测试的运行时间呈指数关系。推荐的方式是根据测试期望的运行时间进行实验性选择。

详情

标准库类型

此特性对大多数标准库类型实现了,例如 VecResultOptionBoxHashMapHashSet、元组、数组等。主要的例外是数值类型,因为它们的增长速度太快,无法进行彻底测试。

派生宏

派生宏可以为任何具有所有字段都实现 Exhaustivestructenum 派生 Exhaustive。为此,需要启用此包的 macros 功能。默认情况下,此功能是启用的。

手动实现

可以手动实现此特性。特性行为的签名是

trait Exhaustive: Sized {
    fn generate(u: &mut DataSourceTaker) -> Result<Self>;
}

DataSourceTaker 有两个重要的函数,可用于生成您的类型

fn choice(&mut self, range: usize) -> Result<usize>;
fn iter_of<T: Exhaustive>(&mut self) -> Result<DataSourceTakerIter<T>>;
  • choice 将生成一个在 0..range 范围内的数字。这可以用来选择枚举的一个变体,或者在生成数据类型时做出任何其他选择。
  • iter_of 将生成一个 T 类型的迭代器。这个迭代器总是有限大小的,并且应该被完全消费。iter_of 会做出一次选择来决定迭代器的大小,之后元素生成可能会做出更多的选择。

在不使用 exhaustive_test 宏的情况下使用此 crate

任何实现了 Exhaustive 特性的类型都将自动实现以下函数

fn iter_exhaustive(max_choices: Option<usize>) -> impl Iterator<Item=Self>;

此函数提供了一个包含该类型所有生成值的迭代器,可选地带有最大选择数。

与 arbitrary 的比较

arbitrary crate 对此 crate 是一个很大的启发。它提供了与此 crate 相似的功能,但它做出了几个不同的设计决策,使其无法用于高效的穷举测试。

类型总是从一个字节切片中生成,这意味着不可能做出精确的选择,只能读取一个字节并根据它做出选择。这对于 arbitrary 的预期用途来说是可行的,即生成任意值。但要生成所有值进行穷举,这意味着我们可能需要生成所有字节序列,这可能非常大。这最终会导致生成大量重复值,因此扩展性较差。

依赖

~110KB