Skip to content

Commit 75a2975

Browse files
committed
Enhance report-time option
1 parent 06c6894 commit 75a2975

File tree

8 files changed

+546
-95
lines changed

8 files changed

+546
-95
lines changed

src/librustdoc/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ impl Tester for Collector {
702702
// compiler failures are test failures
703703
should_panic: testing::ShouldPanic::No,
704704
allow_fail: config.allow_fail,
705+
test_type: testing::TestType::DocTest,
705706
},
706707
testfn: testing::DynTestFn(box move || {
707708
let res = run_test(

src/libsyntax_ext/test.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ pub fn expand_test_or_bench(
106106
cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic", sp), cx.ident_of(name, sp)])
107107
};
108108

109+
// creates test::TestType::$name
110+
let test_type_path = |name| {
111+
cx.path(sp, vec![test_id, cx.ident_of("TestType", sp), cx.ident_of(name, sp)])
112+
};
113+
109114
// creates $name: $expr
110115
let field = |name, expr| cx.field_imm(sp, cx.ident_of(name, sp), expr);
111116

@@ -181,6 +186,17 @@ pub fn expand_test_or_bench(
181186
cx.expr_path(should_panic_path("YesWithMessage")),
182187
vec![cx.expr_str(sp, sym)]),
183188
}),
189+
// test_type: ...
190+
field("test_type", match test_type(cx) {
191+
// test::TestType::UnitTest
192+
TestType::UnitTest => cx.expr_path(test_type_path("UnitTest")),
193+
// test::TestType::IntegrationTest
194+
TestType::IntegrationTest => cx.expr_path(
195+
test_type_path("IntegrationTest")
196+
),
197+
// test::TestPath::Unknown
198+
TestType::Unknown => cx.expr_path(test_type_path("Unknown")),
199+
}),
184200
// },
185201
])),
186202
// testfn: test::StaticTestFn(...) | test::StaticBenchFn(...)
@@ -261,6 +277,34 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
261277
}
262278
}
263279

280+
enum TestType {
281+
UnitTest,
282+
IntegrationTest,
283+
Unknown,
284+
}
285+
286+
/// Attempts to determine the type of test.
287+
/// Since doctests are created without macro expanding, only possible variants here
288+
/// are `UnitTest`, `IntegrationTest` or `Unknown`.
289+
fn test_type(cx: &ExtCtxt<'_>) -> TestType {
290+
// Root path from context contains the topmost sources directory of the crate.
291+
// I.e., for `project` with sources in `src` and tests in `tests` folders
292+
// (no matter how many nested folders lie inside),
293+
// there will be two different root paths: `/project/src` and `/project/tests`.
294+
let crate_path = cx.root_path.as_path();
295+
296+
if crate_path.ends_with("src") {
297+
// `/src` folder contains unit-tests.
298+
TestType::UnitTest
299+
} else if crate_path.ends_with("tests") {
300+
// `/tests` folder contains integration tests.
301+
TestType::IntegrationTest
302+
} else {
303+
// Crate layout doesn't match expected one, test type is unknown.
304+
TestType::Unknown
305+
}
306+
}
307+
264308
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
265309
let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
266310
let ref sd = cx.parse_sess.span_diagnostic;

src/libtest/formatters/json.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
9494
self.write_event("test", desc.name.as_slice(), "failed", exec_time, stdout, None)
9595
}
9696

