create new tool rustdoc-gui-test

This commit is contained in:
ozkanonur 2023-05-20 14:40:11 +03:00
parent 548978f1d0
commit c36b2092bb
5 changed files with 243 additions and 0 deletions

View file

@ -4324,6 +4324,15 @@ dependencies = [
"tracing-tree",
]
[[package]]
name = "rustdoc-gui-test"
version = "0.1.0"
dependencies = [
"compiletest",
"getopts",
"walkdir",
]
[[package]]
name = "rustdoc-json-types"
version = "0.1.0"

View file

@ -40,6 +40,7 @@ members = [
"src/tools/generate-copyright",
"src/tools/suggest-tests",
"src/tools/generate-windows-sys",
"src/tools/rustdoc-gui-test",
]
exclude = [

View file

@ -0,0 +1,9 @@
[package]
name = "rustdoc-gui-test"
version = "0.1.0"
edition = "2021"
[dependencies]
compiletest = { path = "../compiletest" }
getopts = "0.2"
walkdir = "2"

View file

@ -0,0 +1,62 @@
use getopts::Options;
use std::{env, path::PathBuf};
pub(crate) struct Config {
pub(crate) nodejs: PathBuf,
pub(crate) npm: PathBuf,
pub(crate) rust_src: PathBuf,
pub(crate) out_dir: PathBuf,
pub(crate) initial_cargo: PathBuf,
pub(crate) jobs: String,
pub(crate) test_args: Vec<PathBuf>,
pub(crate) goml_files: Vec<PathBuf>,
pub(crate) rustc: PathBuf,
pub(crate) rustdoc: PathBuf,
pub(crate) verbose: bool,
}
impl Config {
pub(crate) fn from_args(args: Vec<String>) -> Self {
let mut opts = Options::new();
opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH")
.reqopt("", "npm", "absolute path of npm", "PATH")
.reqopt("", "out-dir", "output path of doc compilation", "PATH")
.reqopt("", "rust-src", "root source of the rust source", "PATH")
.reqopt(
"",
"initial-cargo",
"path to cargo to use for compiling tests/rustdoc-gui/src/*",
"PATH",
)
.reqopt("", "jobs", "jobs arg of browser-ui-test", "JOBS")
.optflag("", "verbose", "run tests verbosely, showing all output")
.optmulti("", "test-arg", "args for browser-ui-test", "FLAGS")
.optmulti("", "goml-file", "goml files for testing with browser-ui-test", "LIST");
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
println!("{}", opts.usage(&message));
std::process::exit(1);
}
let matches = &match opts.parse(args_) {
Ok(m) => m,
Err(f) => panic!("{:?}", f),
};
Self {
nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"),
npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"),
rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(),
out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(),
initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(),
jobs: matches.opt_str("jobs").unwrap(),
goml_files: matches.opt_strs("goml-file").iter().map(PathBuf::from).collect(),
test_args: matches.opt_strs("test-arg").iter().map(PathBuf::from).collect(),
rustc: env::var("RUSTC").map(PathBuf::from).unwrap(),
rustdoc: env::var("RUSTDOC").map(PathBuf::from).unwrap(),
verbose: matches.opt_present("verbose"),
}
}
}

View file

@ -0,0 +1,162 @@
use compiletest::header::TestProps;
use config::Config;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Arc;
use std::{env, fs};
mod config;
fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> {
let mut command = Command::new(&npm);
command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
if global {
command.arg("--global");
}
let lines = command
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
.unwrap_or(String::new());
lines
.lines()
.find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
.map(|v| v.to_owned())
}
fn get_browser_ui_test_version(npm: &Path) -> Option<String> {
get_browser_ui_test_version_inner(npm, false)
.or_else(|| get_browser_ui_test_version_inner(npm, true))
}
fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
match fs::read_to_string(
src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"),
) {
Ok(v) => {
if v.trim() != installed_version {
eprintln!(
"⚠️ Installed version of browser-ui-test (`{}`) is different than the \
one used in the CI (`{}`)",
installed_version, v
);
eprintln!(
"You can install this version using `npm update browser-ui-test` or by using \
`npm install browser-ui-test@{}`",
v,
);
}
}
Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
}
}
fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
for entry in walkdir::WalkDir::new(path) {
let entry = entry.ok()?;
if entry.file_type().is_file() && entry.file_name() == "lib.rs" {
return Some(entry.path().to_path_buf());
}
}
None
}
// FIXME: move `bootstrap::util::try_run` into `build_helper` crate
// and use that one instead of creating this function.
fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
let status = match cmd.status() {
Ok(status) => status,
Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cmd, e),
};
if !status.success() && print_cmd_on_fail {
println!(
"\n\ncommand did not execute successfully: {:?}\n\
expected success, got: {}\n\n",
cmd, status
);
}
status.success()
}
fn main() {
let config = Arc::new(Config::from_args(env::args().collect()));
// The goal here is to check if the necessary packages are installed, and if not, we
// panic.
match get_browser_ui_test_version(&config.npm) {
Some(version) => {
// We also check the version currently used in CI and emit a warning if it's not the
// same one.
compare_browser_ui_test_version(&version, &config.rust_src);
}
None => {
eprintln!(
r#"
error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing.
If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test`
"#,
);
panic!("Cannot run rustdoc-gui tests");
}
}
let src_path = config.rust_src.join("tests/rustdoc-gui/src");
for entry in src_path.read_dir().expect("read_dir call failed") {
if let Ok(entry) = entry {
let path = entry.path();
if !path.is_dir() {
continue;
}
let mut cargo = Command::new(&config.initial_cargo);
cargo
.arg("doc")
.arg("--target-dir")
.arg(&config.out_dir)
.env("RUSTC_BOOTSTRAP", "1")
.env("RUSTDOC", &config.rustdoc)
.env("RUSTC", &config.rustc)
.current_dir(path);
if let Some(librs) = find_librs(entry.path()) {
let compiletest_c = compiletest::common::Config {
edition: None,
mode: compiletest::common::Mode::Rustdoc,
..Default::default()
};
let test_props = TestProps::from_file(&librs, None, &compiletest_c);
if !test_props.compile_flags.is_empty() {
cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" "));
}
if let Some(flags) = &test_props.run_flags {
cargo.arg(flags);
}
}
try_run(&mut cargo, config.verbose);
}
}
let mut command = Command::new(&config.nodejs);
command
.arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js"))
.arg("--jobs")
.arg(&config.jobs)
.arg("--doc-folder")
.arg(config.out_dir.join("doc"))
.arg("--tests-folder")
.arg(config.rust_src.join("tests/rustdoc-gui"));
for file in &config.goml_files {
command.arg("--file").arg(file);
}
command.args(&config.test_args);
try_run(&mut command, config.verbose);
}