diff options
| author | bors <bors@rust-lang.org> | 2014-12-08 12:12:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-12-08 12:12:23 +0000 |
| commit | c7a9b49d1b5d4e520f25355f26a93dfac4ffa146 (patch) | |
| tree | 7a2a559658447be5fe71de276b7e8296b2999770 /src/libsyntax | |
| parent | cf0b4e068227dd33fa15f3ffe24f29e0535d197f (diff) | |
| parent | a20926a51add66ab67053843e244efb1a4d7ad76 (diff) | |
| download | rust-c7a9b49d1b5d4e520f25355f26a93dfac4ffa146.tar.gz rust-c7a9b49d1b5d4e520f25355f26a93dfac4ffa146.zip | |
auto merge of #19560 : sfackler/rust/should-fail-reason, r=alexcrichton
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..ca2f190ce76 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("expected"))) + .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( |
