Skip to content

Commit 2cc4348

Browse files
committed
rustdoc: Test --format=junit
Copied validate_junit.py from libtest-junit. JUnit format works well in edition 2021, but is currently broken in edition 2024 by the mergeable doctest report.
1 parent e39e127 commit 2cc4348

File tree

4 files changed

+109
-0
lines changed

4 files changed

+109
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="0" tests="3" skipped="0" ><testcase classname="doctest.rs" name="add (line 1)" time="$TIME"/><testcase classname="doctest.rs" name="add (line 5)" time="$TIME"/><testcase classname="doctest.rs" name="add (line 9)" time="$TIME"/><system-out/><system-err/></testsuite></testsuites>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// ```
2+
/// assert_eq!(doctest::add(2, 2), 4);
3+
/// ```
4+
///
5+
/// ```should_panic
6+
/// assert_eq!(doctest::add(2, 2), 5);
7+
/// ```
8+
///
9+
/// ```compile_fail
10+
/// assert_eq!(doctest::add(2, 2), "banana");
11+
/// ```
12+
pub fn add(a: i32, b: i32) -> i32 {
13+
a + b
14+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Check rustdoc's test JUnit (XML) output against snapshots.
2+
3+
//@ ignore-cross-compile (running doctests)
4+
//@ needs-unwind (test file contains `should_panic` test)
5+
6+
use std::path::Path;
7+
8+
use run_make_support::{cwd, diff, python_command, rustc, rustdoc};
9+
10+
fn main() {
11+
let rlib = cwd().join("libdoctest.rlib");
12+
rustc().input("doctest.rs").crate_type("rlib").output(&rlib).run();
13+
14+
run_doctests(&rlib, "2021", "doctest-2021.xml");
15+
run_doctests_fail(&rlib, "2024");
16+
}
17+
18+
#[track_caller]
19+
fn run_doctests(rlib: &Path, edition: &str, expected_xml: &str) {
20+
let rustdoc_out = rustdoc()
21+
.input("doctest.rs")
22+
.args(&[
23+
"--test",
24+
"--test-args=-Zunstable-options",
25+
"--test-args=--test-threads=1",
26+
"--test-args=--format=junit",
27+
])
28+
.edition(edition)
29+
.env("RUST_BACKTRACE", "0")
30+
.extern_("doctest", rlib.display().to_string())
31+
.run();
32+
let rustdoc_stdout = &rustdoc_out.stdout_utf8();
33+
34+
python_command().arg("validate_junit.py").stdin_buf(rustdoc_stdout).run();
35+
36+
diff()
37+
.expected_file(expected_xml)
38+
.actual_text("output", rustdoc_stdout)
39+
.normalize(r#"\btime="[0-9.]+""#, r#"time="$$TIME""#)
40+
.run();
41+
}
42+
43+
// FIXME: gone in the next patch
44+
#[track_caller]
45+
fn run_doctests_fail(rlib: &Path, edition: &str) {
46+
let rustdoc_out = rustdoc()
47+
.input("doctest.rs")
48+
.args(&[
49+
"--test",
50+
"--test-args=-Zunstable-options",
51+
"--test-args=--test-threads=1",
52+
"--test-args=--format=junit",
53+
])
54+
.edition(edition)
55+
.env("RUST_BACKTRACE", "0")
56+
.extern_("doctest", rlib.display().to_string())
57+
.run_fail();
58+
let rustdoc_stderr = &rustdoc_out.stderr_utf8();
59+
60+
diff()
61+
.expected_text(
62+
"expected",
63+
r#"
64+
thread 'main' ($TID) panicked at library/test/src/formatters/junit.rs:22:9:
65+
assertion failed: !s.contains('\n')
66+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
67+
"#,
68+
)
69+
.actual_text("actual", rustdoc_stderr)
70+
.normalize(r#"thread 'main' \([0-9]+\)"#, r#"thread 'main' ($$TID)"#)
71+
.run();
72+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env python
2+
3+
# Trivial Python script that reads lines from stdin, and checks that each line
4+
# is a well-formed XML document.
5+
#
6+
# This takes advantage of the fact that Python has a built-in XML parser,
7+
# whereas doing the same check in Rust would require us to pull in an XML
8+
# crate just for this relatively-minor test.
9+
#
10+
# If you're trying to remove Python scripts from the test suite, think twice
11+
# before removing this one. You could do so, but it's probably not worth it.
12+
13+
import sys
14+
import xml.etree.ElementTree as ET
15+
16+
# Read the entire output and try to decode it as XML.
17+
junit = sys.stdin.read()
18+
try:
19+
ET.fromstring(junit)
20+
except ET.ParseError:
21+
print("Invalid xml: %r" % junit)
22+
raise

0 commit comments

Comments
 (0)