@@ -47,6 +47,7 @@ use self::TestEvent::*;
47
47
use self :: NamePadding :: * ;
48
48
use self :: OutputLocation :: * ;
49
49
50
+ use std:: any:: { Any , AnyRefExt } ;
50
51
use std:: collections:: TreeMap ;
51
52
use stats:: Stats ;
52
53
use getopts:: { OptGroup , optflag, optopt} ;
@@ -78,7 +79,7 @@ pub mod test {
78
79
MetricChange , Improvement , Regression , LikelyNoise ,
79
80
StaticTestFn , StaticTestName , DynTestName , DynTestFn ,
80
81
run_test, test_main, test_main_static, filter_tests,
81
- parse_opts, StaticBenchFn } ;
82
+ parse_opts, StaticBenchFn , ShouldFail } ;
82
83
}
83
84
84
85
pub mod stats;
@@ -184,13 +185,19 @@ pub struct Bencher {
184
185
pub bytes : u64 ,
185
186
}
186
187
188
+ #[ deriving( Clone , Show , PartialEq , Eq , Hash ) ]
189
+ pub enum ShouldFail {
190
+ No ,
191
+ Yes ( Option < & ' static str > )
192
+ }
193
+
187
194
// The definition of a single test. A test runner will run a list of
188
195
// these.
189
196
#[ deriving( Clone , Show , PartialEq , Eq , Hash ) ]
190
197
pub struct TestDesc {
191
198
pub name : TestName ,
192
199
pub ignore : bool ,
193
- pub should_fail : bool ,
200
+ pub should_fail : ShouldFail ,
194
201
}
195
202
196
203
#[ deriving( Show ) ]
@@ -346,7 +353,7 @@ fn optgroups() -> Vec<getopts::OptGroup> {
346
353
347
354
fn usage ( binary : & str ) {
348
355
let message = format ! ( "Usage: {} [OPTIONS] [FILTER]" , binary) ;
349
- println ! ( r"{usage}
356
+ println ! ( r# "{usage}
350
357
351
358
The FILTER regex is tested against the name of all tests to run, and
352
359
only those tests that match are run.
@@ -366,10 +373,12 @@ Test Attributes:
366
373
function takes one argument (test::Bencher).
367
374
#[should_fail] - This function (also labeled with #[test]) will only pass if
368
375
the code causes a failure (an assertion failure or panic!)
376
+ A message may be provided, which the failure string must
377
+ contain: #[should_fail(expected = "foo")].
369
378
#[ignore] - When applied to a function which is already attributed as a
370
379
test, then the test runner will ignore these tests during
371
380
normal test runs. Running with --ignored will run these
372
- tests." ,
381
+ tests."# ,
373
382
usage = getopts:: usage( message. as_slice( ) ,
374
383
optgroups( ) . as_slice( ) ) ) ;
375
384
}
@@ -902,13 +911,13 @@ fn should_sort_failures_before_printing_them() {
902
911
let test_a = TestDesc {
903
912
name : StaticTestName ( "a" ) ,
904
913
ignore : false ,
905
- should_fail : false
914
+ should_fail : ShouldFail :: No
906
915
} ;
907
916
908
917
let test_b = TestDesc {
909
918
name : StaticTestName ( "b" ) ,
910
919
ignore : false ,
911
- should_fail : false
920
+ should_fail : ShouldFail :: No
912
921
} ;
913
922
914
923
let mut st = ConsoleTestState {
@@ -1114,7 +1123,7 @@ pub fn run_test(opts: &TestOpts,
1114
1123
1115
1124
let stdout = reader. read_to_end ( ) . unwrap ( ) . into_iter ( ) . collect ( ) ;
1116
1125
let task_result = result_future. into_inner ( ) ;
1117
- let test_result = calc_result ( & desc, task_result. is_ok ( ) ) ;
1126
+ let test_result = calc_result ( & desc, task_result) ;
1118
1127
monitor_ch. send ( ( desc. clone ( ) , test_result, stdout) ) ;
1119
1128
} )
1120
1129
}
@@ -1148,13 +1157,17 @@ pub fn run_test(opts: &TestOpts,
1148
1157
}
1149
1158
}
1150
1159
1151
- fn calc_result ( desc : & TestDesc , task_succeeded : bool ) -> TestResult {
1152
- if task_succeeded {
1153
- if desc. should_fail { TrFailed }
1154
- else { TrOk }
1155
- } else {
1156
- if desc. should_fail { TrOk }
1157
- else { TrFailed }
1160
+ fn calc_result ( desc : & TestDesc , task_result : Result < ( ) , Box < Any +Send > > ) -> TestResult {
1161
+ match ( & desc. should_fail , task_result) {
1162
+ ( & ShouldFail :: No , Ok ( ( ) ) ) |
1163
+ ( & ShouldFail :: Yes ( None ) , Err ( _) ) => TrOk ,
1164
+ ( & ShouldFail :: Yes ( Some ( msg) ) , Err ( ref err) )
1165
+ if err. downcast_ref :: < String > ( )
1166
+ . map ( |e| & * * e)
1167
+ . or_else ( || err. downcast_ref :: < & ' static str > ( ) . map ( |e| * e) )
1168
+ . map ( |e| e. contains ( msg) )
1169
+ . unwrap_or ( false ) => TrOk ,
1170
+ _ => TrFailed ,
1158
1171
}
1159
1172
}
1160
1173
@@ -1437,7 +1450,7 @@ mod tests {
1437
1450
TestDesc , TestDescAndFn , TestOpts , run_test,
1438
1451
Metric , MetricMap , MetricAdded , MetricRemoved ,
1439
1452
Improvement , Regression , LikelyNoise ,
1440
- StaticTestName , DynTestName , DynTestFn } ;
1453
+ StaticTestName , DynTestName , DynTestFn , ShouldFail } ;
1441
1454
use std:: io:: TempDir ;
1442
1455
1443
1456
#[ test]
@@ -1447,7 +1460,7 @@ mod tests {
1447
1460
desc : TestDesc {
1448
1461
name : StaticTestName ( "whatever" ) ,
1449
1462
ignore : true ,
1450
- should_fail : false
1463
+ should_fail : ShouldFail :: No ,
1451
1464
} ,
1452
1465
testfn : DynTestFn ( proc ( ) f( ) ) ,
1453
1466
} ;
@@ -1464,7 +1477,7 @@ mod tests {
1464
1477
desc : TestDesc {
1465
1478
name : StaticTestName ( "whatever" ) ,
1466
1479
ignore : true ,
1467
- should_fail : false
1480
+ should_fail : ShouldFail :: No ,
1468
1481
} ,
1469
1482
testfn : DynTestFn ( proc ( ) f( ) ) ,
1470
1483
} ;
@@ -1481,7 +1494,24 @@ mod tests {
1481
1494
desc : TestDesc {
1482
1495
name : StaticTestName ( "whatever" ) ,
1483
1496
ignore : false ,
1484
- should_fail : true
1497
+ should_fail : ShouldFail :: Yes ( None )
1498
+ } ,
1499
+ testfn : DynTestFn ( proc ( ) f( ) ) ,
1500
+ } ;
1501
+ let ( tx, rx) = channel ( ) ;
1502
+ run_test ( & TestOpts :: new ( ) , false , desc, tx) ;
1503
+ let ( _, res, _) = rx. recv ( ) ;
1504
+ assert ! ( res == TrOk ) ;
1505
+ }
1506
+
1507
+ #[ test]
1508
+ fn test_should_fail_good_message ( ) {
1509
+ fn f ( ) { panic ! ( "an error message" ) ; }
1510
+ let desc = TestDescAndFn {
1511
+ desc : TestDesc {
1512
+ name : StaticTestName ( "whatever" ) ,
1513
+ ignore : false ,
1514
+ should_fail : ShouldFail :: Yes ( Some ( "error message" ) )
1485
1515
} ,
1486
1516
testfn : DynTestFn ( proc ( ) f( ) ) ,
1487
1517
} ;
@@ -1491,14 +1521,31 @@ mod tests {
1491
1521
assert ! ( res == TrOk ) ;
1492
1522
}
1493
1523
1524
+ #[ test]
1525
+ fn test_should_fail_bad_message ( ) {
1526
+ fn f ( ) { panic ! ( "an error message" ) ; }
1527
+ let desc = TestDescAndFn {
1528
+ desc : TestDesc {
1529
+ name : StaticTestName ( "whatever" ) ,
1530
+ ignore : false ,
1531
+ should_fail : ShouldFail :: Yes ( Some ( "foobar" ) )
1532
+ } ,
1533
+ testfn : DynTestFn ( proc ( ) f( ) ) ,
1534
+ } ;
1535
+ let ( tx, rx) = channel ( ) ;
1536
+ run_test ( & TestOpts :: new ( ) , false , desc, tx) ;
1537
+ let ( _, res, _) = rx. recv ( ) ;
1538
+ assert ! ( res == TrFailed ) ;
1539
+ }
1540
+
1494
1541
#[ test]
1495
1542
fn test_should_fail_but_succeeds ( ) {
1496
1543
fn f ( ) { }
1497
1544
let desc = TestDescAndFn {
1498
1545
desc : TestDesc {
1499
1546
name : StaticTestName ( "whatever" ) ,
1500
1547
ignore : false ,
1501
- should_fail : true
1548
+ should_fail : ShouldFail :: Yes ( None )
1502
1549
} ,
1503
1550
testfn : DynTestFn ( proc ( ) f( ) ) ,
1504
1551
} ;
@@ -1544,15 +1591,15 @@ mod tests {
1544
1591
desc: TestDesc {
1545
1592
name: StaticTestName ( "1" ) ,
1546
1593
ignore: true ,
1547
- should_fail: false ,
1594
+ should_fail: ShouldFail :: No ,
1548
1595
} ,
1549
1596
testfn: DynTestFn ( proc( ) { } ) ,
1550
1597
} ,
1551
1598
TestDescAndFn {
1552
1599
desc: TestDesc {
1553
1600
name: StaticTestName ( "2" ) ,
1554
1601
ignore: false ,
1555
- should_fail: false
1602
+ should_fail: ShouldFail :: No ,
1556
1603
} ,
1557
1604
testfn: DynTestFn ( proc( ) { } ) ,
1558
1605
} ) ;
@@ -1588,7 +1635,7 @@ mod tests {
1588
1635
desc : TestDesc {
1589
1636
name : DynTestName ( ( * name) . clone ( ) ) ,
1590
1637
ignore : false ,
1591
- should_fail : false
1638
+ should_fail : ShouldFail :: No ,
1592
1639
} ,
1593
1640
testfn : DynTestFn ( testfn) ,
1594
1641
} ;
@@ -1629,7 +1676,7 @@ mod tests {
1629
1676
desc : TestDesc {
1630
1677
name : DynTestName ( name. to_string ( ) ) ,
1631
1678
ignore : false ,
1632
- should_fail : false
1679
+ should_fail : ShouldFail :: No ,
1633
1680
} ,
1634
1681
testfn : DynTestFn ( test_fn)
1635
1682
}
0 commit comments