Sort tests at compile time, not at startup Recently, another Miri user was trying to run `cargo miri test` on the crate `iced-x86` with `--features=code_asm,mvex`. This configuration has a startup time of ~18 minutes. That's ~18 minutes before any tests even start to run. The fact that this crate has over 26,000 tests and Miri is slow makes a lot of code which is otherwise a bit sloppy but fine into a huge runtime issue. Sorting the tests when the test harness is created instead of at startup time knocks just under 4 minutes out of those ~18 minutes. I have ways to remove most of the rest of the startup time, but this change requires coordinating changes of both the compiler and libtest, so I'm sending it separately. (except for doctests, because there is no compile-time harness)
842 lines
25 KiB
Rust
842 lines
25 KiB
Rust
use super::*;
|
|
|
|
use crate::{
|
|
bench::Bencher,
|
|
console::OutputLocation,
|
|
formatters::PrettyFormatter,
|
|
options::OutputFormat,
|
|
test::{
|
|
filter_tests,
|
|
parse_opts,
|
|
run_test,
|
|
DynTestFn,
|
|
DynTestName,
|
|
MetricMap,
|
|
RunIgnored,
|
|
RunStrategy,
|
|
ShouldPanic,
|
|
StaticTestName,
|
|
TestDesc,
|
|
TestDescAndFn,
|
|
TestOpts,
|
|
TrIgnored,
|
|
TrOk,
|
|
// FIXME (introduced by #65251)
|
|
// ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions,
|
|
// TestType, TrFailedMsg, TrIgnored, TrOk,
|
|
},
|
|
time::{TestTimeOptions, TimeThreshold},
|
|
};
|
|
use std::sync::mpsc::channel;
|
|
use std::time::Duration;
|
|
|
|
impl TestOpts {
|
|
fn new() -> TestOpts {
|
|
TestOpts {
|
|
list: false,
|
|
filters: vec![],
|
|
filter_exact: false,
|
|
force_run_in_process: false,
|
|
exclude_should_panic: false,
|
|
run_ignored: RunIgnored::No,
|
|
run_tests: false,
|
|
bench_benchmarks: false,
|
|
logfile: None,
|
|
nocapture: false,
|
|
color: AutoColor,
|
|
format: OutputFormat::Pretty,
|
|
shuffle: false,
|
|
shuffle_seed: None,
|
|
test_threads: None,
|
|
skip: vec![],
|
|
time_options: None,
|
|
options: Options::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
|
vec![
|
|
TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("1"),
|
|
ignore: true,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
|
},
|
|
TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("2"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
|
},
|
|
]
|
|
}
|
|
|
|
#[test]
|
|
pub fn do_not_run_ignored_tests() {
|
|
fn f() -> Result<(), String> {
|
|
panic!();
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: true,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_ne!(result, TrOk);
|
|
}
|
|
|
|
#[test]
|
|
pub fn ignored_tests_result_in_ignored() {
|
|
fn f() -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: true,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(result, TrIgnored);
|
|
}
|
|
|
|
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
|
#[test]
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
fn test_should_panic() {
|
|
fn f() -> Result<(), String> {
|
|
panic!();
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::Yes,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(result, TrOk);
|
|
}
|
|
|
|
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
|
#[test]
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
fn test_should_panic_good_message() {
|
|
fn f() -> Result<(), String> {
|
|
panic!("an error message");
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::YesWithMessage("error message"),
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(result, TrOk);
|
|
}
|
|
|
|
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
|
#[test]
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
fn test_should_panic_bad_message() {
|
|
use crate::tests::TrFailedMsg;
|
|
fn f() -> Result<(), String> {
|
|
panic!("an error message");
|
|
}
|
|
let expected = "foobar";
|
|
let failed_msg = r#"panic did not contain expected string
|
|
panic message: `"an error message"`,
|
|
expected substring: `"foobar"`"#;
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::YesWithMessage(expected),
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(result, TrFailedMsg(failed_msg.to_string()));
|
|
}
|
|
|
|
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
|
#[test]
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
fn test_should_panic_non_string_message_type() {
|
|
use crate::tests::TrFailedMsg;
|
|
use std::any::TypeId;
|
|
fn f() -> Result<(), String> {
|
|
std::panic::panic_any(1i32);
|
|
}
|
|
let expected = "foobar";
|
|
let failed_msg = format!(
|
|
r#"expected panic with string value,
|
|
found non-string value: `{:?}`
|
|
expected substring: `"foobar"`"#,
|
|
TypeId::of::<i32>()
|
|
);
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::YesWithMessage(expected),
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(result, TrFailedMsg(failed_msg));
|
|
}
|
|
|
|
// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
|
|
#[test]
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
fn test_should_panic_but_succeeds() {
|
|
let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")];
|
|
|
|
for &should_panic in should_panic_variants.iter() {
|
|
fn f() -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
run_test(
|
|
&TestOpts::new(),
|
|
false,
|
|
TestId(0),
|
|
desc,
|
|
RunStrategy::InProcess,
|
|
tx,
|
|
Concurrent::No,
|
|
);
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(
|
|
result,
|
|
TrFailedMsg("test did not panic as expected".to_string()),
|
|
"should_panic == {:?}",
|
|
should_panic
|
|
);
|
|
}
|
|
}
|
|
|
|
fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
|
|
fn f() -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
let time_options = if report_time { Some(TestTimeOptions::default()) } else { None };
|
|
|
|
let test_opts = TestOpts { time_options, ..TestOpts::new() };
|
|
let (tx, rx) = channel();
|
|
run_test(&test_opts, false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let exec_time = rx.recv().unwrap().exec_time;
|
|
exec_time
|
|
}
|
|
|
|
#[test]
|
|
fn test_should_not_report_time() {
|
|
let exec_time = report_time_test_template(false);
|
|
assert!(exec_time.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_should_report_time() {
|
|
let exec_time = report_time_test_template(true);
|
|
assert!(exec_time.is_some());
|
|
}
|
|
|
|
fn time_test_failure_template(test_type: TestType) -> TestResult {
|
|
fn f() -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type,
|
|
},
|
|
testfn: DynTestFn(Box::new(f)),
|
|
};
|
|
// `Default` will initialize all the thresholds to 0 milliseconds.
|
|
let mut time_options = TestTimeOptions::default();
|
|
time_options.error_on_excess = true;
|
|
|
|
let test_opts = TestOpts { time_options: Some(time_options), ..TestOpts::new() };
|
|
let (tx, rx) = channel();
|
|
run_test(&test_opts, false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
|
|
let result = rx.recv().unwrap().result;
|
|
|
|
result
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_on_exceed() {
|
|
let types = [TestType::UnitTest, TestType::IntegrationTest, TestType::DocTest];
|
|
|
|
for test_type in types.iter() {
|
|
let result = time_test_failure_template(*test_type);
|
|
|
|
assert_eq!(result, TestResult::TrTimedFail);
|
|
}
|
|
|
|
// Check that for unknown tests thresholds aren't applied.
|
|
let result = time_test_failure_template(TestType::Unknown);
|
|
assert_eq!(result, TestResult::TrOk);
|
|
}
|
|
|
|
fn typed_test_desc(test_type: TestType) -> TestDesc {
|
|
TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type,
|
|
}
|
|
}
|
|
|
|
fn test_exec_time(millis: u64) -> TestExecTime {
|
|
TestExecTime(Duration::from_millis(millis))
|
|
}
|
|
|
|
#[test]
|
|
fn test_time_options_threshold() {
|
|
let unit = TimeThreshold::new(Duration::from_millis(50), Duration::from_millis(100));
|
|
let integration = TimeThreshold::new(Duration::from_millis(500), Duration::from_millis(1000));
|
|
let doc = TimeThreshold::new(Duration::from_millis(5000), Duration::from_millis(10000));
|
|
|
|
let options = TestTimeOptions {
|
|
error_on_excess: false,
|
|
unit_threshold: unit.clone(),
|
|
integration_threshold: integration.clone(),
|
|
doctest_threshold: doc.clone(),
|
|
};
|
|
|
|
let test_vector = [
|
|
(TestType::UnitTest, unit.warn.as_millis() - 1, false, false),
|
|
(TestType::UnitTest, unit.warn.as_millis(), true, false),
|
|
(TestType::UnitTest, unit.critical.as_millis(), true, true),
|
|
(TestType::IntegrationTest, integration.warn.as_millis() - 1, false, false),
|
|
(TestType::IntegrationTest, integration.warn.as_millis(), true, false),
|
|
(TestType::IntegrationTest, integration.critical.as_millis(), true, true),
|
|
(TestType::DocTest, doc.warn.as_millis() - 1, false, false),
|
|
(TestType::DocTest, doc.warn.as_millis(), true, false),
|
|
(TestType::DocTest, doc.critical.as_millis(), true, true),
|
|
];
|
|
|
|
for (test_type, time, expected_warn, expected_critical) in test_vector.iter() {
|
|
let test_desc = typed_test_desc(*test_type);
|
|
let exec_time = test_exec_time(*time as u64);
|
|
|
|
assert_eq!(options.is_warn(&test_desc, &exec_time), *expected_warn);
|
|
assert_eq!(options.is_critical(&test_desc, &exec_time), *expected_critical);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn parse_ignored_flag() {
|
|
let args = vec!["progname".to_string(), "filter".to_string(), "--ignored".to_string()];
|
|
let opts = parse_opts(&args).unwrap().unwrap();
|
|
assert_eq!(opts.run_ignored, RunIgnored::Only);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_show_output_flag() {
|
|
let args = vec!["progname".to_string(), "filter".to_string(), "--show-output".to_string()];
|
|
let opts = parse_opts(&args).unwrap().unwrap();
|
|
assert!(opts.options.display_output);
|
|
}
|
|
|
|
#[test]
|
|
fn parse_include_ignored_flag() {
|
|
let args = vec!["progname".to_string(), "filter".to_string(), "--include-ignored".to_string()];
|
|
let opts = parse_opts(&args).unwrap().unwrap();
|
|
assert_eq!(opts.run_ignored, RunIgnored::Yes);
|
|
}
|
|
|
|
#[test]
|
|
pub fn filter_for_ignored_option() {
|
|
// When we run ignored tests the test filter should filter out all the
|
|
// unignored tests and flip the ignore flag on the rest to false
|
|
|
|
let mut opts = TestOpts::new();
|
|
opts.run_tests = true;
|
|
opts.run_ignored = RunIgnored::Only;
|
|
|
|
let tests = one_ignored_one_unignored_test();
|
|
let filtered = filter_tests(&opts, tests);
|
|
|
|
assert_eq!(filtered.len(), 1);
|
|
assert_eq!(filtered[0].desc.name.to_string(), "1");
|
|
assert!(!filtered[0].desc.ignore);
|
|
}
|
|
|
|
#[test]
|
|
pub fn run_include_ignored_option() {
|
|
// When we "--include-ignored" tests, the ignore flag should be set to false on
|
|
// all tests and no test filtered out
|
|
|
|
let mut opts = TestOpts::new();
|
|
opts.run_tests = true;
|
|
opts.run_ignored = RunIgnored::Yes;
|
|
|
|
let tests = one_ignored_one_unignored_test();
|
|
let filtered = filter_tests(&opts, tests);
|
|
|
|
assert_eq!(filtered.len(), 2);
|
|
assert!(!filtered[0].desc.ignore);
|
|
assert!(!filtered[1].desc.ignore);
|
|
}
|
|
|
|
#[test]
|
|
pub fn exclude_should_panic_option() {
|
|
let mut opts = TestOpts::new();
|
|
opts.run_tests = true;
|
|
opts.exclude_should_panic = true;
|
|
|
|
let mut tests = one_ignored_one_unignored_test();
|
|
tests.push(TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("3"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::Yes,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
|
});
|
|
|
|
let filtered = filter_tests(&opts, tests);
|
|
|
|
assert_eq!(filtered.len(), 2);
|
|
assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No));
|
|
}
|
|
|
|
#[test]
|
|
pub fn exact_filter_match() {
|
|
fn tests() -> Vec<TestDescAndFn> {
|
|
["base", "base::test", "base::test1", "base::test2"]
|
|
.into_iter()
|
|
.map(|name| TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName(name),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
let substr =
|
|
filter_tests(&TestOpts { filters: vec!["base".into()], ..TestOpts::new() }, tests());
|
|
assert_eq!(substr.len(), 4);
|
|
|
|
let substr =
|
|
filter_tests(&TestOpts { filters: vec!["bas".into()], ..TestOpts::new() }, tests());
|
|
assert_eq!(substr.len(), 4);
|
|
|
|
let substr =
|
|
filter_tests(&TestOpts { filters: vec!["::test".into()], ..TestOpts::new() }, tests());
|
|
assert_eq!(substr.len(), 3);
|
|
|
|
let substr =
|
|
filter_tests(&TestOpts { filters: vec!["base::test".into()], ..TestOpts::new() }, tests());
|
|
assert_eq!(substr.len(), 3);
|
|
|
|
let substr = filter_tests(
|
|
&TestOpts { filters: vec!["test1".into(), "test2".into()], ..TestOpts::new() },
|
|
tests(),
|
|
);
|
|
assert_eq!(substr.len(), 2);
|
|
|
|
let exact = filter_tests(
|
|
&TestOpts { filters: vec!["base".into()], filter_exact: true, ..TestOpts::new() },
|
|
tests(),
|
|
);
|
|
assert_eq!(exact.len(), 1);
|
|
|
|
let exact = filter_tests(
|
|
&TestOpts { filters: vec!["bas".into()], filter_exact: true, ..TestOpts::new() },
|
|
tests(),
|
|
);
|
|
assert_eq!(exact.len(), 0);
|
|
|
|
let exact = filter_tests(
|
|
&TestOpts { filters: vec!["::test".into()], filter_exact: true, ..TestOpts::new() },
|
|
tests(),
|
|
);
|
|
assert_eq!(exact.len(), 0);
|
|
|
|
let exact = filter_tests(
|
|
&TestOpts { filters: vec!["base::test".into()], filter_exact: true, ..TestOpts::new() },
|
|
tests(),
|
|
);
|
|
assert_eq!(exact.len(), 1);
|
|
|
|
let exact = filter_tests(
|
|
&TestOpts {
|
|
filters: vec!["base".into(), "base::test".into()],
|
|
filter_exact: true,
|
|
..TestOpts::new()
|
|
},
|
|
tests(),
|
|
);
|
|
assert_eq!(exact.len(), 2);
|
|
}
|
|
|
|
fn sample_tests() -> Vec<TestDescAndFn> {
|
|
let names = vec![
|
|
"sha1::test".to_string(),
|
|
"isize::test_to_str".to_string(),
|
|
"isize::test_pow".to_string(),
|
|
"test::do_not_run_ignored_tests".to_string(),
|
|
"test::ignored_tests_result_in_ignored".to_string(),
|
|
"test::first_free_arg_should_be_a_filter".to_string(),
|
|
"test::parse_ignored_flag".to_string(),
|
|
"test::parse_include_ignored_flag".to_string(),
|
|
"test::filter_for_ignored_option".to_string(),
|
|
"test::run_include_ignored_option".to_string(),
|
|
"test::sort_tests".to_string(),
|
|
];
|
|
fn testfn() -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
let mut tests = Vec::new();
|
|
for name in &names {
|
|
let test = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: DynTestName((*name).clone()),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynTestFn(Box::new(testfn)),
|
|
};
|
|
tests.push(test);
|
|
}
|
|
tests
|
|
}
|
|
|
|
#[test]
|
|
pub fn shuffle_tests() {
|
|
let mut opts = TestOpts::new();
|
|
opts.shuffle = true;
|
|
|
|
let shuffle_seed = get_shuffle_seed(&opts).unwrap();
|
|
|
|
let left =
|
|
sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::<Vec<_>>();
|
|
let mut right =
|
|
sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::<Vec<_>>();
|
|
|
|
assert!(left.iter().zip(&right).all(|(a, b)| a.1.desc.name == b.1.desc.name));
|
|
|
|
helpers::shuffle::shuffle_tests(shuffle_seed, right.as_mut_slice());
|
|
|
|
assert!(left.iter().zip(right).any(|(a, b)| a.1.desc.name != b.1.desc.name));
|
|
}
|
|
|
|
#[test]
|
|
pub fn shuffle_tests_with_seed() {
|
|
let mut opts = TestOpts::new();
|
|
opts.shuffle = true;
|
|
|
|
let shuffle_seed = get_shuffle_seed(&opts).unwrap();
|
|
|
|
let mut left =
|
|
sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::<Vec<_>>();
|
|
let mut right =
|
|
sample_tests().into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::<Vec<_>>();
|
|
|
|
helpers::shuffle::shuffle_tests(shuffle_seed, left.as_mut_slice());
|
|
helpers::shuffle::shuffle_tests(shuffle_seed, right.as_mut_slice());
|
|
|
|
assert!(left.iter().zip(right).all(|(a, b)| a.1.desc.name == b.1.desc.name));
|
|
}
|
|
|
|
#[test]
|
|
pub fn order_depends_on_more_than_seed() {
|
|
let mut opts = TestOpts::new();
|
|
opts.shuffle = true;
|
|
|
|
let shuffle_seed = get_shuffle_seed(&opts).unwrap();
|
|
|
|
let mut left_tests = sample_tests();
|
|
let mut right_tests = sample_tests();
|
|
|
|
left_tests.pop();
|
|
right_tests.remove(0);
|
|
|
|
let mut left =
|
|
left_tests.into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::<Vec<_>>();
|
|
let mut right =
|
|
right_tests.into_iter().enumerate().map(|(i, e)| (TestId(i), e)).collect::<Vec<_>>();
|
|
|
|
assert_eq!(left.len(), right.len());
|
|
|
|
assert!(left.iter().zip(&right).all(|(a, b)| a.0 == b.0));
|
|
|
|
helpers::shuffle::shuffle_tests(shuffle_seed, left.as_mut_slice());
|
|
helpers::shuffle::shuffle_tests(shuffle_seed, right.as_mut_slice());
|
|
|
|
assert!(left.iter().zip(right).any(|(a, b)| a.0 != b.0));
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_metricmap_compare() {
|
|
let mut m1 = MetricMap::new();
|
|
let mut m2 = MetricMap::new();
|
|
m1.insert_metric("in-both-noise", 1000.0, 200.0);
|
|
m2.insert_metric("in-both-noise", 1100.0, 200.0);
|
|
|
|
m1.insert_metric("in-first-noise", 1000.0, 2.0);
|
|
m2.insert_metric("in-second-noise", 1000.0, 2.0);
|
|
|
|
m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0);
|
|
m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0);
|
|
|
|
m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0);
|
|
m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0);
|
|
|
|
m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0);
|
|
m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0);
|
|
|
|
m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0);
|
|
m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0);
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_bench_once_no_iter() {
|
|
fn f(_: &mut Bencher) -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
bench::run_once(f).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_bench_once_iter() {
|
|
fn f(b: &mut Bencher) -> Result<(), String> {
|
|
b.iter(|| {});
|
|
Ok(())
|
|
}
|
|
bench::run_once(f).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_bench_no_iter() {
|
|
fn f(_: &mut Bencher) -> Result<(), String> {
|
|
Ok(())
|
|
}
|
|
|
|
let (tx, rx) = channel();
|
|
|
|
let desc = TestDesc {
|
|
name: StaticTestName("f"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
};
|
|
|
|
crate::bench::benchmark(TestId(0), desc, tx, true, f);
|
|
rx.recv().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
pub fn test_bench_iter() {
|
|
fn f(b: &mut Bencher) -> Result<(), String> {
|
|
b.iter(|| {});
|
|
Ok(())
|
|
}
|
|
|
|
let (tx, rx) = channel();
|
|
|
|
let desc = TestDesc {
|
|
name: StaticTestName("f"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
};
|
|
|
|
crate::bench::benchmark(TestId(0), desc, tx, true, f);
|
|
rx.recv().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn should_sort_failures_before_printing_them() {
|
|
let test_a = TestDesc {
|
|
name: StaticTestName("a"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
};
|
|
|
|
let test_b = TestDesc {
|
|
name: StaticTestName("b"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
};
|
|
|
|
let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None);
|
|
|
|
let st = console::ConsoleTestState {
|
|
log_out: None,
|
|
total: 0,
|
|
passed: 0,
|
|
failed: 0,
|
|
ignored: 0,
|
|
filtered_out: 0,
|
|
measured: 0,
|
|
exec_time: None,
|
|
metrics: MetricMap::new(),
|
|
failures: vec![(test_b, Vec::new()), (test_a, Vec::new())],
|
|
options: Options::new(),
|
|
not_failures: Vec::new(),
|
|
time_failures: Vec::new(),
|
|
};
|
|
|
|
out.write_failures(&st).unwrap();
|
|
let s = match out.output_location() {
|
|
&OutputLocation::Raw(ref m) => String::from_utf8_lossy(&m[..]),
|
|
&OutputLocation::Pretty(_) => unreachable!(),
|
|
};
|
|
|
|
let apos = s.find("a").unwrap();
|
|
let bpos = s.find("b").unwrap();
|
|
assert!(apos < bpos);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(target_os = "emscripten"))]
|
|
fn test_dyn_bench_returning_err_fails_when_run_as_test() {
|
|
fn f(_: &mut Bencher) -> Result<(), String> {
|
|
Result::Err("An error".into())
|
|
}
|
|
let desc = TestDescAndFn {
|
|
desc: TestDesc {
|
|
name: StaticTestName("whatever"),
|
|
ignore: false,
|
|
ignore_message: None,
|
|
should_panic: ShouldPanic::No,
|
|
compile_fail: false,
|
|
no_run: false,
|
|
test_type: TestType::Unknown,
|
|
},
|
|
testfn: DynBenchFn(Box::new(f)),
|
|
};
|
|
let (tx, rx) = channel();
|
|
let notify = move |event: TestEvent| {
|
|
if let TestEvent::TeResult(result) = event {
|
|
tx.send(result).unwrap();
|
|
}
|
|
Ok(())
|
|
};
|
|
run_tests(&TestOpts { run_tests: true, ..TestOpts::new() }, vec![desc], notify).unwrap();
|
|
let result = rx.recv().unwrap().result;
|
|
assert_eq!(result, TrFailed);
|
|
}
|