Skip to content

Commit c36b209

Browse files
committed
create new tool rustdoc-gui-test
1 parent 548978f commit c36b209

File tree

5 files changed

+243
-0
lines changed

5 files changed

+243
-0
lines changed

Cargo.lock

+9
Original file line numberDiff line numberDiff line change
@@ -4324,6 +4324,15 @@ dependencies = [
43244324
"tracing-tree",
43254325
]
43264326

4327+
[[package]]
4328+
name = "rustdoc-gui-test"
4329+
version = "0.1.0"
4330+
dependencies = [
4331+
"compiletest",
4332+
"getopts",
4333+
"walkdir",
4334+
]
4335+
43274336
[[package]]
43284337
name = "rustdoc-json-types"
43294338
version = "0.1.0"

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ members = [
4040
"src/tools/generate-copyright",
4141
"src/tools/suggest-tests",
4242
"src/tools/generate-windows-sys",
43+
"src/tools/rustdoc-gui-test",
4344
]
4445

4546
exclude = [

src/tools/rustdoc-gui-test/Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "rustdoc-gui-test"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
compiletest = { path = "../compiletest" }
8+
getopts = "0.2"
9+
walkdir = "2"
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use getopts::Options;
2+
use std::{env, path::PathBuf};
3+
4+
pub(crate) struct Config {
5+
pub(crate) nodejs: PathBuf,
6+
pub(crate) npm: PathBuf,
7+
pub(crate) rust_src: PathBuf,
8+
pub(crate) out_dir: PathBuf,
9+
pub(crate) initial_cargo: PathBuf,
10+
pub(crate) jobs: String,
11+
pub(crate) test_args: Vec<PathBuf>,
12+
pub(crate) goml_files: Vec<PathBuf>,
13+
pub(crate) rustc: PathBuf,
14+
pub(crate) rustdoc: PathBuf,
15+
pub(crate) verbose: bool,
16+
}
17+
18+
impl Config {
19+
pub(crate) fn from_args(args: Vec<String>) -> Self {
20+
let mut opts = Options::new();
21+
opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH")
22+
.reqopt("", "npm", "absolute path of npm", "PATH")
23+
.reqopt("", "out-dir", "output path of doc compilation", "PATH")
24+
.reqopt("", "rust-src", "root source of the rust source", "PATH")
25+
.reqopt(
26+
"",
27+
"initial-cargo",
28+
"path to cargo to use for compiling tests/rustdoc-gui/src/*",
29+
"PATH",
30+
)
31+
.reqopt("", "jobs", "jobs arg of browser-ui-test", "JOBS")
32+
.optflag("", "verbose", "run tests verbosely, showing all output")
33+
.optmulti("", "test-arg", "args for browser-ui-test", "FLAGS")
34+
.optmulti("", "goml-file", "goml files for testing with browser-ui-test", "LIST");
35+
36+
let (argv0, args_) = args.split_first().unwrap();
37+
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
38+
let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
39+
println!("{}", opts.usage(&message));
40+
std::process::exit(1);
41+
}
42+
43+
let matches = &match opts.parse(args_) {
44+
Ok(m) => m,
45+
Err(f) => panic!("{:?}", f),
46+
};
47+
48+
Self {
49+
nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"),
50+
npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"),
51+
rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(),
52+
out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(),
53+
initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(),
54+
jobs: matches.opt_str("jobs").unwrap(),
55+
goml_files: matches.opt_strs("goml-file").iter().map(PathBuf::from).collect(),
56+
test_args: matches.opt_strs("test-arg").iter().map(PathBuf::from).collect(),
57+
rustc: env::var("RUSTC").map(PathBuf::from).unwrap(),
58+
rustdoc: env::var("RUSTDOC").map(PathBuf::from).unwrap(),
59+
verbose: matches.opt_present("verbose"),
60+
}
61+
}
62+
}
+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
use compiletest::header::TestProps;
2+
use config::Config;
3+
use std::path::{Path, PathBuf};
4+
use std::process::Command;
5+
use std::sync::Arc;
6+
use std::{env, fs};
7+
8+
mod config;
9+
10+
fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
11+
let mut command = Command::new(&npm);
12+
command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
13+
if global {
14+
command.arg("--global");
15+
}
16+
let lines = command
17+
.output()
18+
.map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
19+
.unwrap_or(String::new());
20+
lines
21+
.lines()
22+
.find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
23+
.map(|v| v.to_owned())
24+
}
25+
26+
fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
27+
get_browser_ui_test_version_inner(npm, false)
28+
.or_else(|| get_browser_ui_test_version_inner(npm, true))
29+
}
30+
31+
fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
32+
match fs::read_to_string(
33+
src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"),
34+
) {
35+
Ok(v) => {
36+
if v.trim() != installed_version {
37+
eprintln!(
38+
"⚠️ Installed version of browser-ui-test (`{}`) is different than the \
39+
one used in the CI (`{}`)",
40+
installed_version, v
41+
);
42+
eprintln!(
43+
"You can install this version using `npm update browser-ui-test` or by using \
44+
`npm install browser-ui-test@{}`",
45+
v,
46+
);
47+
}
48+
}
49+
Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
50+
}
51+
}
52+
53+
fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
54+
for entry in walkdir::WalkDir::new(path) {
55+
let entry = entry.ok()?;
56+
if entry.file_type().is_file() && entry.file_name() == "lib.rs" {
57+
return Some(entry.path().to_path_buf());
58+
}
59+
}
60+
None
61+
}
62+
63+
// FIXME: move `bootstrap::util::try_run` into `build_helper` crate
64+
// and use that one instead of creating this function.
65+
fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
66+
let status = match cmd.status() {
67+
Ok(status) => status,
68+
Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cmd, e),
69+
};
70+
if !status.success() && print_cmd_on_fail {
71+
println!(
72+
"\n\ncommand did not execute successfully: {:?}\n\
73+
expected success, got: {}\n\n",
74+
cmd, status
75+
);
76+
}
77+
status.success()
78+
}
79+
80+
fn main() {
81+
let config = Arc::new(Config::from_args(env::args().collect()));
82+
83+
// The goal here is to check if the necessary packages are installed, and if not, we
84+
// panic.
85+
match get_browser_ui_test_version(&config.npm) {
86+
Some(version) => {
87+
// We also check the version currently used in CI and emit a warning if it's not the
88+
// same one.
89+
compare_browser_ui_test_version(&version, &config.rust_src);
90+
}
91+
None => {
92+
eprintln!(
93+
r#"
94+
error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing.
95+
96+
If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test`
97+
"#,
98+
);
99+
100+
panic!("Cannot run rustdoc-gui tests");
101+
}
102+
}
103+
104+
let src_path = config.rust_src.join("tests/rustdoc-gui/src");
105+
for entry in src_path.read_dir().expect("read_dir call failed") {
106+
if let Ok(entry) = entry {
107+
let path = entry.path();
108+
109+
if !path.is_dir() {
110+
continue;
111+
}
112+
113+
let mut cargo = Command::new(&config.initial_cargo);
114+
cargo
115+
.arg("doc")
116+
.arg("--target-dir")
117+
.arg(&config.out_dir)
118+
.env("RUSTC_BOOTSTRAP", "1")
119+
.env("RUSTDOC", &config.rustdoc)
120+
.env("RUSTC", &config.rustc)
121+
.current_dir(path);
122+
123+
if let Some(librs) = find_librs(entry.path()) {
124+
let compiletest_c = compiletest::common::Config {
125+
edition: None,
126+
mode: compiletest::common::Mode::Rustdoc,
127+
..Default::default()
128+
};
129+
130+
let test_props = TestProps::from_file(&librs, None, &compiletest_c);
131+
132+
if !test_props.compile_flags.is_empty() {
133+
cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" "));
134+
}
135+
136+
if let Some(flags) = &test_props.run_flags {
137+
cargo.arg(flags);
138+
}
139+
}
140+
141+
try_run(&mut cargo, config.verbose);
142+
}
143+
}
144+
145+
let mut command = Command::new(&config.nodejs);
146+
command
147+
.arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js"))
148+
.arg("--jobs")
149+
.arg(&config.jobs)
150+
.arg("--doc-folder")
151+
.arg(config.out_dir.join("doc"))
152+
.arg("--tests-folder")
153+
.arg(config.rust_src.join("tests/rustdoc-gui"));
154+
155+
for file in &config.goml_files {
156+
command.arg("--file").arg(file);
157+
}
158+
159+
command.args(&config.test_args);
160+
161+
try_run(&mut command, config.verbose);
162+
}

0 commit comments

Comments
 (0)