Auto merge of #125752 - jieyouxu:kaboom, r=Kobzol

run-make: arm command wrappers with drop bombs

This PR is one in a series of cleanups to run-make tests and the run-make-support library.

### Summary

It's easy to forget to actually executed constructed command wrappers, e.g. `rustc().input("foo.rs")` but forget the `run()`, so to help catch these mistakes, we arm command wrappers with drop bombs on construction to force them to be executed by test code.

This PR also removes the `Deref`/`DerefMut` impl for our custom `Command` which derefs to `std::process::Command` because it can cause issues when trying to use a custom command:

```rs
htmldocck().arg().run()
```

fails to compile because the `arg()` is resolved to `std::process::Command::arg`, which returns `&mut std::process::Command` that doesn't have a `run()` command.

This PR also:

- Removes `env_var` on the `impl_common_helper` macro that was wrongly named and is a footgun (no users).
- Bumps the run-make-support library to version `0.1.0`.
- Adds a changelog to the support library.

### Details

Especially for command wrappers like `Rustc`, it's very easy to build up
a command invocation but forget to actually execute it, e.g. by using
`run()`. This commit adds "drop bombs" to command wrappers, which are
armed on command wrapper construction, and only defused if the command
is executed (through `run`, `run_fail`).

If the test writer forgets to execute the command, the drop bomb will
"explode" and panic with an error message. This is so that tests don't
silently pass with constructed-but-not-executed command wrappers.

This PR is best reviewed commit-by-commit.

try-job: x86_64-msvc
This commit is contained in:
bors 2024-06-11 11:29:02 +00:00
commit 20ba13c38e
22 changed files with 280 additions and 80 deletions

View File

