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.
This commit is contained in:
Oleksii Lozovskyi
2025-12-13 14:29:44 +09:00
parent e39e127bd0
commit 2cc434863c
4 changed files with 109 additions and 0 deletions
@@ -0,0 +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>
+14
View File
@@ -0,0 +1,14 @@
/// ```
/// assert_eq!(doctest::add(2, 2), 4);
/// ```
///
/// ```should_panic
/// assert_eq!(doctest::add(2, 2), 5);
/// ```
///
/// ```compile_fail
/// assert_eq!(doctest::add(2, 2), "banana");
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
+72
View File
@@ -0,0 +1,72 @@
// Check rustdoc's test JUnit (XML) output against snapshots.
//@ ignore-cross-compile (running doctests)
//@ needs-unwind (test file contains `should_panic` test)
use std::path::Path;
use run_make_support::{cwd, diff, python_command, rustc, rustdoc};
fn main() {
let rlib = cwd().join("libdoctest.rlib");
rustc().input("doctest.rs").crate_type("rlib").output(&rlib).run();
run_doctests(&rlib, "2021", "doctest-2021.xml");
run_doctests_fail(&rlib, "2024");
}
#[track_caller]
fn run_doctests(rlib: &Path, edition: &str, expected_xml: &str) {
let rustdoc_out = rustdoc()
.input("doctest.rs")
.args(&[
"--test",
"--test-args=-Zunstable-options",
"--test-args=--test-threads=1",
"--test-args=--format=junit",
])
.edition(edition)
.env("RUST_BACKTRACE", "0")
.extern_("doctest", rlib.display().to_string())
.run();
let rustdoc_stdout = &rustdoc_out.stdout_utf8();
python_command().arg("validate_junit.py").stdin_buf(rustdoc_stdout).run();
diff()
.expected_file(expected_xml)
.actual_text("output", rustdoc_stdout)
.normalize(r#"\btime="[0-9.]+""#, r#"time="$$TIME""#)
.run();
}
// FIXME: gone in the next patch
#[track_caller]
fn run_doctests_fail(rlib: &Path, edition: &str) {
let rustdoc_out = rustdoc()
.input("doctest.rs")
.args(&[
"--test",
"--test-args=-Zunstable-options",
"--test-args=--test-threads=1",
"--test-args=--format=junit",
])
.edition(edition)
.env("RUST_BACKTRACE", "0")
.extern_("doctest", rlib.display().to_string())
.run_fail();
let rustdoc_stderr = &rustdoc_out.stderr_utf8();
diff()
.expected_text(
"expected",
r#"
thread 'main' ($TID) panicked at library/test/src/formatters/junit.rs:22:9:
assertion failed: !s.contains('\n')
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
"#,
)
.actual_text("actual", rustdoc_stderr)
.normalize(r#"thread 'main' \([0-9]+\)"#, r#"thread 'main' ($$TID)"#)
.run();
}
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
# Trivial Python script that reads lines from stdin, and checks that each line
# is a well-formed XML document.
#
# This takes advantage of the fact that Python has a built-in XML parser,
# whereas doing the same check in Rust would require us to pull in an XML
# crate just for this relatively-minor test.
#
# If you're trying to remove Python scripts from the test suite, think twice
# before removing this one. You could do so, but it's probably not worth it.
import sys
import xml.etree.ElementTree as ET
# Read the entire output and try to decode it as XML.
junit = sys.stdin.read()
try:
ET.fromstring(junit)
except ET.ParseError:
print("Invalid xml: %r" % junit)
raise