about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakob Schikowski <jakob.schikowski@gmx.de>2020-11-26 21:15:15 +0100
committerJakob Schikowski <jakob.schikowski@gmx.de>2020-11-27 17:53:59 +0100
commit470c059e691a4e7befa5e2a7ad0110a2b0055b50 (patch)
treec0cd91f6776567f5e6f3b241661435fa56fdd170
parentc9228570668803e3e6402770d55f23a12c9ae686 (diff)
downloadrust-470c059e691a4e7befa5e2a7ad0110a2b0055b50.tar.gz
rust-470c059e691a4e7befa5e2a7ad0110a2b0055b50.zip
libtest: Print the total time taken to execute a test suite
-rw-r--r--library/test/src/console.rs12
-rw-r--r--library/test/src/formatters/json.rs15
-rw-r--r--library/test/src/formatters/pretty.rs11
-rw-r--r--library/test/src/formatters/terse.rs11
-rw-r--r--library/test/src/tests.rs1
-rw-r--r--library/test/src/time.rs15
-rw-r--r--src/test/run-make-fulldeps/libtest-json/Makefile6
-rw-r--r--src/test/run-make-fulldeps/libtest-json/output-default.json2
-rw-r--r--src/test/run-make-fulldeps/libtest-json/output-stdout-success.json2
-rw-r--r--src/test/rustdoc-ui/cfg-test.rs1
-rw-r--r--src/test/rustdoc-ui/cfg-test.stdout6
-rw-r--r--src/test/rustdoc-ui/doc-test-doctest-feature.rs1
-rw-r--r--src/test/rustdoc-ui/doc-test-doctest-feature.stdout4
-rw-r--r--src/test/rustdoc-ui/doc-test-rustdoc-feature.rs1
-rw-r--r--src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout4
-rw-r--r--src/test/rustdoc-ui/doctest-output.rs1
-rw-r--r--src/test/rustdoc-ui/doctest-output.stdout8
-rw-r--r--src/test/rustdoc-ui/failed-doctest-compile-fail.rs1
-rw-r--r--src/test/rustdoc-ui/failed-doctest-compile-fail.stdout8
-rw-r--r--src/test/rustdoc-ui/failed-doctest-missing-codes.rs1
-rw-r--r--src/test/rustdoc-ui/failed-doctest-missing-codes.stdout10
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.rs1
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.stdout16
-rw-r--r--src/test/rustdoc-ui/failed-doctest-should-panic.rs1
-rw-r--r--src/test/rustdoc-ui/failed-doctest-should-panic.stdout8
-rw-r--r--src/test/rustdoc-ui/test-no_std.rs1
-rw-r--r--src/test/rustdoc-ui/test-no_std.stdout4
-rw-r--r--src/test/rustdoc-ui/unparseable-doc-test.rs1
-rw-r--r--src/test/rustdoc-ui/unparseable-doc-test.stdout10
-rw-r--r--src/test/ui/test-panic-abort-nocapture.rs1
-rw-r--r--src/test/ui/test-panic-abort-nocapture.run.stderr4
-rw-r--r--src/test/ui/test-panic-abort-nocapture.run.stdout2
-rw-r--r--src/test/ui/test-panic-abort.rs1
-rw-r--r--src/test/ui/test-panic-abort.run.stdout4
-rw-r--r--src/test/ui/test-passed-wasm.rs20
-rw-r--r--src/test/ui/test-passed-wasm.run.stdout7
-rw-r--r--src/test/ui/test-passed.rs21
-rw-r--r--src/test/ui/test-passed.run.stdout7
-rw-r--r--src/test/ui/test-thread-capture.rs1
-rw-r--r--src/test/ui/test-thread-capture.run.stdout4
-rw-r--r--src/test/ui/test-thread-nocapture.rs1
-rw-r--r--src/test/ui/test-thread-nocapture.run.stderr2
-rw-r--r--src/test/ui/test-thread-nocapture.run.stdout2
43 files changed, 176 insertions, 64 deletions
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index ff741e3bd53..1721c3c14f9 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -3,6 +3,7 @@
 use std::fs::File;
 use std::io;
 use std::io::prelude::Write;
