diff options
| author | Steven Fackler <sfackler@gmail.com> | 2014-12-04 23:02:36 -0800 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2014-12-06 15:13:48 -0800 |
| commit | 616af6eb83630b76bb3a9bde57a00f5ebe5dbd6c (patch) | |
| tree | 494380149d05abc6c6954b1b6bcbee856563d163 /src/libsyntax | |
| parent | de83d7dd191bf5564855057a29f9b5d9dcfcb201 (diff) | |
| download | rust-616af6eb83630b76bb3a9bde57a00f5ebe5dbd6c.tar.gz rust-616af6eb83630b76bb3a9bde57a00f5ebe5dbd6c.zip | |
Allow message specification for should_fail
The test harness will make sure that the panic message contains the
specified string. This is useful to help make `#[should_fail]` tests a
bit less brittle by decreasing the chance that the test isn't
"accidentally" passing due to a panic occurring earlier than expected.
The behavior is in some ways similar to JUnit's `expected` feature:
`@Test(expected=NullPointerException.class)`.
Without the message assertion, this test would pass even though it's not
actually reaching the intended part of the code:
```rust
#[test]
#[should_fail(message = "out of bounds")]
fn test_oob_array_access() {
let idx: uint = from_str("13o").unwrap(); // oops, this will panic
[1i32, 2, 3][idx];
}
```
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/test.rs | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 05828fc05f8..3d2cb988434 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -37,12 +37,17 @@ use {ast, ast_util}; use ptr::P; use util::small_vector::SmallVector; +enum ShouldFail { + No, + Yes(Option<InternedString>), +} + struct Test { span: Span, path: Vec<ast::Ident> , bench: bool, ignore: bool, - should_fail: bool + should_fail: ShouldFail } struct TestCtxt<'a> { @@ -360,8 +365,16 @@ fn is_ignored(i: &ast::Item) -> bool { i.attrs.iter().any(|attr| attr.check_name("ignore")) } -fn should_fail(i: &ast::Item) -> bool { - attr::contains_name(i.attrs.as_slice(), "should_fail") +fn should_fail(i: &ast::Item) -> ShouldFail { + match i.attrs.iter().find(|attr| attr.check_name("should_fail")) { + Some(attr) => { + let msg = attr.meta_item_list() + .and_then(|list| list.iter().find(|mi| mi.check_name("message"))) + .and_then(|mi| mi.value_str()); + ShouldFail::Yes(msg) + } + None => ShouldFail::No, + } } /* @@ -550,7 +563,20 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> { vec![name_expr]); let ignore_expr = ecx.expr_bool(span, test.ignore); - let fail_expr = ecx.expr_bool(span, test.should_fail); + let should_fail_path = |name| { + ecx.path(span, vec![self_id, test_id, ecx.ident_of("ShouldFail"), ecx.ident_of(name)]) + }; + let fail_expr = match test.should_fail { + ShouldFail::No => ecx.expr_path(should_fail_path("No")), + ShouldFail::Yes(ref msg) => { + let path = should_fail_path("Yes"); + let arg = match *msg { + Some(ref msg) => ecx.expr_some(span, ecx.expr_str(span, msg.clone())), + None => ecx.expr_none(span), + }; + ecx.expr_call(span, ecx.expr_path(path), vec![arg]) + } + }; // self::test::TestDesc { ... } let desc_expr = ecx.expr_struct( |
