summaryrefslogtreecommitdiffstats
path: root/library/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:19 +0000
commita0b8f38ab54ac451646aa00cd5e91b6c76f22a84 (patch)
treefc451898ccaf445814e26b46664d78702178101d /library/test
parentAdding debian version 1.71.1+dfsg1-2. (diff)
downloadrustc-a0b8f38ab54ac451646aa00cd5e91b6c76f22a84.tar.xz
rustc-a0b8f38ab54ac451646aa00cd5e91b6c76f22a84.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.rs2
-rw-r--r--library/test/src/lib.rs206
-rw-r--r--library/test/src/tests.rs5
-rw-r--r--library/test/src/types.rs80
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);