@ -3452,7 +3452,7 @@ dependencies = [
[[package]]
name = "run_make_support"
version = "0.0.0"
version = "0.1.0"
dependencies = [
"gimli 0.28.1",
"object 0.34.0",

View File

@ -0,0 +1,67 @@
# Changelog
All notable changes to the `run_make_support` library should be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the support
library should adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) even if it's
not intended for public consumption (it's moreso to help internally, to help test writers track
changes to the support library).
This support library will probably never reach 1.0. Please bump the minor version in `Cargo.toml` if
you make any breaking changes or other significant changes, or bump the patch version for bug fixes.
## [0.1.0] - 2024-06-09
### Changed
- Use *drop bombs* to enforce that commands are executed; a command invocation will panic if it is
constructed but never executed. Execution methods `Command::{run, run_fail}` will defuse the drop
bomb.
- Added `Command` helpers that forward to `std::process::Command` counterparts.
### Removed
- The `env_var` method which was incorrectly named and is `env_clear` underneath and is a footgun
from `impl_common_helpers`. For example, removing `TMPDIR` on Unix and `TMP`/`TEMP` breaks
`std::env::temp_dir` and wrecks anything using that, such as rustc's codgen.
- Removed `Deref`/`DerefMut` for `run_make_support::Command` -> `std::process::Command` because it
causes a method chain like `htmldocck().arg().run()` to fail, because `arg()` resolves to
`std::process::Command` which also returns a `&mut std::process::Command`, causing the `run()` to
be not found.
## [0.0.0] - 2024-06-09
Consider this version to contain all changes made to the support library before we started to track
changes in this changelog.
### Added
- Custom command wrappers around `std::process::Command` (`run_make_support::Command`) and custom
wrapper around `std::process::Output` (`CompletedProcess`) to make it more convenient to work with
commands and their output, and help avoid forgetting to check for exit status.
- `Command`: `set_stdin`, `run`, `run_fail`.
- `CompletedProcess`: `std{err,out}_utf8`, `status`, `assert_std{err,out}_{equals, contains,
not_contains}`, `assert_exit_code`.
- `impl_common_helpers` macro to avoid repeating adding common convenience methods, including:
- Environment manipulation methods: `env`, `env_remove`
- Command argument providers: `arg`, `args`
- Common invocation inspection (of the command invocation up until `inspect` is called):
`inspect`
- Execution methods: `run` (for commands expected to succeed execution, exit status `0`) and
`run_fail` (for commands expected to fail execution, exit status non-zero).
- Command wrappers around: `rustc`, `clang`, `cc`, `rustc`, `rustdoc`, `llvm-readobj`.
- Thin helpers to construct `python` and `htmldocck` commands.
- `run` and `run_fail` (like `Command::{run, run_fail}`) for running binaries, which sets suitable
env vars (like `LD_LIB_PATH` or equivalent, `TARGET_RPATH_ENV`, `PATH` on Windows).
- Pseudo command `diff` which has similar functionality as the cli util but not the same API.
- Convenience panic-on-fail helpers `env_var`, `env_var_os`, `cwd` for their `std::env` conterparts.
- Convenience panic-on-fail helpers for reading respective env vars: `target`, `source_root`.
- Platform check helpers: `is_windows`, `is_msvc`, `cygpath_windows`, `uname`.
- fs helpers: `copy_dir_all`.
- `recursive_diff` helper.
- Generic `assert_not_contains` helper.
- Scoped run-with-teardown helper `run_in_tmpdir` which is designed to run commands in a temporary
directory that is cleared when closure returns.
- Helpers for constructing the name of binaries and libraries: `rust_lib_name`, `static_lib_name`,
`bin_name`, `dynamic_lib_name`.
- Re-export libraries: `gimli`, `object`, `regex`, `wasmparsmer`.

View File

@ -1,6 +1,6 @@
[package]
name = "run_make_support"
version = "0.0.0"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -7,6 +7,7 @@
///
/// WARNING: This means that what flags are accepted by the underlying C compiler is
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
#[track_caller]
pub fn cc() -> Cc {
Cc::new()
}
@ -25,6 +26,7 @@ impl Cc {
///
/// WARNING: This means that what flags are accepted by the underlying C compile is
/// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`.
#[track_caller]
pub fn new() -> Self {
let compiler = env_var("CC");
@ -84,11 +86,6 @@ pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg(path.as_ref());
self
}
/// Get the [`Output`][::std::process::Output] of the finished process.
pub fn command_output(&mut self) -> ::std::process::Output {
self.cmd.output().expect("failed to get output of finished process")
}
}
/// `EXTRACFLAGS`

View File

@ -4,6 +4,7 @@
use crate::{bin_name, env_var};
/// Construct a new `clang` invocation. `clang` is not always available for all targets.
#[track_caller]
pub fn clang() -> Clang {
Clang::new()
}
@ -18,6 +19,7 @@ pub struct Clang {
impl Clang {
/// Construct a new `clang` invocation. `clang` is not always available for all targets.
#[track_caller]
pub fn new() -> Self {
let clang = env_var("CLANG");
let cmd = Command::new(clang);

View File

@ -1,36 +1,107 @@
use crate::{assert_not_contains, handle_failed_output};
use std::ffi;
use std::ffi::OsStr;
use std::io::Write;
use std::ops::{Deref, DerefMut};
use std::panic;
use std::path::Path;
use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
/// This is a custom command wrapper that simplifies working with commands
/// and makes it easier to ensure that we check the exit status of executed
/// processes.
use crate::drop_bomb::DropBomb;
use crate::{assert_not_contains, handle_failed_output};
/// This is a custom command wrapper that simplifies working with commands and makes it easier to
/// ensure that we check the exit status of executed processes.
///
/// # A [`Command`] must be executed
///
/// A [`Command`] is armed by a [`DropBomb`] on construction to enforce that it will be executed. If
/// a [`Command`] is constructed but never executed, the drop bomb will explode and cause the test
/// to panic. Execution methods [`run`] and [`run_fail`] will defuse the drop bomb. A test
/// containing constructed but never executed commands is dangerous because it can give a false
/// sense of confidence.
///
/// [`run`]: Self::run
/// [`run_fail`]: Self::run_fail
#[derive(Debug)]
pub struct Command {
cmd: StdCommand,
stdin: Option<Box<[u8]>>,
drop_bomb: DropBomb,
}
impl Command {
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
Self { cmd: StdCommand::new(program), stdin: None }
#[track_caller]
pub fn new<P: AsRef<OsStr>>(program: P) -> Self {
let program = program.as_ref();
Self { cmd: StdCommand::new(program), stdin: None, drop_bomb: DropBomb::arm(program) }
}
pub fn set_stdin(&mut self, stdin: Box<[u8]>) {
self.stdin = Some(stdin);
}
/// Specify an environment variable.
pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<ffi::OsStr>,
V: AsRef<ffi::OsStr>,
{
self.cmd.env(key, value);
self
}
/// Remove an environmental variable.
pub fn env_remove<K>(&mut self, key: K) -> &mut Self
where
K: AsRef<ffi::OsStr>,
{
self.cmd.env_remove(key);
self
}
/// Generic command argument provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
pub fn arg<S>(&mut self, arg: S) -> &mut Self
where
S: AsRef<ffi::OsStr>,
{
self.cmd.arg(arg);
self
}
/// Generic command arguments provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
pub fn args<S>(&mut self, args: &[S]) -> &mut Self
where
S: AsRef<ffi::OsStr>,
{
self.cmd.args(args);
self
}
/// Inspect what the underlying [`std::process::Command`] is up to the
/// current construction.
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
where
I: FnOnce(&StdCommand),
{
inspector(&self.cmd);
self
}
/// Set the path where the command will be run.
pub fn current_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.current_dir(path);
self
}
/// Run the constructed command and assert that it is successfully run.
#[track_caller]
pub fn run(&mut self) -> CompletedProcess {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let output = self.command_output();
if !output.status().success() {
handle_failed_output(&self, output, caller_line_number);
handle_failed_output(&self, output, panic::Location::caller().line());
}
output
}
@ -38,18 +109,16 @@ pub fn run(&mut self) -> CompletedProcess {
/// Run the constructed command and assert that it does not successfully run.
#[track_caller]
pub fn run_fail(&mut self) -> CompletedProcess {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let output = self.command_output();
if output.status().success() {
handle_failed_output(&self, output, caller_line_number);
handle_failed_output(&self, output, panic::Location::caller().line());
}
output
}
#[track_caller]
pub(crate) fn command_output(&mut self) -> CompletedProcess {
fn command_output(&mut self) -> CompletedProcess {
self.drop_bomb.defuse();
// let's make sure we piped all the input and outputs
self.cmd.stdin(Stdio::piped());
self.cmd.stdout(Stdio::piped());
@ -71,20 +140,6 @@ pub(crate) fn command_output(&mut self) -> CompletedProcess {
}
}
impl Deref for Command {
type Target = StdCommand;
fn deref(&self) -> &Self::Target {
&self.cmd
}
}
impl DerefMut for Command {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cmd
}
}
/// Represents the result of an executed process.
/// The various `assert_` helper methods should preferably be used for
/// checking the contents of stdout/stderr.

View File

@ -2,9 +2,12 @@
use similar::TextDiff;
use std::path::Path;
use crate::drop_bomb::DropBomb;
#[cfg(test)]
mod tests;
#[track_caller]
pub fn diff() -> Diff {
Diff::new()
}
@ -16,10 +19,12 @@ pub struct Diff {
actual: Option<String>,
actual_name: Option<String>,
normalizers: Vec<(String, String)>,
drop_bomb: DropBomb,
}
impl Diff {
/// Construct a bare `diff` invocation.
#[track_caller]
pub fn new() -> Self {
Self {
expected: None,
@ -27,6 +32,7 @@ pub fn new() -> Self {
actual: None,
actual_name: None,
normalizers: Vec::new(),
drop_bomb: DropBomb::arm("diff"),
}
}
@ -79,9 +85,9 @@ pub fn normalize<R: Into<String>, I: Into<String>>(
self
}
/// Executes the diff process, prints any differences to the standard error.
#[track_caller]
pub fn run(&self) {
pub fn run(&mut self) {
self.drop_bomb.defuse();
let expected = self.expected.as_ref().expect("expected text not set");
let mut actual = self.actual.as_ref().expect("actual text not set").to_string();
let expected_name = self.expected_name.as_ref().unwrap();

View File

@ -0,0 +1,50 @@
//! This module implements "drop bombs" intended for use by command wrappers to ensure that the
//! constructed commands are *eventually* executed. This is exactly like `rustc_errors::Diag` where
//! we force every `Diag` to be consumed or we emit a bug, but we panic instead.
//!
//! This is adapted from <https://docs.rs/drop_bomb/latest/drop_bomb/> and simplified for our
//! purposes.
use std::ffi::{OsStr, OsString};
use std::panic;
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub(crate) struct DropBomb {
command: OsString,
defused: bool,
armed_line: u32,
}
impl DropBomb {
/// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then
/// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help
/// propagate the caller info from rmake.rs.
#[track_caller]
pub(crate) fn arm<S: AsRef<OsStr>>(command: S) -> DropBomb {
DropBomb {
command: command.as_ref().into(),
defused: false,
armed_line: panic::Location::caller().line(),
}
}
/// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped.
pub(crate) fn defuse(&mut self) {
self.defused = true;
}
}
impl Drop for DropBomb {
fn drop(&mut self) {
if !self.defused && !std::thread::panicking() {
panic!(
"command constructed but not executed at line {}: `{}`",
self.armed_line,
self.command.to_string_lossy()
)
}
}
}

View File

@ -0,0 +1,15 @@
use super::DropBomb;
#[test]
#[should_panic]
fn test_arm() {
let bomb = DropBomb::arm("hi :3");
drop(bomb); // <- armed bomb should explode when not defused
}
#[test]
fn test_defuse() {
let mut bomb = DropBomb::arm("hi :3");
bomb.defuse();
drop(bomb); // <- defused bomb should not explode
}

View File

@ -7,6 +7,7 @@
pub mod clang;
mod command;
pub mod diff;
mod drop_bomb;
pub mod llvm_readobj;
pub mod run;
pub mod rustc;
@ -16,6 +17,7 @@
use std::ffi::OsString;
use std::fs;
use std::io;
use std::panic;
use std::path::{Path, PathBuf};
pub use gimli;
@ -31,6 +33,7 @@
pub use rustc::{aux_build, rustc, Rustc};
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
#[track_caller]
pub fn env_var(name: &str) -> String {
match env::var(name) {
Ok(v) => v,
@ -38,6 +41,7 @@ pub fn env_var(name: &str) -> String {
}
}
#[track_caller]
pub fn env_var_os(name: &str) -> OsString {
match env::var_os(name) {
Some(v) => v,
@ -65,11 +69,13 @@ pub fn is_darwin() -> bool {
target().contains("darwin")
}
#[track_caller]
pub fn python_command() -> Command {
let python_path = env_var("PYTHON");
Command::new(python_path)
}
#[track_caller]
pub fn htmldocck() -> Command {
let mut python = python_command();
python.arg(source_root().join("src/etc/htmldocck.py"));
@ -161,15 +167,13 @@ pub fn cwd() -> PathBuf {
/// available on the platform!
#[track_caller]
pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let caller = panic::Location::caller();
let mut cygpath = Command::new("cygpath");
cygpath.arg("-w");
cygpath.arg(path.as_ref());
let output = cygpath.command_output();
let output = cygpath.run();
if !output.status().success() {
handle_failed_output(&cygpath, output, caller_line_number);
handle_failed_output(&cygpath, output, caller.line());
}
// cygpath -w can attach a newline
output.stdout_utf8().trim().to_string()
@ -178,13 +182,11 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
/// Run `uname`. This assumes that `uname` is available on the platform!
#[track_caller]
pub fn uname() -> String {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let caller = panic::Location::caller();
let mut uname = Command::new("uname");
let output = uname.command_output();
let output = uname.run();
if !output.status().success() {
handle_failed_output(&uname, output, caller_line_number);
handle_failed_output(&uname, output, caller.line());
}
output.stdout_utf8()
}
@ -364,12 +366,6 @@ pub fn env_remove<K>(&mut self, key: K) -> &mut Self
self
}
/// Clear all environmental variables.
pub fn env_var(&mut self) -> &mut Self {
self.cmd.env_clear();
self
}
/// Generic command argument provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
@ -398,7 +394,7 @@ pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
where
I: FnOnce(&::std::process::Command),
{
inspector(&self.cmd);
self.cmd.inspect(inspector);
self
}
@ -415,7 +411,7 @@ pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
}
/// Set the path where the command will be run.
pub fn current_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self {
self.cmd.current_dir(path);
self
}

View File

@ -5,6 +5,7 @@
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
/// at `$LLVM_BIN_DIR/llvm-readobj`.
#[track_caller]
pub fn llvm_readobj() -> LlvmReadobj {
LlvmReadobj::new()
}
@ -20,6 +21,7 @@ pub struct LlvmReadobj {
impl LlvmReadobj {
/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
/// at `$LLVM_BIN_DIR/llvm-readobj`.
#[track_caller]
pub fn new() -> Self {
let llvm_bin_dir = env_var("LLVM_BIN_DIR");
let llvm_bin_dir = PathBuf::from(llvm_bin_dir);

View File

@ -1,5 +1,6 @@
use std::env;
use std::ffi::OsStr;
use std::panic;
use std::path::{Path, PathBuf};
use crate::command::{Command, CompletedProcess};
@ -7,7 +8,8 @@
use super::handle_failed_output;
fn run_common(name: &str) -> (Command, CompletedProcess) {
#[track_caller]
fn run_common(name: &str) -> Command {
let mut bin_path = PathBuf::new();
bin_path.push(cwd());
bin_path.push(name);
@ -34,19 +36,17 @@ fn run_common(name: &str) -> (Command, CompletedProcess) {
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
}
let output = cmd.command_output();
(cmd, output)
cmd
}
/// Run a built binary and make sure it succeeds.
#[track_caller]
pub fn run(name: &str) -> CompletedProcess {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let (cmd, output) = run_common(name);
let caller = panic::Location::caller();
let mut cmd = run_common(name);
let output = cmd.run();
if !output.status().success() {
handle_failed_output(&cmd, output, caller_line_number);
handle_failed_output(&cmd, output, caller.line());
}
output
}
@ -54,18 +54,18 @@ pub fn run(name: &str) -> CompletedProcess {
/// Run a built binary and make sure it fails.
#[track_caller]
pub fn run_fail(name: &str) -> CompletedProcess {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
let (cmd, output) = run_common(name);
let caller = panic::Location::caller();
let mut cmd = run_common(name);
let output = cmd.run_fail();
if output.status().success() {
handle_failed_output(&cmd, output, caller_line_number);
handle_failed_output(&cmd, output, caller.line());
}
output
}
/// Create a new custom Command.
/// This should be preferred to creating `std::process::Command` directly.
/// Create a new custom [`Command`]. This should be preferred to creating [`std::process::Command`]
/// directly.
#[track_caller]
pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command {
let mut command = Command::new(program);
set_host_rpath(&mut command);

View File

@ -5,11 +5,13 @@
use crate::{command, cwd, env_var, set_host_rpath};
/// Construct a new `rustc` invocation.
#[track_caller]
pub fn rustc() -> Rustc {
Rustc::new()
}
/// Construct a new `rustc` aux-build invocation.
#[track_caller]
pub fn aux_build() -> Rustc {
Rustc::new_aux_build()
}
@ -22,6 +24,7 @@ pub struct Rustc {
crate::impl_common_helpers!(Rustc);
#[track_caller]
fn setup_common() -> Command {
let rustc = env_var("RUSTC");
let mut cmd = Command::new(rustc);
@ -34,12 +37,14 @@ impl Rustc {
// `rustc` invocation constructor methods
/// Construct a new `rustc` invocation.
#[track_caller]
pub fn new() -> Self {
let cmd = setup_common();
Self { cmd }
}
/// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
#[track_caller]
pub fn new_aux_build() -> Self {
let mut cmd = setup_common();
cmd.arg("--crate-type=lib");

View File

@ -5,11 +5,13 @@
use crate::{env_var, env_var_os, set_host_rpath};
/// Construct a plain `rustdoc` invocation with no flags set.
#[track_caller]
pub fn bare_rustdoc() -> Rustdoc {
Rustdoc::bare()
}
/// Construct a new `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
#[track_caller]
pub fn rustdoc() -> Rustdoc {
Rustdoc::new()
}
@ -21,6 +23,7 @@ pub struct Rustdoc {
crate::impl_common_helpers!(Rustdoc);
#[track_caller]
fn setup_common() -> Command {
let rustdoc = env_var("RUSTDOC");
let mut cmd = Command::new(rustdoc);
@ -30,12 +33,14 @@ fn setup_common() -> Command {
impl Rustdoc {
/// Construct a bare `rustdoc` invocation.
#[track_caller]
pub fn bare() -> Self {
let cmd = setup_common();
Self { cmd }
}
/// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set.
#[track_caller]
pub fn new() -> Self {
let mut cmd = setup_common();
let target_rpath_dir = env_var_os("TARGET_RPATH_DIR");

View File

@ -35,7 +35,7 @@ fn main() {
let rustc = env_var("RUSTC");
let bootstrap_cargo = env_var("BOOTSTRAP_CARGO");
let mut cmd = cmd(bootstrap_cargo);
cmd.args([
cmd.args(&[
"build",
"--manifest-path",
manifest_path.to_str().unwrap(),

View File

@ -9,5 +9,5 @@ fn main() {
.output(&out_dir)
.run();
// FIXME (GuillaumeGomez): Port the python script to Rust as well.
assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success());
python_command().arg("validate_json.py").arg(&out_dir).run();
}

View File

@ -56,5 +56,5 @@ fn main() {
.arg(&ex_dir)
.run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
htmldocck().arg(out_dir).arg("src/lib.rs").run();
}

View File

@ -45,5 +45,5 @@ pub fn scrape(extra_args: &[&str]) {
}
rustdoc.run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
htmldocck().arg(out_dir).arg("src/lib.rs").run();
}

View File

@ -28,5 +28,5 @@ fn main() {
std::fs::write(&test_css, test_content).unwrap();
rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
assert!(htmldocck().arg(out_dir).arg("foo.rs").status().unwrap().success());
htmldocck().arg(out_dir).arg("foo.rs").run();
}

View File

@ -3,5 +3,5 @@
fn main() {
let out_dir = "rustdoc";
rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
htmldocck().arg(out_dir).arg("src/lib.rs").run();
}

View File

@ -12,5 +12,5 @@ fn main() {
.arg(&out_dir)
.run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
htmldocck().arg(out_dir).arg("src/lib.rs").run();
}

View File

@ -12,5 +12,5 @@ fn main() {
.arg(&out_dir)
.run();
assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
htmldocck().arg(out_dir).arg("src/lib.rs").run();
}