Skip to content

Commit

Permalink
Rollup merge of rust-lang#128161 - EtomicBomb:just-compiletest, r=not…
Browse files Browse the repository at this point in the history
…riddle

nested aux-build in tests/rustdoc/ tests

* Fixes bug that prevented using nested aux-build in `tests/rustdoc/` tests. Before, `fn document` and the auxiliary builder disagreed about where to find the nested aux-build source file (`auxiliary/auxiliary/aux.rs` vs `auxiliary/aux.rs`), preventing them from building. Picked the latter in line with other builders in compiletest.
* Adds `//@ doc-flags` header, which forwards flags to rustdoc and not rustc.
* Adds `//@ unique-doc-out-dir` header, which sets the --out-dir for the rustdoc invocation to a unique directory: `<root out dir>/docs/<test name>/doc`
* Changes working directory of the rustdoc invocation to the root out directory (common among all aux-builds). Prior art: exec_compiled_test in runtest.rs
* Adds tests that use nested aux builds and new headers

These changes provide useful capabilities for writing rustdoc tests on their own. They are also needed to test the implementation for the [mergable-rustdoc-cross-crate-info](rust-lang/rfcs#3662) RFC.

try-job: x86_64-msvc
  • Loading branch information
matthiaskrgr authored Aug 2, 2024
2 parents 84b403f + bd23e0e commit 168972f
Show file tree
Hide file tree
Showing 31 changed files with 318 additions and 35 deletions.
2 changes: 2 additions & 0 deletions src/tools/compiletest/src/command-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"check-test-line-numbers-match",
"compare-output-lines-by-subset",
"compile-flags",
"doc-flags",
"dont-check-compiler-stderr",
"dont-check-compiler-stdout",
"dont-check-failure-status",
Expand Down Expand Up @@ -226,6 +227,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"should-ice",
"stderr-per-bitwidth",
"test-mir-pass",
"unique-doc-out-dir",
"unset-exec-env",
"unset-rustc-env",
// Used by the tidy check `unknown_revision`.
Expand Down
13 changes: 13 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub struct TestProps {
pub compile_flags: Vec<String>,
// Extra flags to pass when the compiled code is run (such as --bench)
pub run_flags: Vec<String>,
/// Extra flags to pass to rustdoc but not the compiler.
pub doc_flags: Vec<String>,
// If present, the name of a file that this test should match when
// pretty-printed
pub pp_exact: Option<PathBuf>,
Expand Down Expand Up @@ -122,6 +124,9 @@ pub struct TestProps {
pub unset_exec_env: Vec<String>,
// Build documentation for all specified aux-builds as well
pub build_aux_docs: bool,
/// Build the documentation for each crate in a unique output directory.
/// Uses <root output directory>/docs/<test name>/doc
pub unique_doc_out_dir: bool,
// Flag to force a crate to be built with the host architecture
pub force_host: bool,
// Check stdout for error-pattern output as well as stderr
Expand Down Expand Up @@ -220,8 +225,10 @@ mod directives {
pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern";
pub const COMPILE_FLAGS: &'static str = "compile-flags";
pub const RUN_FLAGS: &'static str = "run-flags";
pub const DOC_FLAGS: &'static str = "doc-flags";
pub const SHOULD_ICE: &'static str = "should-ice";
pub const BUILD_AUX_DOCS: &'static str = "build-aux-docs";
pub const UNIQUE_DOC_OUT_DIR: &'static str = "unique-doc-out-dir";
pub const FORCE_HOST: &'static str = "force-host";
pub const CHECK_STDOUT: &'static str = "check-stdout";
pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
Expand Down Expand Up @@ -267,6 +274,7 @@ impl TestProps {
regex_error_patterns: vec![],
compile_flags: vec![],
run_flags: vec![],
doc_flags: vec![],
pp_exact: None,
aux_builds: vec![],
aux_bins: vec![],
Expand All @@ -281,6 +289,7 @@ impl TestProps {
exec_env: vec![],
unset_exec_env: vec![],
build_aux_docs: false,
unique_doc_out_dir: false,
force_host: false,
check_stdout: false,
check_run_results: false,
Expand Down Expand Up @@ -378,6 +387,8 @@ impl TestProps {
|r| r,
);

config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);

fn split_flags(flags: &str) -> Vec<String> {
// Individual flags can be single-quoted to preserve spaces; see
// <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
Expand Down Expand Up @@ -415,6 +426,8 @@ impl TestProps {

config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs);
config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut self.unique_doc_out_dir);

config.set_name_directive(ln, FORCE_HOST, &mut self.force_host);
config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout);
config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results);
Expand Down
92 changes: 58 additions & 34 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// ignore-tidy-filelength

use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::ffi::{OsStr, OsString};
use std::fs::{self, create_dir_all, File, OpenOptions};
Expand Down Expand Up @@ -723,7 +724,7 @@ impl<'test> TestCx<'test> {
self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
rustc.args(&self.props.compile_flags);

self.compose_and_run_compiler(rustc, Some(src))
self.compose_and_run_compiler(rustc, Some(src), self.testpaths)
}

fn run_debuginfo_test(&self) {
Expand Down Expand Up @@ -1579,13 +1580,15 @@ impl<'test> TestCx<'test> {
passes,
);

self.compose_and_run_compiler(rustc, None)
self.compose_and_run_compiler(rustc, None, self.testpaths)
}

fn document(&self, out_dir: &Path) -> ProcRes {
/// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run.
/// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
if self.props.build_aux_docs {
for rel_ab in &self.props.aux_builds {
let aux_testpaths = self.compute_aux_test_paths(&self.testpaths, rel_ab);
let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
let aux_props =
self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
let aux_cx = TestCx {
Expand All @@ -1596,7 +1599,9 @@ impl<'test> TestCx<'test> {
};
// Create the directory for the stdout/stderr files.
create_dir_all(aux_cx.output_base_dir()).unwrap();
let auxres = aux_cx.document(out_dir);
// use root_testpaths here, because aux-builds should have the
// same --out-dir and auxiliary directory.
let auxres = aux_cx.document(&root_out_dir, root_testpaths);
if !auxres.status.success() {
return auxres;
}
Expand All @@ -1606,21 +1611,40 @@ impl<'test> TestCx<'test> {
let aux_dir = self.aux_output_dir_name();

let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed");
let mut rustdoc = Command::new(rustdoc_path);

// actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire
// test
let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir {
let file_name = self.testpaths.file.file_stem().expect("file name should not be empty");
let out_dir = PathBuf::from_iter([
root_out_dir,
Path::new("docs"),
Path::new(file_name),
Path::new("doc"),
]);
create_dir_all(&out_dir).unwrap();
Cow::Owned(out_dir)
} else {
Cow::Borrowed(root_out_dir)
};

let mut rustdoc = Command::new(rustdoc_path);
let current_dir = output_base_dir(self.config, root_testpaths, self.safe_revision());
rustdoc.current_dir(current_dir);
rustdoc
.arg("-L")
.arg(self.config.run_lib_path.to_str().unwrap())
.arg("-L")
.arg(aux_dir)
.arg("-o")
.arg(out_dir)
.arg(out_dir.as_ref())
.arg("--deny")
.arg("warnings")
.arg(&self.testpaths.file)
.arg("-A")
.arg("internal_features")
.args(&self.props.compile_flags);
.args(&self.props.compile_flags)
.args(&self.props.doc_flags);

if self.config.mode == RustdocJson {
rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options");
Expand All @@ -1630,7 +1654,7 @@ impl<'test> TestCx<'test> {
rustdoc.arg(format!("-Clinker={}", linker));
}

self.compose_and_run_compiler(rustdoc, None)
self.compose_and_run_compiler(rustdoc, None, root_testpaths)
}

fn exec_compiled_test(&self) -> ProcRes {
Expand Down Expand Up @@ -1828,9 +1852,16 @@ impl<'test> TestCx<'test> {
}
}

fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
/// `root_testpaths` refers to the path of the original test.
/// the auxiliary and the test with an aux-build have the same `root_testpaths`.
fn compose_and_run_compiler(
&self,
mut rustc: Command,
input: Option<String>,
root_testpaths: &TestPaths,
) -> ProcRes {
let aux_dir = self.aux_output_dir();
self.build_all_auxiliary(&self.testpaths, &aux_dir, &mut rustc);
self.build_all_auxiliary(root_testpaths, &aux_dir, &mut rustc);

rustc.envs(self.props.rustc_env.clone());
self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove);
Expand Down Expand Up @@ -2545,7 +2576,7 @@ impl<'test> TestCx<'test> {
Vec::new(),
);

let proc_res = self.compose_and_run_compiler(rustc, None);
let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
let output_path = self.get_filecheck_file("ll");
(proc_res, output_path)
}
Expand Down Expand Up @@ -2581,7 +2612,7 @@ impl<'test> TestCx<'test> {
Vec::new(),
);

let proc_res = self.compose_and_run_compiler(rustc, None);
let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
let output_path = self.get_filecheck_file("s");
(proc_res, output_path)
}
Expand Down Expand Up @@ -2664,7 +2695,7 @@ impl<'test> TestCx<'test> {
let out_dir = self.output_base_dir();
remove_and_create_dir_all(&out_dir);

let proc_res = self.document(&out_dir);
let proc_res = self.document(&out_dir, &self.testpaths);
if !proc_res.status.success() {
self.fatal_proc_rec("rustdoc failed!", &proc_res);
}
Expand Down Expand Up @@ -2723,7 +2754,7 @@ impl<'test> TestCx<'test> {
let aux_dir = new_rustdoc.aux_output_dir();
new_rustdoc.build_all_auxiliary(&new_rustdoc.testpaths, &aux_dir, &mut rustc);

let proc_res = new_rustdoc.document(&compare_dir);
let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths);
if !proc_res.status.success() {
eprintln!("failed to run nightly rustdoc");
return;
Expand Down Expand Up @@ -2847,7 +2878,7 @@ impl<'test> TestCx<'test> {
let out_dir = self.output_base_dir();
remove_and_create_dir_all(&out_dir);

let proc_res = self.document(&out_dir);
let proc_res = self.document(&out_dir, &self.testpaths);
if !proc_res.status.success() {
self.fatal_proc_rec("rustdoc failed!", &proc_res);
}
Expand Down Expand Up @@ -2923,31 +2954,24 @@ impl<'test> TestCx<'test> {
fn check_rustdoc_test_option(&self, res: ProcRes) {
let mut other_files = Vec::new();
let mut files: HashMap<String, Vec<usize>> = HashMap::new();
let cwd = env::current_dir().unwrap();
files.insert(
self.testpaths
.file
.strip_prefix(&cwd)
.unwrap_or(&self.testpaths.file)
.to_str()
.unwrap()
.replace('\\', "/"),
self.get_lines(&self.testpaths.file, Some(&mut other_files)),
);
let normalized = fs::canonicalize(&self.testpaths.file).expect("failed to canonicalize");
let normalized = normalized.to_str().unwrap().replace('\\', "/");
files.insert(normalized, self.get_lines(&self.testpaths.file, Some(&mut other_files)));
for other_file in other_files {
let mut path = self.testpaths.file.clone();
path.set_file_name(&format!("{}.rs", other_file));
files.insert(
path.strip_prefix(&cwd).unwrap_or(&path).to_str().unwrap().replace('\\', "/"),
self.get_lines(&path, None),
);
let path = fs::canonicalize(path).expect("failed to canonicalize");
let normalized = path.to_str().unwrap().replace('\\', "/");
files.insert(normalized, self.get_lines(&path, None));
}

let mut tested = 0;
for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
if let Some((left, right)) = s.split_once(" - ") {
let path = left.rsplit("test ").next().unwrap();
if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
let path = fs::canonicalize(&path).expect("failed to canonicalize");
let path = path.to_str().unwrap().replace('\\', "/");
if let Some(ref mut v) = files.get_mut(&path) {
tested += 1;
let mut iter = right.split("(line ");
iter.next();
Expand Down Expand Up @@ -3779,7 +3803,7 @@ impl<'test> TestCx<'test> {
if let Some(nodejs) = &self.config.nodejs {
let out_dir = self.output_base_dir();

self.document(&out_dir);
self.document(&out_dir, &self.testpaths);

let root = self.config.find_rust_src_root().unwrap();
let file_stem =
Expand Down Expand Up @@ -4095,7 +4119,7 @@ impl<'test> TestCx<'test> {
rustc.arg(crate_name);
}

let res = self.compose_and_run_compiler(rustc, None);
let res = self.compose_and_run_compiler(rustc, None, self.testpaths);
if !res.status.success() {
self.fatal_proc_rec("failed to compile fixed code", &res);
}
Expand Down
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<'test> TestCx<'test> {

rustdoc_cmd.arg(&self.testpaths.file);

let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None, self.testpaths);
if !proc_res.status.success() {
self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//@ build-aux-docs
pub struct Quebec;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//@ aux-build:q.rs
//@ build-aux-docs
extern crate q;
pub trait Tango {}
16 changes: 16 additions & 0 deletions tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ aux-build:t.rs
//@ build-aux-docs
//@ has q/struct.Quebec.html
//@ has s/struct.Sierra.html
//@ has t/trait.Tango.html
//@ hasraw s/struct.Sierra.html 'Tango'
//@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
//@ hasraw search-index.js 'Tango'
//@ hasraw search-index.js 'Sierra'
//@ hasraw search-index.js 'Quebec'

// We document multiple crates into the same output directory, which
// merges the cross-crate information. Everything is available.
extern crate t;
pub struct Sierra;
impl t::Tango for Sierra {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//@ build-aux-docs
//@ doc-flags:--enable-index-page
//@ doc-flags:-Zunstable-options

pub struct Quebec;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//@ aux-build:q.rs
//@ build-aux-docs
//@ doc-flags:--enable-index-page
//@ doc-flags:-Zunstable-options

extern crate q;
pub trait Tango {}
24 changes: 24 additions & 0 deletions tests/rustdoc/cross-crate-info/cargo-transitive/s.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ aux-build:t.rs
//@ build-aux-docs
//@ doc-flags:--enable-index-page
//@ doc-flags:-Zunstable-options

//@ has index.html
//@ has index.html '//h1' 'List of all crates'
//@ has index.html '//ul[@class="all-items"]//a[@href="q/index.html"]' 'q'
//@ has index.html '//ul[@class="all-items"]//a[@href="s/index.html"]' 's'
//@ has index.html '//ul[@class="all-items"]//a[@href="t/index.html"]' 't'
//@ has q/struct.Quebec.html
//@ has s/struct.Sierra.html
//@ has t/trait.Tango.html
//@ hasraw s/struct.Sierra.html 'Tango'
//@ hasraw trait.impl/t/trait.Tango.js 'struct.Sierra.html'
//@ hasraw search-index.js 'Tango'
//@ hasraw search-index.js 'Sierra'
//@ hasraw search-index.js 'Quebec'

// We document multiple crates into the same output directory, which
// merges the cross-crate information. Everything is available.
extern crate t;
pub struct Sierra;
impl t::Tango for Sierra {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//@ build-aux-docs
pub trait Foxtrot {}
14 changes: 14 additions & 0 deletions tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//@ aux-build:f.rs
//@ build-aux-docs
//@ has e/enum.Echo.html
//@ has f/trait.Foxtrot.html
//@ hasraw e/enum.Echo.html 'Foxtrot'
//@ hasraw trait.impl/f/trait.Foxtrot.js 'enum.Echo.html'
//@ hasraw search-index.js 'Foxtrot'
//@ hasraw search-index.js 'Echo'

// document two crates in the same way that cargo does. do not provide
// --enable-index-page
extern crate f;
pub enum Echo {}
impl f::Foxtrot for Echo {}
5 changes: 5 additions & 0 deletions tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//@ build-aux-docs
//@ doc-flags:--enable-index-page
//@ doc-flags:-Zunstable-options

pub trait Foxtrot {}
Loading

0 comments on commit 168972f

Please sign in to comment.