97+
TrTimedFail => self.write_event(
98+
"test",
99+
desc.name.as_slice(),
100+
"failed",
101+
exec_time,
102+
stdout,
103+
Some(r#""reason": "time limit exceeded""#),
104+
),
105+
97106
TrFailedMsg(ref m) => self.write_event(
98107
"test",
99108
desc.name.as_slice(),

src/libtest/formatters/pretty.rs

Lines changed: 84 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::*;
33
pub(crate) struct PrettyFormatter<T> {
44
out: OutputLocation<T>,
55
use_color: bool,
6+
time_options: Option<TestTimeOptions>,
67

78
/// Number of columns to fill when aligning names
89
max_name_len: usize,
@@ -16,12 +17,14 @@ impl<T: Write> PrettyFormatter<T> {
1617
use_color: bool,
1718
max_name_len: usize,
1819
is_multithreaded: bool,
20+
time_options: Option<TestTimeOptions>,
1921
) -> Self {
2022
PrettyFormatter {
2123
out,
2224
use_color,
2325
max_name_len,
2426
is_multithreaded,
27+
time_options
2528
}
2629
}
2730

@@ -30,20 +33,24 @@ impl<T: Write> PrettyFormatter<T> {
3033
&self.out
3134
}
3235

33-
pub fn write_ok(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
34-
self.write_short_result("ok", term::color::GREEN, exec_time)
36+
pub fn write_ok(&mut self) -> io::Result<()> {
37+
self.write_short_result("ok", term::color::GREEN)
3538
}
3639

37-
pub fn write_failed(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
38-
self.write_short_result("FAILED", term::color::RED, exec_time)
40+
pub fn write_failed(&mut self) -> io::Result<()> {
41+
self.write_short_result("FAILED", term::color::RED)
3942
}
4043

41-
pub fn write_ignored(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
42-
self.write_short_result("ignored", term::color::YELLOW, exec_time)
44+
pub fn write_ignored(&mut self) -> io::Result<()> {
45+
self.write_short_result("ignored", term::color::YELLOW)
4346
}
4447

45-
pub fn write_allowed_fail(&mut self, exec_time: Option<&TestExecTime>) -> io::Result<()> {
46-
self.write_short_result("FAILED (allowed)", term::color::YELLOW, exec_time)
48+
pub fn write_allowed_fail(&mut self) -> io::Result<()> {
49+
self.write_short_result("FAILED (allowed)", term::color::YELLOW)
50+
}
51+
52+
pub fn write_time_failed(&mut self) -> io::Result<()> {
53+
self.write_short_result("FAILED (time limit exceeded)", term::color::RED)
4754
}
4855

4956
pub fn write_bench(&mut self) -> io::Result<()> {
@@ -54,13 +61,8 @@ impl<T: Write> PrettyFormatter<T> {
5461
&mut self,
5562
result: &str,
5663
color: term::color::Color,
57-
exec_time: Option<&TestExecTime>,
5864
) -> io::Result<()> {
59-
self.write_pretty(result, color)?;
60-
if let Some(exec_time) = exec_time {
61-
self.write_plain(format!(" {}", exec_time))?;
62-
}
63-
self.write_plain("\n")
65+
self.write_pretty(result, color)
6466
}
6567

6668
pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
@@ -88,12 +90,48 @@ impl<T: Write> PrettyFormatter<T> {
8890
self.out.flush()
8991
}
9092

91-
pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
92-
self.write_plain("\nsuccesses:\n")?;
93-
let mut successes = Vec::new();
93+
fn write_time(
94+
&mut self,
95+
desc: &TestDesc,
96+
exec_time: Option<&TestExecTime>
97+
) -> io::Result<()> {
98+
if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
99+
let time_str = format!(" <{}>", time);
100+
101+
let color = if opts.colored {
102+
if opts.is_critical(desc, time) {
103+
Some(term::color::RED)
104+
} else if opts.is_warn(desc, time) {
105+
Some(term::color::YELLOW)
106+
} else {
107+
None
108+
}
109+
} else {
110+
None
111+
};
112+
113+
match color {
114+
Some(color) => self.write_pretty(&time_str, color)?,
115+
None => self.write_plain(&time_str)?
116+
}
117+
}
118+
119+
Ok(())
120+
}
121+
122+
fn write_results(
123+
&mut self,
124+
inputs: &Vec<(TestDesc, Vec<u8>)>,
125+
results_type: &str
126+
) -> io::Result<()> {
127+
let results_out_str = format!("\n{}:\n", results_type);
128+
129+
self.write_plain(&results_out_str)?;
130+
131+
let mut results = Vec::new();
94132
let mut stdouts = String::new();
95-
for &(ref f, ref stdout) in &state.not_failures {
96-
successes.push(f.name.to_string());
133+
for &(ref f, ref stdout) in inputs {
134+
results.push(f.name.to_string());
97135
if !stdout.is_empty() {
98136
stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
99137
let output = String::from_utf8_lossy(stdout);
@@ -106,38 +144,24 @@ impl<T: Write> PrettyFormatter<T> {
106144
self.write_plain(&stdouts)?;
107145
}
108146

109-
self.write_plain("\nsuccesses:\n")?;
110-
successes.sort();
111-
for name in &successes {
147+
self.write_plain(&results_out_str)?;
148+
results.sort();
149+
for name in &results {
112150
self.write_plain(&format!(" {}\n", name))?;
113151
}
114152
Ok(())
115153
}
116154

155+
pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
156+
self.write_results(&state.not_failures, "successes")
157+
}
158+
117159
pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
118-
self.write_plain("\nfailures:\n")?;
119-
let mut failures = Vec::new();
120-
let mut fail_out = String::new();
121-
for &(ref f, ref stdout) in &state.failures {
122-
failures.push(f.name.to_string());
123-
if !stdout.is_empty() {
124-
fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
125-
let output = String::from_utf8_lossy(stdout);
126-
fail_out.push_str(&output);
127-
fail_out.push_str("\n");
128-
}
129-
}
130-
if !fail_out.is_empty() {
131-
self.write_plain("\n")?;
132-
self.write_plain(&fail_out)?;
133-
}
160+
self.write_results(&state.failures, "failures")
161+
}
134162

135-
self.write_plain("\nfailures:\n")?;
136-
failures.sort();
137-
for name in &failures {
138-
self.write_plain(&format!(" {}\n", name))?;
139-
}
140-
Ok(())
163+
pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
164+
self.write_results(&state.time_failures, "failures (time limit exceeded)")
141165
}
142166

143167
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -179,15 +203,19 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
179203
}
180204

181205
match *result {
182-
TrOk => self.write_ok(exec_time),
183-
TrFailed | TrFailedMsg(_) => self.write_failed(exec_time),
184-
TrIgnored => self.write_ignored(exec_time),
185-
TrAllowedFail => self.write_allowed_fail(exec_time),
206+
TrOk => self.write_ok()?,
207+
TrFailed | TrFailedMsg(_) => self.write_failed()?,
208+
TrIgnored => self.write_ignored()?,
209+
TrAllowedFail => self.write_allowed_fail()?,
186210
TrBench(ref bs) => {
187211
self.write_bench()?;
188-
self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
212+
self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))?;
189213
}
214+
TrTimedFail => self.write_time_failed()?,
190215
}
216+
217+
self.write_time(desc, exec_time)?;
218+
self.write_plain("\n")
191219
}
192220

193221
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
@@ -207,7 +235,13 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
207235
}
208236
let success = state.failed == 0;
209237
if !success {
210-
self.write_failures(state)?;
238+
if !state.failures.is_empty() {
239+
self.write_failures(state)?;
240+
}
241+
242+
if !state.time_failures.is_empty() {
243+
self.write_time_failures(state)?;
244+
}
211245
}
212246

213247
self.write_plain("\ntest result: ")?;

src/libtest/formatters/terse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
180180
) -> io::Result<()> {
181181
match *result {
182182
TrOk => self.write_ok(),
183-
TrFailed | TrFailedMsg(_) => self.write_failed(),
183+
TrFailed | TrFailedMsg(_) | TrTimedFail => self.write_failed(),
184184
TrIgnored => self.write_ignored(),
185185
TrAllowedFail => self.write_allowed_fail(),
186186
TrBench(ref bs) => {

0 commit comments

Comments
 (0)