diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /library/test | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/test')
-rw-r--r-- | library/test/src/console.rs | 2 | ||||
-rw-r--r-- | library/test/src/lib.rs | 206 | ||||
-rw-r--r-- | library/test/src/tests.rs | 5 | ||||
-rw-r--r-- | library/test/src/types.rs | 80 |
4 files changed, 175 insertions, 118 deletions
diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 7eee4ca23..bbeb944e8 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -199,7 +199,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Res let TestDescAndFn { desc, testfn } = test; let fntype = match testfn { - StaticTestFn(..) | DynTestFn(..) => { + StaticTestFn(..) | DynTestFn(..) | StaticBenchAsTestFn(..) | DynBenchAsTestFn(..) => { st.tests += 1; "test" } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index e76d6716b..b40b6009e 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -92,6 +92,7 @@ use time::TestExecTime; const ERROR_EXIT_CODE: i32 = 101; const SECONDARY_TEST_INVOKER_VAR: &str = "__RUST_TEST_INVOKE"; +const SECONDARY_TEST_BENCH_BENCHMARKS_VAR: &str = "__RUST_TEST_BENCH_BENCHMARKS"; // The default console test runner. It accepts the command line // arguments and a vector of test_descs. @@ -171,18 +172,32 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { // will then exit the process. if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) { env::remove_var(SECONDARY_TEST_INVOKER_VAR); + + // Convert benchmarks to tests if we're not benchmarking. + let mut tests = tests.iter().map(make_owned_test).collect::<Vec<_>>(); + if env::var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR).is_ok() { + env::remove_var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR); + } else { + tests = convert_benchmarks_to_tests(tests); + }; + let test = tests - .iter() + .into_iter() .filter(|test| test.desc.name.as_slice() == name) - .map(make_owned_test) .next() .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{name}'")); let TestDescAndFn { desc, testfn } = test; - let testfn = match testfn { - StaticTestFn(f) => f, - _ => panic!("only static tests are supported"), - }; - run_test_in_spawned_subprocess(desc, Box::new(testfn)); + match testfn.into_runnable() { + Runnable::Test(runnable_test) => { + if runnable_test.is_dynamic() { + panic!("only static tests are supported"); + } + run_test_in_spawned_subprocess(desc, runnable_test); + } + Runnable::Bench(_) => { + panic!("benchmarks should not be executed into child processes") + } + } } let args = env::args().collect::<Vec<_>>(); @@ -234,16 +249,6 @@ impl FilteredTests { self.tests.push((TestId(self.next_id), test)); self.next_id += 1; } - fn add_bench_as_test( - &mut self, - desc: TestDesc, - benchfn: impl Fn(&mut Bencher) -> Result<(), String> + Send + 'static, - ) { - let testfn = DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) - })); - self.add_test(desc, testfn); - } fn total_len(&self) -> usize { self.tests.len() + self.benches.len() } @@ -301,14 +306,14 @@ where if opts.bench_benchmarks { filtered.add_bench(desc, DynBenchFn(benchfn)); } else { - filtered.add_bench_as_test(desc, benchfn); + filtered.add_test(desc, DynBenchAsTestFn(benchfn)); } } StaticBenchFn(benchfn) => { if opts.bench_benchmarks { filtered.add_bench(desc, StaticBenchFn(benchfn)); } else { - filtered.add_bench_as_test(desc, benchfn); + filtered.add_test(desc, StaticBenchAsTestFn(benchfn)); } } testfn => { @@ -519,12 +524,8 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd .into_iter() .map(|x| { let testfn = match x.testfn { - DynBenchFn(benchfn) => DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) - })), - StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) - })), + DynBenchFn(benchfn) => DynBenchAsTestFn(benchfn), + StaticBenchFn(benchfn) => StaticBenchAsTestFn(benchfn), f => f, }; TestDescAndFn { desc: x.desc, testfn } @@ -553,99 +554,69 @@ pub fn run_test( return None; } - struct TestRunOpts { - pub strategy: RunStrategy, - pub nocapture: bool, - pub time: Option<time::TestTimeOptions>, - } + match testfn.into_runnable() { + Runnable::Test(runnable_test) => { + if runnable_test.is_dynamic() { + match strategy { + RunStrategy::InProcess => (), + _ => panic!("Cannot run dynamic test fn out-of-process"), + }; + } - fn run_test_inner( - id: TestId, - desc: TestDesc, - monitor_ch: Sender<CompletedTest>, - testfn: Box<dyn FnOnce() -> Result<(), String> + Send>, - opts: TestRunOpts, - ) -> Option<thread::JoinHandle<()>> { - let name = desc.name.clone(); - - let runtest = move || match opts.strategy { - RunStrategy::InProcess => run_test_in_process( - id, - desc, - opts.nocapture, - opts.time.is_some(), - testfn, - monitor_ch, - opts.time, - ), - RunStrategy::SpawnPrimary => spawn_test_subprocess( - id, - desc, - opts.nocapture, - opts.time.is_some(), - monitor_ch, - opts.time, - ), - }; + let name = desc.name.clone(); + let nocapture = opts.nocapture; + let time_options = opts.time_options; + let bench_benchmarks = opts.bench_benchmarks; + + let runtest = move || match strategy { + RunStrategy::InProcess => run_test_in_process( + id, + desc, + nocapture, + time_options.is_some(), + runnable_test, + monitor_ch, + time_options, + ), + RunStrategy::SpawnPrimary => spawn_test_subprocess( + id, + desc, + nocapture, + time_options.is_some(), + monitor_ch, + time_options, + bench_benchmarks, + ), + }; - // If the platform is single-threaded we're just going to run - // the test synchronously, regardless of the concurrency - // level. - let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm"); - if supports_threads { - let cfg = thread::Builder::new().name(name.as_slice().to_owned()); - let mut runtest = Arc::new(Mutex::new(Some(runtest))); - let runtest2 = runtest.clone(); - match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) { - Ok(handle) => Some(handle), - Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - // `ErrorKind::WouldBlock` means hitting the thread limit on some - // platforms, so run the test synchronously here instead. - Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()(); - None + // If the platform is single-threaded we're just going to run + // the test synchronously, regardless of the concurrency + // level. + let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm"); + if supports_threads { + let cfg = thread::Builder::new().name(name.as_slice().to_owned()); + let mut runtest = Arc::new(Mutex::new(Some(runtest))); + let runtest2 = runtest.clone(); + match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) { + Ok(handle) => Some(handle), + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // `ErrorKind::WouldBlock` means hitting the thread limit on some + // platforms, so run the test synchronously here instead. + Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()(); + None + } + Err(e) => panic!("failed to spawn thread to run test: {e}"), } - Err(e) => panic!("failed to spawn thread to run test: {e}"), + } else { + runtest(); + None } - } else { - runtest(); - None } - } - - let test_run_opts = - TestRunOpts { strategy, nocapture: opts.nocapture, time: opts.time_options }; - - match testfn { - DynBenchFn(benchfn) => { + Runnable::Bench(runnable_bench) => { // Benchmarks aren't expected to panic, so we run them all in-process. - crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn); + runnable_bench.run(id, &desc, &monitor_ch, opts.nocapture); None } - StaticBenchFn(benchfn) => { - // Benchmarks aren't expected to panic, so we run them all in-process. - crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn); - None - } - DynTestFn(f) => { - match strategy { - RunStrategy::InProcess => (), - _ => panic!("Cannot run dynamic test fn out-of-process"), - }; - run_test_inner( - id, - desc, - monitor_ch, - Box::new(move || __rust_begin_short_backtrace(f)), - test_run_opts, - ) - } - StaticTestFn(f) => run_test_inner( - id, - desc, - monitor_ch, - Box::new(move || __rust_begin_short_backtrace(f)), - test_run_opts, - ), } } @@ -663,7 +634,7 @@ fn run_test_in_process( desc: TestDesc, nocapture: bool, report_time: bool, - testfn: Box<dyn FnOnce() -> Result<(), String> + Send>, + runnable_test: RunnableTest, monitor_ch: Sender<CompletedTest>, time_opts: Option<time::TestTimeOptions>, ) { @@ -675,7 +646,7 @@ fn run_test_in_process( } let start = report_time.then(Instant::now); - let result = fold_err(catch_unwind(AssertUnwindSafe(testfn))); + let result = fold_err(catch_unwind(AssertUnwindSafe(|| runnable_test.run()))); let exec_time = start.map(|start| { let duration = start.elapsed(); TestExecTime(duration) @@ -712,6 +683,7 @@ fn spawn_test_subprocess( report_time: bool, monitor_ch: Sender<CompletedTest>, time_opts: Option<time::TestTimeOptions>, + bench_benchmarks: bool, ) { let (result, test_output, exec_time) = (|| { let args = env::args().collect::<Vec<_>>(); @@ -719,6 +691,9 @@ fn spawn_test_subprocess( let mut command = Command::new(current_exe); command.env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice()); + if bench_benchmarks { + command.env(SECONDARY_TEST_BENCH_BENCHMARKS_VAR, "1"); + } if nocapture { command.stdout(process::Stdio::inherit()); command.stderr(process::Stdio::inherit()); @@ -760,10 +735,7 @@ fn spawn_test_subprocess( monitor_ch.send(message).unwrap(); } -fn run_test_in_spawned_subprocess( - desc: TestDesc, - testfn: Box<dyn FnOnce() -> Result<(), String> + Send>, -) -> ! { +fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! { let builtin_panic_hook = panic::take_hook(); let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| { let test_result = match panic_info { @@ -789,7 +761,7 @@ fn run_test_in_spawned_subprocess( }); let record_result2 = record_result.clone(); panic::set_hook(Box::new(move |info| record_result2(Some(info)))); - if let Err(message) = testfn() { + if let Err(message) = runnable_test.run() { panic!("{}", message); } record_result(None); diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index c34583e69..4ef18b14f 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -154,6 +154,7 @@ pub fn ignored_tests_result_in_ignored() { // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic() { fn f() -> Result<(), String> { panic!(); @@ -184,6 +185,7 @@ fn test_should_panic() { // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_good_message() { fn f() -> Result<(), String> { panic!("an error message"); @@ -214,6 +216,7 @@ fn test_should_panic_good_message() { // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_bad_message() { use crate::tests::TrFailedMsg; fn f() -> Result<(), String> { @@ -249,6 +252,7 @@ fn test_should_panic_bad_message() { // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_non_string_message_type() { use crate::tests::TrFailedMsg; use std::any::TypeId; @@ -288,6 +292,7 @@ fn test_should_panic_non_string_message_type() { // FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251) #[test] #[cfg(not(target_os = "emscripten"))] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_should_panic_but_succeeds() { let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")]; diff --git a/library/test/src/types.rs b/library/test/src/types.rs index e79914dbf..504ceee7f 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -2,8 +2,11 @@ use std::borrow::Cow; use std::fmt; +use std::sync::mpsc::Sender; +use super::__rust_begin_short_backtrace; use super::bench::Bencher; +use super::event::CompletedTest; use super::options; pub use NamePadding::*; @@ -82,8 +85,10 @@ impl fmt::Display for TestName { pub enum TestFn { StaticTestFn(fn() -> Result<(), String>), StaticBenchFn(fn(&mut Bencher) -> Result<(), String>), + StaticBenchAsTestFn(fn(&mut Bencher) -> Result<(), String>), DynTestFn(Box<dyn FnOnce() -> Result<(), String> + Send>), DynBenchFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>), + DynBenchAsTestFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>), } impl TestFn { @@ -91,8 +96,21 @@ impl TestFn { match *self { StaticTestFn(..) => PadNone, StaticBenchFn(..) => PadOnRight, + StaticBenchAsTestFn(..) => PadNone, DynTestFn(..) => PadNone, DynBenchFn(..) => PadOnRight, + DynBenchAsTestFn(..) => PadNone, + } + } + + pub(crate) fn into_runnable(self) -> Runnable { + match self { + StaticTestFn(f) => Runnable::Test(RunnableTest::Static(f)), + StaticBenchFn(f) => Runnable::Bench(RunnableBench::Static(f)), + StaticBenchAsTestFn(f) => Runnable::Test(RunnableTest::StaticBenchAsTest(f)), + DynTestFn(f) => Runnable::Test(RunnableTest::Dynamic(f)), + DynBenchFn(f) => Runnable::Bench(RunnableBench::Dynamic(f)), + DynBenchAsTestFn(f) => Runnable::Test(RunnableTest::DynamicBenchAsTest(f)), } } } @@ -102,12 +120,74 @@ impl fmt::Debug for TestFn { f.write_str(match *self { StaticTestFn(..) => "StaticTestFn(..)", StaticBenchFn(..) => "StaticBenchFn(..)", + StaticBenchAsTestFn(..) => "StaticBenchAsTestFn(..)", DynTestFn(..) => "DynTestFn(..)", DynBenchFn(..) => "DynBenchFn(..)", + DynBenchAsTestFn(..) => "DynBenchAsTestFn(..)", }) } } +pub(crate) enum Runnable { + Test(RunnableTest), + Bench(RunnableBench), +} + +pub(crate) enum RunnableTest { + Static(fn() -> Result<(), String>), + Dynamic(Box<dyn FnOnce() -> Result<(), String> + Send>), + StaticBenchAsTest(fn(&mut Bencher) -> Result<(), String>), + DynamicBenchAsTest(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>), +} + +impl RunnableTest { + pub(crate) fn run(self) -> Result<(), String> { + match self { + RunnableTest::Static(f) => __rust_begin_short_backtrace(f), + RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f), + RunnableTest::StaticBenchAsTest(f) => { + crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b))) + } + RunnableTest::DynamicBenchAsTest(f) => { + crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b))) + } + } + } + + pub(crate) fn is_dynamic(&self) -> bool { + match self { + RunnableTest::Static(_) => false, + RunnableTest::StaticBenchAsTest(_) => false, + RunnableTest::Dynamic(_) => true, + RunnableTest::DynamicBenchAsTest(_) => true, + } + } +} + +pub(crate) enum RunnableBench { + Static(fn(&mut Bencher) -> Result<(), String>), + Dynamic(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>), +} + +impl RunnableBench { + pub(crate) fn run( + self, + id: TestId, + desc: &TestDesc, + monitor_ch: &Sender<CompletedTest>, + nocapture: bool, + ) { + match self { + RunnableBench::Static(f) => { + crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f) + } + RunnableBench::Dynamic(f) => { + crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f) + } + } + } +} + // A unique integer associated with each test. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct TestId(pub usize); |