mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
Rework test error handling
This commit is contained in:
parent
e5ec3a8ff9
commit
23735d4c09
@ -73,12 +73,5 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
|
||||
let bench_args = bench_args.chain(args.get_many::<String>("args").unwrap_or_default());
|
||||
let bench_args = bench_args.map(String::as_str).collect::<Vec<_>>();
|
||||
|
||||
let err = ops::run_benches(&ws, &ops, &bench_args)?;
|
||||
match err {
|
||||
None => Ok(()),
|
||||
Some(err) => Err(match err.code {
|
||||
Some(i) => CliError::new(anyhow::format_err!("bench failed"), i),
|
||||
None => CliError::new(err.into(), 101),
|
||||
}),
|
||||
}
|
||||
ops::run_benches(&ws, &ops, &bench_args)
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::command_prelude::*;
|
||||
use anyhow::Error;
|
||||
use cargo::ops;
|
||||
|
||||
pub fn cli() -> App {
|
||||
@ -110,18 +109,5 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
|
||||
compile_opts,
|
||||
};
|
||||
|
||||
let err = ops::run_tests(&ws, &ops, &test_args)?;
|
||||
match err {
|
||||
None => Ok(()),
|
||||
Some(err) => {
|
||||
let context = anyhow::format_err!("{}", err.hint(&ws, &ops.compile_opts));
|
||||
let e = match err.code {
|
||||
// Don't show "process didn't exit successfully" for simple errors.
|
||||
Some(i) if cargo_util::is_simple_exit_code(i) => CliError::new(context, i),
|
||||
Some(i) => CliError::new(Error::from(err).context(context), i),
|
||||
None => CliError::new(Error::from(err).context(context), 101),
|
||||
};
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
ops::run_tests(&ws, &ops, &test_args)
|
||||
}
|
||||
|
@ -3,9 +3,11 @@ use crate::core::shell::Verbosity;
|
||||
use crate::core::{TargetKind, Workspace};
|
||||
use crate::ops;
|
||||
use crate::util::errors::CargoResult;
|
||||
use crate::util::{add_path_args, CargoTestError, Config, Test};
|
||||
use crate::util::{add_path_args, CliError, CliResult, Config};
|
||||
use anyhow::format_err;
|
||||
use cargo_util::{ProcessBuilder, ProcessError};
|
||||
use std::ffi::OsString;
|
||||
use std::fmt::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct TestOptions {
|
||||
@ -14,61 +16,87 @@ pub struct TestOptions {
|
||||
pub no_fail_fast: bool,
|
||||
}
|
||||
|
||||
pub fn run_tests(
|
||||
ws: &Workspace<'_>,
|
||||
options: &TestOptions,
|
||||
test_args: &[&str],
|
||||
) -> CargoResult<Option<CargoTestError>> {
|
||||
/// The kind of test.
|
||||
///
|
||||
/// This is needed because `Unit` does not track whether or not something is a
|
||||
/// benchmark.
|
||||
#[derive(Copy, Clone)]
|
||||
enum TestKind {
|
||||
Test,
|
||||
Bench,
|
||||
Doctest,
|
||||
}
|
||||
|
||||
/// A unit that failed to run.
|
||||
struct UnitTestError {
|
||||
unit: Unit,
|
||||
kind: TestKind,
|
||||
}
|
||||
|
||||
impl UnitTestError {
|
||||
/// Returns the CLI args needed to target this unit.
|
||||
fn cli_args(&self, ws: &Workspace<'_>, opts: &ops::CompileOptions) -> String {
|
||||
let mut args = if opts.spec.needs_spec_flag(ws) {
|
||||
format!("-p {} ", self.unit.pkg.name())
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let mut add = |which| write!(args, "--{which} {}", self.unit.target.name()).unwrap();
|
||||
|
||||
match self.kind {
|
||||
TestKind::Test | TestKind::Bench => match self.unit.target.kind() {
|
||||
TargetKind::Lib(_) => args.push_str("--lib"),
|
||||
TargetKind::Bin => add("bin"),
|
||||
TargetKind::Test => add("test"),
|
||||
TargetKind::Bench => add("bench"),
|
||||
TargetKind::ExampleLib(_) | TargetKind::ExampleBin => add("example"),
|
||||
TargetKind::CustomBuild => panic!("unexpected CustomBuild kind"),
|
||||
},
|
||||
TestKind::Doctest => args.push_str("--doc"),
|
||||
}
|
||||
args
|
||||
}
|
||||
}
|
||||
|
||||
/// Compiles and runs tests.
|
||||
///
|
||||
/// On error, the returned [`CliError`] will have the appropriate process exit
|
||||
/// code that Cargo should use.
|
||||
pub fn run_tests(ws: &Workspace<'_>, options: &TestOptions, test_args: &[&str]) -> CliResult {
|
||||
let compilation = compile_tests(ws, options)?;
|
||||
|
||||
if options.no_run {
|
||||
if !options.compile_opts.build_config.emit_json() {
|
||||
display_no_run_information(ws, test_args, &compilation, "unittests")?;
|
||||
}
|
||||
|
||||
return Ok(None);
|
||||
return Ok(());
|
||||
}
|
||||
let (test, mut errors) = run_unit_tests(ws.config(), options, test_args, &compilation)?;
|
||||
let mut errors = run_unit_tests(ws, options, test_args, &compilation, TestKind::Test)?;
|
||||
|
||||
// If we have an error and want to fail fast, then return.
|
||||
if !errors.is_empty() && !options.no_fail_fast {
|
||||
return Ok(Some(CargoTestError::new(test, errors)));
|
||||
}
|
||||
|
||||
let (doctest, docerrors) = run_doc_tests(ws, options, test_args, &compilation)?;
|
||||
let test = if docerrors.is_empty() { test } else { doctest };
|
||||
errors.extend(docerrors);
|
||||
if errors.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(CargoTestError::new(test, errors)))
|
||||
}
|
||||
let doctest_errors = run_doc_tests(ws, options, test_args, &compilation)?;
|
||||
errors.extend(doctest_errors);
|
||||
no_fail_fast_err(ws, &options.compile_opts, &errors)
|
||||
}
|
||||
|
||||
pub fn run_benches(
|
||||
ws: &Workspace<'_>,
|
||||
options: &TestOptions,
|
||||
args: &[&str],
|
||||
) -> CargoResult<Option<CargoTestError>> {
|
||||
/// Compiles and runs benchmarks.
|
||||
///
|
||||
/// On error, the returned [`CliError`] will have the appropriate process exit
|
||||
/// code that Cargo should use.
|
||||
pub fn run_benches(ws: &Workspace<'_>, options: &TestOptions, args: &[&str]) -> CliResult {
|
||||
let compilation = compile_tests(ws, options)?;
|
||||
|
||||
if options.no_run {
|
||||
if !options.compile_opts.build_config.emit_json() {
|
||||
display_no_run_information(ws, args, &compilation, "benches")?;
|
||||
}
|
||||
|
||||
return Ok(None);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut args = args.to_vec();
|
||||
args.push("--bench");
|
||||
|
||||
let (test, errors) = run_unit_tests(ws.config(), options, &args, &compilation)?;
|
||||
|
||||
match errors.len() {
|
||||
0 => Ok(None),
|
||||
_ => Ok(Some(CargoTestError::new(test, errors))),
|
||||
}
|
||||
let errors = run_unit_tests(ws, options, &args, &compilation, TestKind::Bench)?;
|
||||
no_fail_fast_err(ws, &options.compile_opts, &errors)
|
||||
}
|
||||
|
||||
fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult<Compilation<'a>> {
|
||||
@ -78,12 +106,17 @@ fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult<C
|
||||
}
|
||||
|
||||
/// Runs the unit and integration tests of a package.
|
||||
///
|
||||
/// Returns a `Vec` of tests that failed when `--no-fail-fast` is used.
|
||||
/// If `--no-fail-fast` is *not* used, then this returns an `Err`.
|
||||
fn run_unit_tests(
|
||||
config: &Config,
|
||||
ws: &Workspace<'_>,
|
||||
options: &TestOptions,
|
||||
test_args: &[&str],
|
||||
compilation: &Compilation<'_>,
|
||||
) -> CargoResult<(Test, Vec<ProcessError>)> {
|
||||
test_kind: TestKind,
|
||||
) -> Result<Vec<UnitTestError>, CliError> {
|
||||
let config = ws.config();
|
||||
let cwd = config.cwd();
|
||||
let mut errors = Vec::new();
|
||||
|
||||
@ -110,46 +143,32 @@ fn run_unit_tests(
|
||||
.shell()
|
||||
.verbose(|shell| shell.status("Running", &cmd))?;
|
||||
|
||||
let result = cmd.exec();
|
||||
|
||||
if let Err(e) = result {
|
||||
let e = e.downcast::<ProcessError>()?;
|
||||
errors.push((
|
||||
unit.target.kind().clone(),
|
||||
unit.target.name().to_string(),
|
||||
unit.pkg.name().to_string(),
|
||||
e,
|
||||
));
|
||||
if let Err(e) = cmd.exec() {
|
||||
let code = fail_fast_code(&e);
|
||||
let unit_err = UnitTestError {
|
||||
unit: unit.clone(),
|
||||
kind: test_kind,
|
||||
};
|
||||
report_test_error(ws, &options.compile_opts, &unit_err, e);
|
||||
errors.push(unit_err);
|
||||
if !options.no_fail_fast {
|
||||
break;
|
||||
return Err(CliError::code(code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if errors.len() == 1 {
|
||||
let (kind, name, pkg_name, e) = errors.pop().unwrap();
|
||||
Ok((
|
||||
Test::UnitTest {
|
||||
kind,
|
||||
name,
|
||||
pkg_name,
|
||||
},
|
||||
vec![e],
|
||||
))
|
||||
} else {
|
||||
Ok((
|
||||
Test::Multiple,
|
||||
errors.into_iter().map(|(_, _, _, e)| e).collect(),
|
||||
))
|
||||
}
|
||||
Ok(errors)
|
||||
}
|
||||
|
||||
/// Runs doc tests.
|
||||
///
|
||||
/// Returns a `Vec` of tests that failed when `--no-fail-fast` is used.
|
||||
/// If `--no-fail-fast` is *not* used, then this returns an `Err`.
|
||||
fn run_doc_tests(
|
||||
ws: &Workspace<'_>,
|
||||
options: &TestOptions,
|
||||
test_args: &[&str],
|
||||
compilation: &Compilation<'_>,
|
||||
) -> CargoResult<(Test, Vec<ProcessError>)> {
|
||||
) -> Result<Vec<UnitTestError>, CliError> {
|
||||
let config = ws.config();
|
||||
let mut errors = Vec::new();
|
||||
let doctest_xcompile = config.cli_unstable().doctest_xcompile;
|
||||
@ -258,16 +277,24 @@ fn run_doc_tests(
|
||||
.shell()
|
||||
.verbose(|shell| shell.status("Running", p.to_string()))?;
|
||||
if let Err(e) = p.exec() {
|
||||
let e = e.downcast::<ProcessError>()?;
|
||||
errors.push(e);
|
||||
let code = fail_fast_code(&e);
|
||||
let unit_err = UnitTestError {
|
||||
unit: unit.clone(),
|
||||
kind: TestKind::Doctest,
|
||||
};
|
||||
report_test_error(ws, &options.compile_opts, &unit_err, e);
|
||||
errors.push(unit_err);
|
||||
if !options.no_fail_fast {
|
||||
return Ok((Test::Doc, errors));
|
||||
return Err(CliError::code(code));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((Test::Doc, errors))
|
||||
Ok(errors)
|
||||
}
|
||||
|
||||
/// Displays human-readable descriptions of the test executables.
|
||||
///
|
||||
/// This is used when `cargo test --no-run` is used.
|
||||
fn display_no_run_information(
|
||||
ws: &Workspace<'_>,
|
||||
test_args: &[&str],
|
||||
@ -303,6 +330,11 @@ fn display_no_run_information(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// Creates a [`ProcessBuilder`] for executing a single test.
|
||||
///
|
||||
/// Returns a tuple `(exe_display, process)` where `exe_display` is a string
|
||||
/// to display that describes the executable path in a human-readable form.
|
||||
/// `process` is the `ProcessBuilder` to use for executing the test.
|
||||
fn cmd_builds(
|
||||
config: &Config,
|
||||
cwd: &Path,
|
||||
@ -341,3 +373,67 @@ fn cmd_builds(
|
||||
|
||||
Ok((exe_display, cmd))
|
||||
}
|
||||
|
||||
/// Returns the error code to use when *not* using `--no-fail-fast`.
|
||||
///
|
||||
/// Cargo will return the error code from the test process itself. If some
|
||||
/// other error happened (like a failure to launch the process), then it will
|
||||
/// return a standard 101 error code.
|
||||
///
|
||||
/// When using `--no-fail-fast`, Cargo always uses the 101 exit code (since
|
||||
/// there may not be just one process to report).
|
||||
fn fail_fast_code(error: &anyhow::Error) -> i32 {
|
||||
if let Some(proc_err) = error.downcast_ref::<ProcessError>() {
|
||||
if let Some(code) = proc_err.code {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
101
|
||||
}
|
||||
|
||||
/// Returns the `CliError` when using `--no-fail-fast` and there is at least
|
||||
/// one error.
|
||||
fn no_fail_fast_err(
|
||||
ws: &Workspace<'_>,
|
||||
opts: &ops::CompileOptions,
|
||||
errors: &[UnitTestError],
|
||||
) -> CliResult {
|
||||
// TODO: This could be improved by combining the flags on a single line when feasible.
|
||||
let args: Vec<_> = errors
|
||||
.iter()
|
||||
.map(|unit_err| format!(" `{}`", unit_err.cli_args(ws, opts)))
|
||||
.collect();
|
||||
let message = match errors.len() {
|
||||
0 => return Ok(()),
|
||||
1 => format!("1 target failed:\n{}", args.join("\n")),
|
||||
n => format!("{n} targets failed:\n{}", args.join("\n")),
|
||||
};
|
||||
Err(anyhow::Error::msg(message).into())
|
||||
}
|
||||
|
||||
/// Displays an error on the console about a test failure.
|
||||
fn report_test_error(
|
||||
ws: &Workspace<'_>,
|
||||
opts: &ops::CompileOptions,
|
||||
unit_err: &UnitTestError,
|
||||
test_error: anyhow::Error,
|
||||
) {
|
||||
let which = match unit_err.kind {
|
||||
TestKind::Test => "test failed",
|
||||
TestKind::Bench => "bench failed",
|
||||
TestKind::Doctest => "doctest failed",
|
||||
};
|
||||
|
||||
let mut err = format_err!("{}, to rerun pass `{}`", which, unit_err.cli_args(ws, opts));
|
||||
// Don't show "process didn't exit successfully" for simple errors.
|
||||
// libtest exits with 101 for normal errors.
|
||||
let is_simple = test_error
|
||||
.downcast_ref::<ProcessError>()
|
||||
.and_then(|proc_err| proc_err.code)
|
||||
.map_or(false, |code| code == 101);
|
||||
if !is_simple {
|
||||
err = test_error.context(err);
|
||||
}
|
||||
|
||||
crate::display_error(&err, &mut ws.config().shell());
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
#![allow(unknown_lints)]
|
||||
|
||||
use crate::core::{TargetKind, Workspace};
|
||||
use crate::ops::CompileOptions;
|
||||
use anyhow::Error;
|
||||
use cargo_util::ProcessError;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -197,91 +194,6 @@ impl<'a> Iterator for ManifestCauses<'a> {
|
||||
|
||||
impl<'a> ::std::iter::FusedIterator for ManifestCauses<'a> {}
|
||||
|
||||
// =============================================================================
|
||||
// Cargo test errors.
|
||||
|
||||
/// Error when testcases fail
|
||||
#[derive(Debug)]
|
||||
pub struct CargoTestError {
|
||||
pub test: Test,
|
||||
pub desc: String,
|
||||
pub code: Option<i32>,
|
||||
pub causes: Vec<ProcessError>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CargoTestError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.desc.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for CargoTestError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Test {
|
||||
Multiple,
|
||||
Doc,
|
||||
UnitTest {
|
||||
kind: TargetKind,
|
||||
name: String,
|
||||
pkg_name: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl CargoTestError {
|
||||
pub fn new(test: Test, errors: Vec<ProcessError>) -> Self {
|
||||
if errors.is_empty() {
|
||||
panic!("Cannot create CargoTestError from empty Vec")
|
||||
}
|
||||
let desc = errors
|
||||
.iter()
|
||||
.map(|error| error.desc.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
CargoTestError {
|
||||
test,
|
||||
desc,
|
||||
code: errors[0].code,
|
||||
causes: errors,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hint(&self, ws: &Workspace<'_>, opts: &CompileOptions) -> String {
|
||||
match self.test {
|
||||
Test::UnitTest {
|
||||
ref kind,
|
||||
ref name,
|
||||
ref pkg_name,
|
||||
} => {
|
||||
let pkg_info = if opts.spec.needs_spec_flag(ws) {
|
||||
format!("-p {} ", pkg_name)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
match *kind {
|
||||
TargetKind::Bench => {
|
||||
format!("test failed, to rerun pass '{}--bench {}'", pkg_info, name)
|
||||
}
|
||||
TargetKind::Bin => {
|
||||
format!("test failed, to rerun pass '{}--bin {}'", pkg_info, name)
|
||||
}
|
||||
TargetKind::Lib(_) => format!("test failed, to rerun pass '{}--lib'", pkg_info),
|
||||
TargetKind::Test => {
|
||||
format!("test failed, to rerun pass '{}--test {}'", pkg_info, name)
|
||||
}
|
||||
TargetKind::ExampleBin | TargetKind::ExampleLib(_) => {
|
||||
format!("test failed, to rerun pass '{}--example {}", pkg_info, name)
|
||||
}
|
||||
_ => "test failed.".into(),
|
||||
}
|
||||
}
|
||||
Test::Doc => "test failed, to rerun pass '--doc'".into(),
|
||||
_ => "test failed.".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// CLI errors
|
||||
|
||||
|
@ -6,8 +6,8 @@ pub use self::config::{homedir, Config, ConfigValue};
|
||||
pub(crate) use self::counter::MetricsCounter;
|
||||
pub use self::dependency_queue::DependencyQueue;
|
||||
pub use self::diagnostic_server::RustfixDiagnosticServer;
|
||||
pub use self::errors::{internal, CargoResult, CliResult, Test};
|
||||
pub use self::errors::{CargoTestError, CliError};
|
||||
pub use self::errors::CliError;
|
||||
pub use self::errors::{internal, CargoResult, CliResult};
|
||||
pub use self::flock::{FileLock, Filesystem};
|
||||
pub use self::graph::Graph;
|
||||
pub use self::hasher::StableHasher;
|
||||
|
@ -1153,7 +1153,7 @@ fn test_bench_no_fail_fast() {
|
||||
let p = project()
|
||||
.file("Cargo.toml", &basic_bin_manifest("foo"))
|
||||
.file(
|
||||
"src/foo.rs",
|
||||
"src/main.rs",
|
||||
r#"
|
||||
#![feature(test)]
|
||||
#[cfg(test)]
|
||||
@ -1177,15 +1177,36 @@ fn test_bench_no_fail_fast() {
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"benches/b1.rs",
|
||||
r#"
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
#[bench]
|
||||
fn b1_fail(_b: &mut test::Bencher) { assert_eq!(1, 2); }
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
p.cargo("bench --no-fail-fast -- --test-threads=1")
|
||||
.with_status(101)
|
||||
.with_stderr_contains("[RUNNING] [..] (target/release/deps/foo-[..][EXE])")
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo v0.5.0 [..]
|
||||
[FINISHED] bench [..]
|
||||
[RUNNING] unittests src/main.rs (target/release/deps/foo[..])
|
||||
[ERROR] bench failed, to rerun pass `--bin foo`
|
||||
[RUNNING] benches/b1.rs (target/release/deps/b1[..])
|
||||
[ERROR] bench failed, to rerun pass `--bench b1`
|
||||
[ERROR] 2 targets failed:
|
||||
`--bin foo`
|
||||
`--bench b1`
|
||||
",
|
||||
)
|
||||
.with_stdout_contains("running 2 tests")
|
||||
.with_stderr_contains("[RUNNING] [..] (target/release/deps/foo-[..][EXE])")
|
||||
.with_stdout_contains("test bench_hello [..]")
|
||||
.with_stdout_contains("test bench_nope [..]")
|
||||
.with_stdout_contains("test b1_fail [..]")
|
||||
.run();
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use cargo_test_support::{
|
||||
basic_bin_manifest, basic_lib_manifest, basic_manifest, cargo_exe, project,
|
||||
};
|
||||
use cargo_test_support::{cross_compile, paths};
|
||||
use cargo_test_support::{rustc_host, sleep_ms};
|
||||
use cargo_test_support::{rustc_host, rustc_host_env, sleep_ms};
|
||||
use std::fs;
|
||||
|
||||
#[cargo_test]
|
||||
@ -377,7 +377,7 @@ fn cargo_test_failing_test_in_bin() {
|
||||
[COMPILING] foo v0.5.0 ([CWD])
|
||||
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
||||
[RUNNING] [..] (target/debug/deps/foo-[..][EXE])
|
||||
[ERROR] test failed, to rerun pass '--bin foo'",
|
||||
[ERROR] test failed, to rerun pass `--bin foo`",
|
||||
)
|
||||
.with_stdout_contains(
|
||||
"
|
||||
@ -426,7 +426,7 @@ fn cargo_test_failing_test_in_test() {
|
||||
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
||||
[RUNNING] [..] (target/debug/deps/foo-[..][EXE])
|
||||
[RUNNING] [..] (target/debug/deps/footest-[..][EXE])
|
||||
[ERROR] test failed, to rerun pass '--test footest'",
|
||||
[ERROR] test failed, to rerun pass `--test footest`",
|
||||
)
|
||||
.with_stdout_contains("running 0 tests")
|
||||
.with_stdout_contains(
|
||||
@ -464,7 +464,7 @@ fn cargo_test_failing_test_in_lib() {
|
||||
[COMPILING] foo v0.5.0 ([CWD])
|
||||
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
||||
[RUNNING] [..] (target/debug/deps/foo-[..][EXE])
|
||||
[ERROR] test failed, to rerun pass '--lib'",
|
||||
[ERROR] test failed, to rerun pass `--lib`",
|
||||
)
|
||||
.with_stdout_contains(
|
||||
"\
|
||||
@ -2466,19 +2466,20 @@ fn no_fail_fast() {
|
||||
.build();
|
||||
p.cargo("test --no-fail-fast")
|
||||
.with_status(101)
|
||||
.with_stderr_contains(
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[FINISHED] test [unoptimized + debuginfo] target(s) in [..]
|
||||
[RUNNING] [..] (target/debug/deps/foo-[..][EXE])
|
||||
[RUNNING] [..] (target/debug/deps/test_add_one-[..][EXE])",
|
||||
[COMPILING] foo v0.0.1 [..]
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/foo[..])
|
||||
[RUNNING] tests/test_add_one.rs (target/debug/deps/test_add_one[..])
|
||||
[ERROR] test failed, to rerun pass `--test test_add_one`
|
||||
[RUNNING] tests/test_sub_one.rs (target/debug/deps/test_sub_one[..])
|
||||
[DOCTEST] foo
|
||||
[ERROR] 1 target failed:
|
||||
`--test test_add_one`
|
||||
",
|
||||
)
|
||||
.with_stdout_contains("running 0 tests")
|
||||
.with_stderr_contains(
|
||||
"\
|
||||
[RUNNING] [..] (target/debug/deps/test_sub_one-[..][EXE])
|
||||
[DOCTEST] foo",
|
||||
)
|
||||
.with_stdout_contains("test result: FAILED. [..]")
|
||||
.with_stdout_contains("test sub_one_test ... ok")
|
||||
.with_stdout_contains_n("test [..] ... ok", 3)
|
||||
@ -3576,10 +3577,7 @@ fn test_hint_not_masked_by_doctest() {
|
||||
.with_status(101)
|
||||
.with_stdout_contains("test this_fails ... FAILED")
|
||||
.with_stdout_contains("[..]this_works (line [..]ok")
|
||||
.with_stderr_contains(
|
||||
"[ERROR] test failed, to rerun pass \
|
||||
'--test integ'",
|
||||
)
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass `--test integ`")
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -3590,24 +3588,131 @@ fn test_hint_workspace_virtual() {
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[workspace]
|
||||
members = ["a", "b"]
|
||||
members = ["a", "b", "c"]
|
||||
"#,
|
||||
)
|
||||
.file("a/Cargo.toml", &basic_manifest("a", "0.1.0"))
|
||||
.file("a/src/lib.rs", "#[test] fn t1() {}")
|
||||
.file("b/Cargo.toml", &basic_manifest("b", "0.1.0"))
|
||||
.file("b/src/lib.rs", "#[test] fn t1() {assert!(false)}")
|
||||
.file("c/Cargo.toml", &basic_manifest("c", "0.1.0"))
|
||||
.file(
|
||||
"c/src/lib.rs",
|
||||
r#"
|
||||
/// ```rust
|
||||
/// assert_eq!(1, 2);
|
||||
/// ```
|
||||
pub fn foo() {}
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"c/src/main.rs",
|
||||
r#"
|
||||
fn main() {}
|
||||
|
||||
#[test]
|
||||
fn from_main() { assert_eq!(1, 2); }
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"c/tests/t1.rs",
|
||||
r#"
|
||||
#[test]
|
||||
fn from_int_test() { assert_eq!(1, 2); }
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"c/examples/ex1.rs",
|
||||
r#"
|
||||
fn main() {}
|
||||
|
||||
#[test]
|
||||
fn from_example() { assert_eq!(1, 2); }
|
||||
"#,
|
||||
)
|
||||
// This does not use #[bench] since it is unstable. #[test] works just
|
||||
// the same for our purpose of checking the hint.
|
||||
.file(
|
||||
"c/benches/b1.rs",
|
||||
r#"
|
||||
#[test]
|
||||
fn from_bench() { assert_eq!(1, 2); }
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// This depends on Units being sorted so that `b` fails first.
|
||||
p.cargo("test")
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass '-p b --lib'")
|
||||
.with_stderr_unordered(
|
||||
"\
|
||||
[COMPILING] c v0.1.0 [..]
|
||||
[COMPILING] a v0.1.0 [..]
|
||||
[COMPILING] b v0.1.0 [..]
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/a[..])
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/b[..])
|
||||
[ERROR] test failed, to rerun pass `-p b --lib`
|
||||
",
|
||||
)
|
||||
.with_status(101)
|
||||
.run();
|
||||
p.cargo("test")
|
||||
.cwd("b")
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass '--lib'")
|
||||
.with_stderr(
|
||||
"\
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] unittests src/lib.rs ([ROOT]/foo/target/debug/deps/b[..])
|
||||
[ERROR] test failed, to rerun pass `--lib`
|
||||
",
|
||||
)
|
||||
.with_status(101)
|
||||
.run();
|
||||
p.cargo("test --no-fail-fast")
|
||||
.with_stderr(
|
||||
"\
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/a[..])
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/b[..])
|
||||
[ERROR] test failed, to rerun pass `-p b --lib`
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/c[..])
|
||||
[RUNNING] unittests src/main.rs (target/debug/deps/c[..])
|
||||
[ERROR] test failed, to rerun pass `-p c --bin c`
|
||||
[RUNNING] tests/t1.rs (target/debug/deps/t1[..])
|
||||
[ERROR] test failed, to rerun pass `-p c --test t1`
|
||||
[DOCTEST] a
|
||||
[DOCTEST] b
|
||||
[DOCTEST] c
|
||||
[ERROR] doctest failed, to rerun pass `-p c --doc`
|
||||
[ERROR] 4 targets failed:
|
||||
`-p b --lib`
|
||||
`-p c --bin c`
|
||||
`-p c --test t1`
|
||||
`-p c --doc`
|
||||
",
|
||||
)
|
||||
.with_status(101)
|
||||
.run();
|
||||
// Check others that are not in the default set.
|
||||
p.cargo("test -p c --examples --benches --no-fail-fast")
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] c v0.1.0 [..]
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] unittests src/lib.rs (target/debug/deps/c[..])
|
||||
[RUNNING] unittests src/main.rs (target/debug/deps/c[..])
|
||||
[ERROR] test failed, to rerun pass `-p c --bin c`
|
||||
[RUNNING] benches/b1.rs (target/debug/deps/b1[..])
|
||||
[ERROR] test failed, to rerun pass `-p c --bench b1`
|
||||
[RUNNING] unittests examples/ex1.rs (target/debug/examples/ex1[..])
|
||||
[ERROR] test failed, to rerun pass `-p c --example ex1`
|
||||
[ERROR] 3 targets failed:
|
||||
`-p c --bin c`
|
||||
`-p c --bench b1`
|
||||
`-p c --example ex1`
|
||||
",
|
||||
)
|
||||
.with_status(101)
|
||||
.run()
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
@ -3630,11 +3735,11 @@ fn test_hint_workspace_nonvirtual() {
|
||||
.build();
|
||||
|
||||
p.cargo("test --workspace")
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass '-p a --lib'")
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass `-p a --lib`")
|
||||
.with_status(101)
|
||||
.run();
|
||||
p.cargo("test -p a")
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass '-p a --lib'")
|
||||
.with_stderr_contains("[ERROR] test failed, to rerun pass `-p a --lib`")
|
||||
.with_status(101)
|
||||
.run();
|
||||
}
|
||||
@ -4494,3 +4599,108 @@ fn test_workspaces_cwd() {
|
||||
.with_stdout_contains("test test_integration_deep_cwd ... ok")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn execution_error() {
|
||||
// Checks the behavior when a test fails to launch.
|
||||
let p = project()
|
||||
.file(
|
||||
"tests/t1.rs",
|
||||
r#"
|
||||
#[test]
|
||||
fn foo() {}
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
let key = format!("CARGO_TARGET_{}_RUNNER", rustc_host_env());
|
||||
p.cargo("test")
|
||||
.env(&key, "does_not_exist")
|
||||
// The actual error is usually "no such file", but on Windows it has a
|
||||
// custom message. Since matching against the error string produced by
|
||||
// Rust is not very reliable, this just uses `[..]`.
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo v0.0.1 [..]
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] tests/t1.rs (target/debug/deps/t1[..])
|
||||
error: test failed, to rerun pass `--test t1`
|
||||
|
||||
Caused by:
|
||||
could not execute process `does_not_exist [ROOT]/foo/target/debug/deps/t1[..]` (never executed)
|
||||
|
||||
Caused by:
|
||||
[..]
|
||||
",
|
||||
)
|
||||
.with_status(101)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn nonzero_exit_status() {
|
||||
// Tests for nonzero exit codes from tests.
|
||||
let p = project()
|
||||
.file(
|
||||
"tests/t1.rs",
|
||||
r#"
|
||||
#[test]
|
||||
fn t() { panic!("this is a normal error") }
|
||||
"#,
|
||||
)
|
||||
.file(
|
||||
"tests/t2.rs",
|
||||
r#"
|
||||
#[test]
|
||||
fn t() { std::process::exit(4) }
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
p.cargo("test --test t1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo [..]
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] tests/t1.rs (target/debug/deps/t1[..])
|
||||
error: test failed, to rerun pass `--test t1`
|
||||
",
|
||||
)
|
||||
.with_stdout_contains("[..]this is a normal error[..]")
|
||||
.with_status(101)
|
||||
.run();
|
||||
|
||||
p.cargo("test --test t2")
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo v0.0.1 [..]
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] tests/t2.rs (target/debug/deps/t2[..])
|
||||
error: test failed, to rerun pass `--test t2`
|
||||
|
||||
Caused by:
|
||||
process didn't exit successfully: `[ROOT]/foo/target/debug/deps/t2[..]` (exit [..]: 4)
|
||||
",
|
||||
)
|
||||
.with_status(4)
|
||||
.run();
|
||||
|
||||
// no-fail-fast always uses 101
|
||||
p.cargo("test --no-fail-fast")
|
||||
.with_stderr(
|
||||
"\
|
||||
[FINISHED] test [..]
|
||||
[RUNNING] tests/t1.rs (target/debug/deps/t1[..])
|
||||
error: test failed, to rerun pass `--test t1`
|
||||
[RUNNING] tests/t2.rs (target/debug/deps/t2[..])
|
||||
error: test failed, to rerun pass `--test t2`
|
||||
|
||||
Caused by:
|
||||
process didn't exit successfully: `[ROOT]/foo/target/debug/deps/t2[..]` (exit [..]: 4)
|
||||
error: 2 targets failed:
|
||||
`--test t1`
|
||||
`--test t2`
|
||||
",
|
||||
)
|
||||
.with_status(101)
|
||||
.run();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user