+use std::time::Instant;
 
 use super::{
     bench::fmt_bench_samples,
@@ -14,7 +15,7 @@ use super::{
     options::{Options, OutputFormat},
     run_tests,
     test_result::TestResult,
-    time::TestExecTime,
+    time::{TestExecTime, TestSuiteExecTime},
     types::{NamePadding, TestDesc, TestDescAndFn},
 };
 
@@ -49,6 +50,7 @@ pub struct ConsoleTestState {
     pub allowed_fail: usize,
     pub filtered_out: usize,
     pub measured: usize,
+    pub exec_time: Option<TestSuiteExecTime>,
     pub metrics: MetricMap,
     pub failures: Vec<(TestDesc, Vec<u8>)>,
     pub not_failures: Vec<(TestDesc, Vec<u8>)>,
@@ -72,6 +74,7 @@ impl ConsoleTestState {
             allowed_fail: 0,
             filtered_out: 0,
             measured: 0,
+            exec_time: None,
             metrics: MetricMap::new(),
             failures: Vec::new(),
             not_failures: Vec::new(),
@@ -277,7 +280,14 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
     };
     let mut st = ConsoleTestState::new(opts)?;
 
+    // Prevent the usage of `Instant` in some cases:
+    // - It's currently not supported for wasm targets.
+    // - We disable it for miri because it's not available when isolation is enabled.
+    let is_instant_supported = !cfg!(target_arch = "wasm32") && !cfg!(miri);
+
+    let start_time = is_instant_supported.then(Instant::now);
     run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
+    st.exec_time = start_time.map(|t| TestSuiteExecTime(t.elapsed()));
 
     assert!(st.current_test_count() == st.total);
 
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 4dc4162700c..57b6d1a0202 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -47,7 +47,7 @@ impl<T: Write> JsonFormatter<T> {
             evt
         ))?;
         if let Some(exec_time) = exec_time {
-            self.write_message(&*format!(r#", "exec_time": "{}""#, exec_time))?;
+            self.write_message(&*format!(r#", "exec_time": {}"#, exec_time.0.as_secs_f64()))?;
         }
         if let Some(stdout) = stdout {
             self.write_message(&*format!(r#", "stdout": "{}""#, EscapedString(stdout)))?;
@@ -162,7 +162,7 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
     }
 
     fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
-        self.writeln_message(&*format!(
+        self.write_message(&*format!(
             "{{ \"type\": \"suite\", \
              \"event\": \"{}\", \
              \"passed\": {}, \
@@ -170,16 +170,23 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
              \"allowed_fail\": {}, \
              \"ignored\": {}, \
              \"measured\": {}, \
-             \"filtered_out\": {} }}",
+             \"filtered_out\": {}",
             if state.failed == 0 { "ok" } else { "failed" },
             state.passed,
             state.failed + state.allowed_fail,
             state.allowed_fail,
             state.ignored,
             state.measured,
-            state.filtered_out
+            state.filtered_out,
         ))?;
 
+        if let Some(ref exec_time) = state.exec_time {
+            let time_str = format!(", \"exec_time\": {}", exec_time.0.as_secs_f64());
+            self.write_message(&time_str)?;
+        }
+
+        self.writeln_message(" }")?;
+
         Ok(state.failed == 0)
     }
 }
diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs
index 8c90b57b3ba..6fa36929841 100644
--- a/library/test/src/formatters/pretty.rs
+++ b/library/test/src/formatters/pretty.rs
@@ -259,7 +259,7 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
 
         let s = if state.allowed_fail > 0 {
             format!(
-                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
+                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
                 state.passed,
                 state.failed + state.allowed_fail,
                 state.allowed_fail,
@@ -269,13 +269,20 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
             )
         } else {
             format!(
-                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
+                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
                 state.passed, state.failed, state.ignored, state.measured, state.filtered_out
             )
         };
 
         self.write_plain(&s)?;
 
+        if let Some(ref exec_time) = state.exec_time {
+            let time_str = format!("; finished in {}", exec_time);
+            self.write_plain(&time_str)?;
+        }
+
+        self.write_plain("\n\n")?;
+
         Ok(success)
     }
 }
diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs
index 1ae7846a99e..6f46f7255a4 100644
--- a/library/test/src/formatters/terse.rs
+++ b/library/test/src/formatters/terse.rs
@@ -236,7 +236,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
 
         let s = if state.allowed_fail > 0 {
             format!(
-                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
+                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
                 state.passed,
                 state.failed + state.allowed_fail,
                 state.allowed_fail,
@@ -246,13 +246,20 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
             )
         } else {
             format!(
-                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
+                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
                 state.passed, state.failed, state.ignored, state.measured, state.filtered_out
             )
         };
 
         self.write_plain(&s)?;
 
+        if let Some(ref exec_time) = state.exec_time {
+            let time_str = format!("; finished in {}", exec_time);
+            self.write_plain(&time_str)?;
+        }
+
+        self.write_plain("\n\n")?;
+
         Ok(success)
     }
 }
diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs
index 85a0705f69c..74313cc4438 100644
--- a/library/test/src/tests.rs
+++ b/library/test/src/tests.rs
@@ -669,6 +669,7 @@ fn should_sort_failures_before_printing_them() {
         allowed_fail: 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(),
diff --git a/library/test/src/time.rs b/library/test/src/time.rs
index 96c090f9b01..130792fa5d7 100644
--- a/library/test/src/time.rs
+++ b/library/test/src/time.rs
@@ -1,8 +1,9 @@
 //! Module `time` contains everything related to the time measurement of unit tests
 //! execution.
-//! Two main purposes of this module:
+//! The purposes of this module:
 //! - Check whether test is timed out.
 //! - Provide helpers for `report-time` and `measure-time` options.
+//! - Provide newtypes for executions times.
 
 use std::env;
 use std::fmt;
@@ -60,7 +61,7 @@ pub fn get_default_test_timeout() -> Instant {
     Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S)
 }
 
-/// The meassured execution time of a unit test.
+/// The measured execution time of a unit test.
 #[derive(Debug, Clone, PartialEq)]
 pub struct TestExecTime(pub Duration);
 
@@ -70,6 +71,16 @@ impl fmt::Display for TestExecTime {
     }
 }
 
+/// The measured execution time of the whole test suite.
+#[derive(Debug, Clone, Default, PartialEq)]
+pub struct TestSuiteExecTime(pub Duration);
+
+impl fmt::Display for TestSuiteExecTime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:.2}s", self.0.as_secs_f64())
+    }
+}
+
 /// Structure denoting time limits for test execution.
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
 pub struct TimeThreshold {
diff --git a/src/test/run-make-fulldeps/libtest-json/Makefile b/src/test/run-make-fulldeps/libtest-json/Makefile
index 8339e230bbe..4f8a24447d1 100644
--- a/src/test/run-make-fulldeps/libtest-json/Makefile
+++ b/src/test/run-make-fulldeps/libtest-json/Makefile
@@ -13,6 +13,6 @@ all:
 	cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_json.py
 	cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_json.py
 
-	# Compare to output file
-	diff output-default.json $(OUTPUT_FILE_DEFAULT)
-	diff output-stdout-success.json $(OUTPUT_FILE_STDOUT_SUCCESS)
+	# Normalize the actual output and compare to expected output file
+	cat $(OUTPUT_FILE_DEFAULT) | sed -r 's/\"exec_time\": [0-9]+(\.[0-9]+)?/\"exec_time\": \$$TIME/' | diff output-default.json -
+	cat $(OUTPUT_FILE_STDOUT_SUCCESS) | sed -r 's/\"exec_time\": [0-9]+(\.[0-9]+)?/\"exec_time\": \$$TIME/' | diff output-stdout-success.json -
diff --git a/src/test/run-make-fulldeps/libtest-json/output-default.json b/src/test/run-make-fulldeps/libtest-json/output-default.json
index 0cd9ab79e32..099b65a23ca 100644
--- a/src/test/run-make-fulldeps/libtest-json/output-default.json
+++ b/src/test/run-make-fulldeps/libtest-json/output-default.json
@@ -7,4 +7,4 @@
 { "type": "test", "name": "c", "event": "ok" }
 { "type": "test", "event": "started", "name": "d" }
 { "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0 }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
diff --git a/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json b/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json
index dfaf005052e..fd676799a76 100644
--- a/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json
+++ b/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json
@@ -7,4 +7,4 @@
 { "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" }
 { "type": "test", "event": "started", "name": "d" }
 { "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0 }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
diff --git a/src/test/rustdoc-ui/cfg-test.rs b/src/test/rustdoc-ui/cfg-test.rs
index 597c86a1f19..d4ca9258587 100644
--- a/src/test/rustdoc-ui/cfg-test.rs
+++ b/src/test/rustdoc-ui/cfg-test.rs
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags:--test --test-args --test-threads=1
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 // Crates like core have doctests gated on `cfg(not(test))` so we need to make
 // sure `cfg(test)` is not active when running `rustdoc --test`.
diff --git a/src/test/rustdoc-ui/cfg-test.stdout b/src/test/rustdoc-ui/cfg-test.stdout
index 474f13cfa98..2960ff8d3b4 100644
--- a/src/test/rustdoc-ui/cfg-test.stdout
+++ b/src/test/rustdoc-ui/cfg-test.stdout
@@ -1,7 +1,7 @@
 
 running 2 tests
-test $DIR/cfg-test.rs - Bar (line 26) ... ok
-test $DIR/cfg-test.rs - Foo (line 18) ... ok
+test $DIR/cfg-test.rs - Bar (line 27) ... ok
+test $DIR/cfg-test.rs - Foo (line 19) ... ok
 
-test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.rs b/src/test/rustdoc-ui/doc-test-doctest-feature.rs
index 2798804880a..0b79aaece8a 100644
--- a/src/test/rustdoc-ui/doc-test-doctest-feature.rs
+++ b/src/test/rustdoc-ui/doc-test-doctest-feature.rs
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags:--test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 // Make sure `cfg(doctest)` is set when finding doctests but not inside
 // the doctests.
diff --git a/src/test/rustdoc-ui/doc-test-doctest-feature.stdout b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout
index b1cd74bf852..d7de1f10522 100644
--- a/src/test/rustdoc-ui/doc-test-doctest-feature.stdout
+++ b/src/test/rustdoc-ui/doc-test-doctest-feature.stdout
@@ -1,6 +1,6 @@
 
 running 1 test
-test $DIR/doc-test-doctest-feature.rs - Foo (line 8) ... ok
+test $DIR/doc-test-doctest-feature.rs - Foo (line 9) ... ok
 
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs
index 2af5782453e..bf334c67eca 100644
--- a/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs
+++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.rs
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags:--test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 #![feature(doc_cfg)]
 
diff --git a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout
index f2525c2dbec..5b07fc4c87a 100644
--- a/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout
+++ b/src/test/rustdoc-ui/doc-test-rustdoc-feature.stdout
@@ -1,6 +1,6 @@
 
 running 1 test
-test $DIR/doc-test-rustdoc-feature.rs - Foo (line 9) ... ok
+test $DIR/doc-test-rustdoc-feature.rs - Foo (line 10) ... ok
 
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/doctest-output.rs b/src/test/rustdoc-ui/doctest-output.rs
index e0e1e061ac7..2670fa57201 100644
--- a/src/test/rustdoc-ui/doctest-output.rs
+++ b/src/test/rustdoc-ui/doctest-output.rs
@@ -2,6 +2,7 @@
 // aux-build:extern_macros.rs
 // compile-flags:--test --test-args=--test-threads=1
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // check-pass
 
 //! ```
diff --git a/src/test/rustdoc-ui/doctest-output.stdout b/src/test/rustdoc-ui/doctest-output.stdout
index c72bd91d1dd..35b0e366fb5 100644
--- a/src/test/rustdoc-ui/doctest-output.stdout
+++ b/src/test/rustdoc-ui/doctest-output.stdout
@@ -1,8 +1,8 @@
 
 running 3 tests
-test $DIR/doctest-output.rs - (line 7) ... ok
-test $DIR/doctest-output.rs - ExpandedStruct (line 23) ... ok
-test $DIR/doctest-output.rs - foo::bar (line 17) ... ok
+test $DIR/doctest-output.rs - (line 8) ... ok
+test $DIR/doctest-output.rs - ExpandedStruct (line 24) ... ok
+test $DIR/doctest-output.rs - foo::bar (line 18) ... ok
 
-test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.rs b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs
index 297d6efd45f..6f2ff5d703a 100644
--- a/src/test/rustdoc-ui/failed-doctest-compile-fail.rs
+++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.rs
@@ -3,6 +3,7 @@
 
 // compile-flags:--test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // failure-status: 101
 
 /// ```compile_fail
diff --git a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout
index 74e33d7beeb..b8bb5ccb403 100644
--- a/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-compile-fail.stdout
@@ -1,14 +1,14 @@
 
 running 1 test
-test $DIR/failed-doctest-compile-fail.rs - Foo (line 8) ... FAILED
+test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-compile-fail.rs - Foo (line 8) stdout ----
+---- $DIR/failed-doctest-compile-fail.rs - Foo (line 9) stdout ----
 Test compiled successfully, but it's marked `compile_fail`.
 
 failures:
-    $DIR/failed-doctest-compile-fail.rs - Foo (line 8)
+    $DIR/failed-doctest-compile-fail.rs - Foo (line 9)
 
-test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.rs b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs
index 62102062d49..57b70b478e6 100644
--- a/src/test/rustdoc-ui/failed-doctest-missing-codes.rs
+++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.rs
@@ -3,6 +3,7 @@
 
 // compile-flags:--test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // failure-status: 101
 
 /// ```compile_fail,E0004
diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
index e4ed4622322..7367a7d6519 100644
--- a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/failed-doctest-missing-codes.rs - Foo (line 8) ... FAILED
+test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-missing-codes.rs - Foo (line 8) stdout ----
+---- $DIR/failed-doctest-missing-codes.rs - Foo (line 9) stdout ----
 error[E0308]: mismatched types
-  --> $DIR/failed-doctest-missing-codes.rs:9:13
+  --> $DIR/failed-doctest-missing-codes.rs:10:13
    |
 LL | let x: () = 5i32;
    |        --   ^^^^ expected `()`, found `i32`
@@ -19,7 +19,7 @@ For more information about this error, try `rustc --explain E0308`.
 Some expected error codes were not found: ["E0004"]
 
 failures:
-    $DIR/failed-doctest-missing-codes.rs - Foo (line 8)
+    $DIR/failed-doctest-missing-codes.rs - Foo (line 9)
 
-test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs
index 90cdb5127be..92473b49e14 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.rs
+++ b/src/test/rustdoc-ui/failed-doctest-output.rs
@@ -5,6 +5,7 @@
 // compile-flags:--test --test-args --test-threads=1
 // rustc-env:RUST_BACKTRACE=0
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // failure-status: 101
 
 // doctest fails at runtime
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index ee79ae1a690..6dfe648f854 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -1,13 +1,13 @@
 
 running 2 tests
-test $DIR/failed-doctest-output.rs - OtherStruct (line 21) ... FAILED
-test $DIR/failed-doctest-output.rs - SomeStruct (line 11) ... FAILED
+test $DIR/failed-doctest-output.rs - OtherStruct (line 22) ... FAILED
+test $DIR/failed-doctest-output.rs - SomeStruct (line 12) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-output.rs - OtherStruct (line 21) stdout ----
+---- $DIR/failed-doctest-output.rs - OtherStruct (line 22) stdout ----
 error[E0425]: cannot find value `no` in this scope
-  --> $DIR/failed-doctest-output.rs:22:1
+  --> $DIR/failed-doctest-output.rs:23:1
    |
 LL | no
    | ^^ not found in this scope
@@ -16,7 +16,7 @@ error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0425`.
 Couldn't compile the test.
----- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ----
+---- $DIR/failed-doctest-output.rs - SomeStruct (line 12) stdout ----
 Test executable failed (exit code 101).
 
 stdout:
@@ -32,8 +32,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
 failures:
-    $DIR/failed-doctest-output.rs - OtherStruct (line 21)
-    $DIR/failed-doctest-output.rs - SomeStruct (line 11)
+    $DIR/failed-doctest-output.rs - OtherStruct (line 22)
+    $DIR/failed-doctest-output.rs - SomeStruct (line 12)
 
-test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.rs b/src/test/rustdoc-ui/failed-doctest-should-panic.rs
index 400fb97804a..2b8bb31686f 100644
--- a/src/test/rustdoc-ui/failed-doctest-should-panic.rs
+++ b/src/test/rustdoc-ui/failed-doctest-should-panic.rs
@@ -3,6 +3,7 @@
 
 // compile-flags:--test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // failure-status: 101
 
 /// ```should_panic
diff --git a/src/test/rustdoc-ui/failed-doctest-should-panic.stdout b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout
index 081b64b50af..57a20092a5d 100644
--- a/src/test/rustdoc-ui/failed-doctest-should-panic.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-should-panic.stdout
@@ -1,14 +1,14 @@
 
 running 1 test
-test $DIR/failed-doctest-should-panic.rs - Foo (line 8) ... FAILED
+test $DIR/failed-doctest-should-panic.rs - Foo (line 9) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-should-panic.rs - Foo (line 8) stdout ----
+---- $DIR/failed-doctest-should-panic.rs - Foo (line 9) stdout ----
 Test executable succeeded, but it's marked `should_panic`.
 
 failures:
-    $DIR/failed-doctest-should-panic.rs - Foo (line 8)
+    $DIR/failed-doctest-should-panic.rs - Foo (line 9)
 
-test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/test-no_std.rs b/src/test/rustdoc-ui/test-no_std.rs
index af4843ad324..ee919985e7a 100644
--- a/src/test/rustdoc-ui/test-no_std.rs
+++ b/src/test/rustdoc-ui/test-no_std.rs
@@ -1,5 +1,6 @@
 // compile-flags:--test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // check-pass
 
 #![no_std]
diff --git a/src/test/rustdoc-ui/test-no_std.stdout b/src/test/rustdoc-ui/test-no_std.stdout
index 9cdcac2a483..8d5a30804c1 100644
--- a/src/test/rustdoc-ui/test-no_std.stdout
+++ b/src/test/rustdoc-ui/test-no_std.stdout
@@ -1,6 +1,6 @@
 
 running 1 test
-test $DIR/test-no_std.rs - f (line 9) ... ok
+test $DIR/test-no_std.rs - f (line 10) ... ok
 
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc-ui/unparseable-doc-test.rs b/src/test/rustdoc-ui/unparseable-doc-test.rs
index 18d6b32bf40..0cff8cd9a33 100644
--- a/src/test/rustdoc-ui/unparseable-doc-test.rs
+++ b/src/test/rustdoc-ui/unparseable-doc-test.rs
@@ -1,5 +1,6 @@
 // compile-flags: --test
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // failure-status: 101
 // rustc-env: RUST_BACKTRACE=0
 
diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout
index 29cb22e2e4b..2641c66f25e 100644
--- a/src/test/rustdoc-ui/unparseable-doc-test.stdout
+++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout
@@ -1,12 +1,12 @@
 
 running 1 test
-test $DIR/unparseable-doc-test.rs - foo (line 6) ... FAILED
+test $DIR/unparseable-doc-test.rs - foo (line 7) ... FAILED
 
 failures:
 
----- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ----
+---- $DIR/unparseable-doc-test.rs - foo (line 7) stdout ----
 error[E0765]: unterminated double quote string
-  --> $DIR/unparseable-doc-test.rs:8:1
+  --> $DIR/unparseable-doc-test.rs:9:1
    |
 LL | "unterminated
    | ^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ For more information about this error, try `rustc --explain E0765`.
 Couldn't compile the test.
 
 failures:
-    $DIR/unparseable-doc-test.rs - foo (line 6)
+    $DIR/unparseable-doc-test.rs - foo (line 7)
 
-test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/ui/test-panic-abort-nocapture.rs b/src/test/ui/test-panic-abort-nocapture.rs
index 978732a9ec3..af530cc1a0b 100644
--- a/src/test/ui/test-panic-abort-nocapture.rs
+++ b/src/test/ui/test-panic-abort-nocapture.rs
@@ -4,6 +4,7 @@
 // run-fail
 // check-run-results
 // exec-env:RUST_BACKTRACE=0
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
diff --git a/src/test/ui/test-panic-abort-nocapture.run.stderr b/src/test/ui/test-panic-abort-nocapture.run.stderr
index 3388813d5a0..727e9691c53 100644
--- a/src/test/ui/test-panic-abort-nocapture.run.stderr
+++ b/src/test/ui/test-panic-abort-nocapture.run.stderr
@@ -1,9 +1,9 @@
 thread 'main' panicked at 'assertion failed: `(left == right)`
   left: `2`,
- right: `4`', $DIR/test-panic-abort-nocapture.rs:32:5
+ right: `4`', $DIR/test-panic-abort-nocapture.rs:33:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 thread 'main' panicked at 'assertion failed: `(left == right)`
   left: `2`,
- right: `4`', $DIR/test-panic-abort-nocapture.rs:26:5
+ right: `4`', $DIR/test-panic-abort-nocapture.rs:27:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 testing321
diff --git a/src/test/ui/test-panic-abort-nocapture.run.stdout b/src/test/ui/test-panic-abort-nocapture.run.stdout
index 87a246db5e0..15b19676a7c 100644
--- a/src/test/ui/test-panic-abort-nocapture.run.stdout
+++ b/src/test/ui/test-panic-abort-nocapture.run.stdout
@@ -19,5 +19,5 @@ failures:
 failures:
     it_fails
 
-test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 3 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/ui/test-panic-abort.rs b/src/test/ui/test-panic-abort.rs
index 21e7dc393f5..931b7993c81 100644
--- a/src/test/ui/test-panic-abort.rs
+++ b/src/test/ui/test-panic-abort.rs
@@ -4,6 +4,7 @@
 // run-fail
 // check-run-results
 // exec-env:RUST_BACKTRACE=0
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout
index 33ddd519030..467f834afec 100644
--- a/src/test/ui/test-panic-abort.run.stdout
+++ b/src/test/ui/test-panic-abort.run.stdout
@@ -18,7 +18,7 @@ testing123
 testing321
 thread 'main' panicked at 'assertion failed: `(left == right)`
   left: `2`,
- right: `5`', $DIR/test-panic-abort.rs:33:5
+ right: `5`', $DIR/test-panic-abort.rs:34:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
@@ -26,5 +26,5 @@ failures:
     it_exits
     it_fails
 
-test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/ui/test-passed-wasm.rs b/src/test/ui/test-passed-wasm.rs
new file mode 100644
index 00000000000..578aa4b1760
--- /dev/null
+++ b/src/test/ui/test-passed-wasm.rs
@@ -0,0 +1,20 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --test-threads=1
+// run-pass
+// check-run-results
+// only-wasm32
+
+// Tests the output of the test harness with only passed tests.
+
+#![cfg(test)]
+
+#[test]
+fn it_works() {
+    assert_eq!(1 + 1, 2);
+}
+
+#[test]
+fn it_works_too() {
+    assert_eq!(1 * 0, 0);
+}
diff --git a/src/test/ui/test-passed-wasm.run.stdout b/src/test/ui/test-passed-wasm.run.stdout
new file mode 100644
index 00000000000..c3005a77983
--- /dev/null
+++ b/src/test/ui/test-passed-wasm.run.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test it_works ... ok
+test it_works_too ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+
diff --git a/src/test/ui/test-passed.rs b/src/test/ui/test-passed.rs
new file mode 100644
index 00000000000..f65f0003022
--- /dev/null
+++ b/src/test/ui/test-passed.rs
@@ -0,0 +1,21 @@
+// no-prefer-dynamic
+// compile-flags: --test
+// run-flags: --test-threads=1
+// run-pass
+// check-run-results
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// ignore-wasm32 no support for `Instant`
+
+// Tests the output of the test harness with only passed tests.
+
+#![cfg(test)]
+
+#[test]
+fn it_works() {
+    assert_eq!(1 + 1, 2);
+}
+
+#[test]
+fn it_works_too() {
+    assert_eq!(1 * 0, 0);
+}
diff --git a/src/test/ui/test-passed.run.stdout b/src/test/ui/test-passed.run.stdout
new file mode 100644
index 00000000000..17f70d60749
--- /dev/null
+++ b/src/test/ui/test-passed.run.stdout
@@ -0,0 +1,7 @@
+
+running 2 tests
+test it_works ... ok
+test it_works_too ... ok
+
+test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/ui/test-thread-capture.rs b/src/test/ui/test-thread-capture.rs
index 6bec48cd816..edc972837a3 100644
--- a/src/test/ui/test-thread-capture.rs
+++ b/src/test/ui/test-thread-capture.rs
@@ -3,6 +3,7 @@
 // run-flags: --test-threads=1
 // check-run-results
 // exec-env:RUST_BACKTRACE=0
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // ignore-emscripten no threads support
 
 #[test]
diff --git a/src/test/ui/test-thread-capture.run.stdout b/src/test/ui/test-thread-capture.run.stdout
index 1102aadab02..487cfb55eb4 100644
--- a/src/test/ui/test-thread-capture.run.stdout
+++ b/src/test/ui/test-thread-capture.run.stdout
@@ -10,12 +10,12 @@ fee
 fie
 foe
 fum
-thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:30:5
+thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:31:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
 failures:
     thready_fail
 
-test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/ui/test-thread-nocapture.rs b/src/test/ui/test-thread-nocapture.rs
index 82df6e77cb1..8e8e9bbfdf0 100644
--- a/src/test/ui/test-thread-nocapture.rs
+++ b/src/test/ui/test-thread-nocapture.rs
@@ -3,6 +3,7 @@
 // run-flags: --test-threads=1 --nocapture
 // check-run-results
 // exec-env:RUST_BACKTRACE=0
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 // ignore-emscripten no threads support
 
 #[test]
diff --git a/src/test/ui/test-thread-nocapture.run.stderr b/src/test/ui/test-thread-nocapture.run.stderr
index 98bd96d0abe..06495681b3e 100644
--- a/src/test/ui/test-thread-nocapture.run.stderr
+++ b/src/test/ui/test-thread-nocapture.run.stderr
@@ -1,2 +1,2 @@
-thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:30:5
+thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:31:5
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/test/ui/test-thread-nocapture.run.stdout b/src/test/ui/test-thread-nocapture.run.stdout
index 77b42ed88d6..9d2da50826c 100644
--- a/src/test/ui/test-thread-nocapture.run.stdout
+++ b/src/test/ui/test-thread-nocapture.run.stdout
@@ -16,5 +16,5 @@ failures:
 failures:
     thready_fail
 
-test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
+test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME