Skip to content

Commit

Permalink
Auto merge of #6683 - dwijnand:cargo-test-quicker-by-not-building-unt…
Browse files Browse the repository at this point in the history
…ested-examples-when-filtered, r=ehuss

Cargo test quicker by not building untested examples when filtered

Alternative to #6677
Fixes #6675
r? @ehuss
  • Loading branch information
bors committed Feb 25, 2019
2 parents b9613ec + 110c813 commit 4536bc9
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 47 deletions.
4 changes: 2 additions & 2 deletions src/bin/cargo/commands/fix.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule};
use cargo::ops::{self, CompileFilter, FilterRule, LibRule};

pub fn cli() -> App {
subcommand("fix")
Expand Down Expand Up @@ -127,7 +127,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
if let CompileFilter::Default { .. } = opts.filter {
opts.filter = CompileFilter::Only {
all_targets: true,
lib: true,
lib: LibRule::Default,
bins: FilterRule::All,
examples: FilterRule::All,
benches: FilterRule::All,
Expand Down
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
.filter_map(|pkg| pkg.manifest().default_run())
.collect();
if default_runs.len() == 1 {
compile_opts.filter = CompileFilter::new(
compile_opts.filter = CompileFilter::from_raw_arguments(
false,
vec![default_runs[0].to_owned()],
false,
Expand Down
48 changes: 27 additions & 21 deletions src/bin/cargo/commands/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cargo::ops::{self, CompileFilter};
use cargo::ops::{self, CompileFilter, FilterRule, LibRule};

use crate::command_prelude::*;

Expand Down Expand Up @@ -94,6 +94,17 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {

let mut compile_opts = args.compile_options(config, CompileMode::Test, Some(&ws))?;

// `TESTNAME` is actually an argument of the test binary, but it's
// important, so we explicitly mention it and reconfigure.
let test_name: Option<&str> = args.value_of("TESTNAME");
let mut test_args = vec![];
test_args.extend(test_name.into_iter().map(|s| s.to_string()));
test_args.extend(
args.values_of("args")
.unwrap_or_default()
.map(|s| s.to_string()),
);

let no_run = args.is_present("no-run");
let doc = args.is_present("doc");
if doc {
Expand All @@ -111,17 +122,22 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
}
compile_opts.build_config.mode = CompileMode::Doctest;
compile_opts.filter = ops::CompileFilter::new(
true,
Vec::new(),
false,
Vec::new(),
false,
Vec::new(),
false,
Vec::new(),
false,
false,
LibRule::True,
FilterRule::none(),
FilterRule::none(),
FilterRule::none(),
FilterRule::none(),
);
} else if test_name.is_some() {
if let CompileFilter::Default { .. } = compile_opts.filter {
compile_opts.filter = ops::CompileFilter::new(
LibRule::Default, // compile the library, so the unit tests can be run filtered
FilterRule::All, // compile the binaries, so the unit tests in binaries can be run filtered
FilterRule::All, // compile the tests, so the integration tests can be run filtered
FilterRule::none(), // specify --examples to unit test binaries filtered
FilterRule::none(), // specify --benches to unit test benchmarks filtered
); // also, specify --doc to run doc tests filtered
}
}

let ops = ops::TestOptions {
Expand All @@ -130,16 +146,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
compile_opts,
};

// `TESTNAME` is actually an argument of the test binary, but it's
// important, so we explicitly mention it and reconfigure.
let mut test_args = vec![];
test_args.extend(args.value_of("TESTNAME").into_iter().map(|s| s.to_string()));
test_args.extend(
args.values_of("args")
.unwrap_or_default()
.map(|s| s.to_string()),
);

let err = ops::run_tests(&ws, &ops, &test_args)?;
match err {
None => Ok(()),
Expand Down
53 changes: 43 additions & 10 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ impl Packages {
}
}

#[derive(Debug, PartialEq, Eq)]
pub enum LibRule {
/// Include the library, fail if not present
True,
/// Include the library if present
Default,
/// Exclude the library
False,
}

#[derive(Debug)]
pub enum FilterRule {
All,
Expand All @@ -198,7 +208,7 @@ pub enum CompileFilter {
},
Only {
all_targets: bool,
lib: bool,
lib: LibRule,
bins: FilterRule,
examples: FilterRule,
tests: FilterRule,
Expand Down Expand Up @@ -361,6 +371,10 @@ impl FilterRule {
}
}

pub fn none() -> FilterRule {
FilterRule::Just(Vec::new())
}

fn matches(&self, target: &Target) -> bool {
match *self {
FilterRule::All => true,
Expand All @@ -384,7 +398,8 @@ impl FilterRule {
}

impl CompileFilter {
pub fn new(
/// Construct a CompileFilter from raw command line arguments.
pub fn from_raw_arguments(
lib_only: bool,
bins: Vec<String>,
all_bins: bool,
Expand All @@ -396,6 +411,7 @@ impl CompileFilter {
all_bens: bool,
all_targets: bool,
) -> CompileFilter {
let rule_lib = if lib_only { LibRule::True } else { LibRule::False };
let rule_bins = FilterRule::new(bins, all_bins);
let rule_tsts = FilterRule::new(tsts, all_tsts);
let rule_exms = FilterRule::new(exms, all_exms);
Expand All @@ -404,21 +420,34 @@ impl CompileFilter {
if all_targets {
CompileFilter::Only {
all_targets: true,
lib: true,
lib: LibRule::Default,
bins: FilterRule::All,
examples: FilterRule::All,
benches: FilterRule::All,
tests: FilterRule::All,
}
} else if lib_only
} else {
CompileFilter::new(rule_lib, rule_bins, rule_tsts, rule_exms, rule_bens)
}
}

/// Construct a CompileFilter from underlying primitives.
pub fn new(
rule_lib: LibRule,
rule_bins: FilterRule,
rule_tsts: FilterRule,
rule_exms: FilterRule,
rule_bens: FilterRule,
) -> CompileFilter {
if rule_lib == LibRule::True
|| rule_bins.is_specific()
|| rule_tsts.is_specific()
|| rule_exms.is_specific()
|| rule_bens.is_specific()
{
CompileFilter::Only {
all_targets: false,
lib: lib_only,
lib: rule_lib,
bins: rule_bins,
examples: rule_exms,
benches: rule_bens,
Expand Down Expand Up @@ -454,7 +483,7 @@ impl CompileFilter {
match *self {
CompileFilter::Default { .. } => true,
CompileFilter::Only {
lib,
ref lib,
ref bins,
ref examples,
ref tests,
Expand All @@ -466,7 +495,11 @@ impl CompileFilter {
TargetKind::Test => tests,
TargetKind::Bench => benches,
TargetKind::ExampleBin | TargetKind::ExampleLib(..) => examples,
TargetKind::Lib(..) => return lib,
TargetKind::Lib(..) => return match *lib {
LibRule::True => true,
LibRule::Default => true,
LibRule::False => false,
},
TargetKind::CustomBuild => return false,
};
rule.matches(target)
Expand Down Expand Up @@ -620,13 +653,13 @@ fn generate_targets<'a>(
}
CompileFilter::Only {
all_targets,
lib,
ref lib,
ref bins,
ref examples,
ref tests,
ref benches,
} => {
if lib {
if *lib != LibRule::False {
let mut libs = Vec::new();
for proposal in filter_targets(packages, Target::is_lib, false, build_config.mode) {
let Proposal { target, pkg, .. } = proposal;
Expand All @@ -640,7 +673,7 @@ fn generate_targets<'a>(
libs.push(proposal)
}
}
if !all_targets && libs.is_empty() {
if !all_targets && libs.is_empty() && *lib == LibRule::True {
let names = packages.iter().map(|pkg| pkg.name()).collect::<Vec<_>>();
if names.len() == 1 {
failure::bail!("no library targets found in package `{}`", names[0]);
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub use self::cargo_clean::{clean, CleanOptions};
pub use self::cargo_compile::{compile, compile_with_exec, compile_ws, CompileOptions};
pub use self::cargo_compile::{CompileFilter, FilterRule, Packages};
pub use self::cargo_compile::{CompileFilter, FilterRule, LibRule, Packages};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_fetch::{fetch, FetchOptions};
pub use self::cargo_generate_lockfile::generate_lockfile;
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ pub trait ArgMatchesExt {
all_features: self._is_present("all-features"),
no_default_features: self._is_present("no-default-features"),
spec,
filter: CompileFilter::new(
filter: CompileFilter::from_raw_arguments(
self._is_present("lib"),
self._values_of("bin"),
self._is_present("bins"),
Expand Down
10 changes: 5 additions & 5 deletions tests/testsuite/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1955,7 +1955,7 @@ fn explicit_examples() {
)
.build();

p.cargo("test -v").run();
p.cargo("build --examples").run();
p.process(&p.bin("examples/hello"))
.with_stdout("Hello, World!\n")
.run();
Expand Down Expand Up @@ -2126,7 +2126,7 @@ fn implicit_examples() {
)
.build();

p.cargo("test").run();
p.cargo("build --examples").run();
p.process(&p.bin("examples/hello"))
.with_stdout("Hello, World!\n")
.run();
Expand Down Expand Up @@ -2739,13 +2739,13 @@ fn example_bin_same_name() {
.file("examples/foo.rs", "fn main() {}")
.build();

p.cargo("test --no-run -v").run();
p.cargo("build --examples").run();

assert!(!p.bin("foo").is_file());
// We expect a file of the form bin/foo-{metadata_hash}
assert!(p.bin("examples/foo").is_file());

p.cargo("test --no-run -v").run();
p.cargo("build --examples").run();

assert!(!p.bin("foo").is_file());
// We expect a file of the form bin/foo-{metadata_hash}
Expand Down Expand Up @@ -4212,7 +4212,7 @@ fn inferred_examples() {
.file("examples/baz/main.rs", "fn main() {}")
.build();

p.cargo("test").run();
p.cargo("build --examples").run();
assert!(p.bin("examples/bar").is_file());
assert!(p.bin("examples/baz").is_file());
}
Expand Down
1 change: 0 additions & 1 deletion tests/testsuite/freshness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ fn changing_profiles_caches_targets() {
"\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target[..]debug[..]deps[..]foo-[..][EXE]
[DOCTEST] foo
",
)
.run();
Expand Down
42 changes: 37 additions & 5 deletions tests/testsuite/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ fn cargo_test_verbose() {
[COMPILING] foo v0.5.0 ([CWD])
[RUNNING] `rustc [..] src/main.rs [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `[..]target/debug/deps/foo-[..][EXE] hello`",
[RUNNING] `[CWD]/target/debug/deps/foo-[..] hello`
",
)
.with_stdout_contains("test test_hello ... ok")
.run();
Expand Down Expand Up @@ -601,21 +602,21 @@ fn pass_through_command_line() {
[COMPILING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target/debug/deps/foo-[..][EXE]
[DOCTEST] foo",
",
)
.with_stdout_contains("running 1 test")
.with_stdout_contains("test bar ... ok")
.with_stdout_contains("running 0 tests")
.run();

p.cargo("test foo")
.with_stderr(
"\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] target/debug/deps/foo-[..][EXE]
[DOCTEST] foo",
",
)
.with_stdout_contains("running 1 test")
.with_stdout_contains("test foo ... ok")
.with_stdout_contains("running 0 tests")
.run();
}

Expand Down Expand Up @@ -1462,6 +1463,37 @@ fn test_run_implicit_example_target() {
.run();
}

#[test]
fn test_filtered_excludes_compiling_examples() {
let p = project()
.file(
"src/lib.rs",
"#[cfg(test)] mod tests { #[test] fn foo() { assert!(true); } }",
)
.file("examples/ex1.rs", "fn main() {}")
.build();

p.cargo("test -v foo")
.with_stdout(
"
running 1 test
test tests::foo ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
",
)
.with_stderr("\
[COMPILING] foo v0.0.1 ([CWD])
[RUNNING] `rustc --crate-name foo src/lib.rs [..] --test [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `[CWD]/target/debug/deps/foo-[..] foo`
",
)
.with_stderr_does_not_contain("[RUNNING][..]rustc[..]ex1[..]")
.run();
}

#[test]
fn test_no_harness() {
let p = project()
Expand Down

0 comments on commit 4536bc9

Please sign in to comment.