#assert #assertions #macro #test

one_assert

一个assert!宏,取代所有其他宏

1 个不稳定版本

0.1.0 2024年7月15日

#428测试

Download history 111/week @ 2024-07-15

111 每月下载量

MIT/Apache

49KB
699

一个带有更强大的assert!()宏的Rust crate

Tests Crates.io Documentation Dependency status

One Assert

TL;DR

当你可以用assert!(a == b)(或assert!(a != b)assert!(a > b)等)获得相同输出时,为什么还要有单独的宏,比如assert_eqassert_ne(以及assert_gt等)?这个crate提供了一个单一的assert!宏,在失败时提供更详细的输出。

简介

Rust的标准库提供了assertassert_eqassert_ne宏。然而,这些宏存在一些不便之处,例如没有为其他不等式提供专门化,比如为>=等提供assert_ge,或者名称只有一两个字母不同(assert_eqassert_neassert_geassert_gt等),因此容易在视觉上混淆。

不添加更多宏的主要原因是可以用assert!(a >= b)很好地表示它们,因此没有必要为每种使用情况都使用单独的宏。

但这引发了一个问题:为什么我们最初要有assert_eqassert_ne呢?

实际原因:assert_eq!(a, b)的输出比assert!(a == b)更好

let x = 1;
let msg = catch_panic!({ assert!(x == 2); });
assert_eq!(msg, "assertion failed: x == 2");

let msg = catch_panic!({ assert_eq!(x, 2); });
assert_eq!(msg, "assertion `left == right` failed
  left: 1
 right: 2"
);

如您所见,assert_eq能够提供关于各个值的具体信息。但是:这并不一定是必须的。Rust有卫生和过程宏,因此我们可以让assert!(a == b)assert_eq!(a, b)具有相同的工作方式

let x = 1;
let msg = catch_panic!({ one_assert::assert!(x == 2); });
assert_eq!(msg, "assertion `x == 2` failed
     left: 1
    right: 2"
);

现在我们可以将此扩展到我们想要的任何数量的运算符

let x = 1;
let msg = catch_panic!({ one_assert::assert!(x > 2); });
assert_eq!(msg, "assertion `x > 2` failed
     left: 1
    right: 2"
);

示例

let x = 1;
let msg = catch_panic!({ one_assert::assert!(x > 2); });
assert_eq!(msg, "assertion `x > 2` failed
     left: 1
    right: 2"
);

let msg = catch_panic!({ one_assert::assert!(x != 1, "x ({}) should not be 1", x); });
assert_eq!(msg, "assertion `x != 1` failed: x (1) should not be 1
     left: 1
    right: 1"
);

let s = "Hello World";
let msg = catch_panic!({ one_assert::assert!(s.starts_with("hello")); });
assert_eq!(msg, r#"assertion `s.starts_with("hello")` failed
     self: "Hello World"
    arg 0: "hello""#
);

局限性

  • 几个组件需要实现Debug
    • 该宏将打印表达式认为有用的任何部分,并进行调试打印。这意味着这些部分需要实现Debug
    • 打印为任何给定表达式类型的部分可能会发生变化,因此建议仅在几乎所有的代码都实现了Debug的情况下使用此功能。
  • Debug打印即使在断言通过的情况下也会发生
    • 因为这个宏打印的不仅仅是==!=比较的两边,它必须处理在表达式评估过程中某些值被移动的事实。这意味着必须提前打印这些值。
    • 后果:不要在性能关键代码中使用此宏。
    • 然而,需要注意的是,表达式及其每个部分只被评估一次。
      • (尽管值得注意的是,像&&这样的快速失败运算符通常只会评估左侧并停止,但与此宏一起,它将始终评估两侧)

依赖关系

~0.6–1.1MB
~18K SLoC