diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index a59f72ed968b4..3b6cd7564f08a 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -7,6 +7,7 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { // don't save toolstates config.save_toolstates = None; config.dry_run = true; + config.submodules = Some(false); config.ninja_in_file = false; // try to avoid spurious failures in dist where we create/delete each others file // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us @@ -25,36 +26,74 @@ fn first(v: Vec<(A, B)>) -> Vec { v.into_iter().map(|(a, _)| a).collect::>() } +fn run_build(paths: &[PathBuf], config: Config) -> Cache { + let kind = config.cmd.kind(); + let build = Build::new(config); + let builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(kind), paths); + builder.cache +} + +#[test] +fn test_exclude() { + let mut config = configure("test", &["A"], &["A"]); + config.exclude = vec![TaskPath::parse("src/tools/tidy")]; + let cache = run_build(&[], config); + + // Ensure we have really excluded tidy + assert!(!cache.contains::()); + + // Ensure other tests are not affected. + assert!(cache.contains::()); +} + +#[test] +fn test_exclude_kind() { + let path = PathBuf::from("src/tools/cargotest"); + let exclude = TaskPath::parse("test::src/tools/cargotest"); + assert_eq!(exclude, TaskPath { kind: Some(Kind::Test), path: path.clone() }); + + let mut config = configure("test", &["A"], &["A"]); + // Ensure our test is valid, and `test::Cargotest` would be run without the exclude. + assert!(run_build(&[path.clone()], config.clone()).contains::()); + // Ensure tests for cargotest are skipped. + config.exclude = vec![exclude.clone()]; + assert!(!run_build(&[path.clone()], config).contains::()); + + // Ensure builds for cargotest are not skipped. + let mut config = configure("build", &["A"], &["A"]); + config.exclude = vec![exclude]; + assert!(run_build(&[path], config).contains::()); +} + mod defaults { - use super::{configure, first}; + use super::{configure, first, run_build}; use crate::builder::*; use crate::Config; use pretty_assertions::assert_eq; #[test] fn build_default() { - let build = Build::new(configure("build", &["A"], &["A"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + let mut cache = run_build(&[], configure("build", &["A"], &["A"])); let a = TargetSelection::from_user("A"); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, ] ); - assert!(!builder.cache.all::().is_empty()); + assert!(!cache.all::().is_empty()); // Make sure rustdoc is only built once. assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), // Recall that rustdoc stages are off-by-one // - this is the compiler it's _linked_ to, not built with. &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }], ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },] ); } @@ -62,31 +101,27 @@ mod defaults { #[test] fn build_stage_0() { let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) }; - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + let mut cache = run_build(&[], config); let a = TargetSelection::from_user("A"); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },] ); - assert!(!builder.cache.all::().is_empty()); + assert!(!cache.all::().is_empty()); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), // This is the beta rustdoc. // Add an assert here to make sure this is the only rustdoc built. &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }], ); - assert!(builder.cache.all::().is_empty()); + assert!(cache.all::().is_empty()); } #[test] fn build_cross_compile() { let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) }; - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + let mut cache = run_build(&[], config); let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); @@ -97,7 +132,7 @@ mod defaults { // (since we're producing stage 1 libraries/binaries). But currently // rustbuild is just a bit buggy here; this should be fixed though. assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, @@ -106,7 +141,7 @@ mod defaults { ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, @@ -114,14 +149,14 @@ mod defaults { ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, ], ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, @@ -134,33 +169,28 @@ mod defaults { let mut config = configure("doc", &["A"], &["A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]); + let mut cache = run_build(&[], config); let a = TargetSelection::from_user("A"); // error_index_generator uses stage 0 to share rustdoc artifacts with the // rustdoc tool. + assert_eq!(first(cache.all::()), &[doc::ErrorIndex { target: a },]); assert_eq!( - first(builder.cache.all::()), - &[doc::ErrorIndex { target: a },] - ); - assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }] ); // docs should be built with the beta compiler, not with the stage0 artifacts. // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to, // not the one it was built by. assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },] ); } } mod dist { - use super::{first, Config}; + use super::{first, run_build, Config}; use crate::builder::*; use pretty_assertions::assert_eq; @@ -170,94 +200,88 @@ mod dist { #[test] fn dist_baseline() { - let build = Build::new(configure(&["A"], &["A"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut cache = run_build(&[], configure(&["A"], &["A"])); let a = TargetSelection::from_user("A"); - assert_eq!(first(builder.cache.all::()), &[dist::Docs { host: a },]); - assert_eq!(first(builder.cache.all::()), &[dist::Mingw { host: a },]); + assert_eq!(first(cache.all::()), &[dist::Docs { host: a },]); + assert_eq!(first(cache.all::()), &[dist::Mingw { host: a },]); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },] ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!(first(cache.all::()), &[dist::Src]); // Make sure rustdoc is only built once. assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] ); } #[test] fn dist_with_targets() { - let build = Build::new(configure(&["A"], &["A", "B"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut cache = run_build(&[], configure(&["A"], &["A", "B"])); let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { host: b },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { host: b },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, ] ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!(first(cache.all::()), &[dist::Src]); } #[test] fn dist_with_hosts() { - let build = Build::new(configure(&["A", "B"], &["A", "B"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"])); let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { host: b },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { host: b },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, @@ -266,26 +290,25 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, ], ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!(first(cache.all::()), &[dist::Src]); } #[test] fn dist_only_cross_host() { let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); - let mut build = Build::new(configure(&["A", "B"], &["A", "B"])); - build.config.docs = false; - build.config.extended = true; - build.hosts = vec![b]; - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut config = configure(&["A", "B"], &["A", "B"]); + config.docs = false; + config.extended = true; + config.hosts = vec![b]; + let mut cache = run_build(&[], config); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, @@ -295,92 +318,86 @@ mod dist { #[test] fn dist_with_targets_and_hosts() { - let build = Build::new(configure(&["A", "B"], &["A", "B", "C"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B", "C"])); let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); let c = TargetSelection::from_user("C"); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, ] ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!(first(cache.all::()), &[dist::Src]); } #[test] fn dist_with_empty_host() { let config = configure(&[], &["C"]); - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut cache = run_build(&[], config); let a = TargetSelection::from_user("A"); let c = TargetSelection::from_user("C"); - assert_eq!(first(builder.cache.all::()), &[dist::Docs { host: c },]); - assert_eq!(first(builder.cache.all::()), &[dist::Mingw { host: c },]); + assert_eq!(first(cache.all::()), &[dist::Docs { host: c },]); + assert_eq!(first(cache.all::()), &[dist::Mingw { host: c },]); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },] ); } #[test] fn dist_with_same_targets_and_hosts() { - let build = Build::new(configure(&["A", "B"], &["A", "B"])); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"])); let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Docs { host: a }, dist::Docs { host: b },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[dist::Mingw { host: a }, dist::Mingw { host: b },] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); - assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!(first(cache.all::()), &[dist::Src]); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, @@ -390,7 +407,7 @@ mod dist { ] ); assert_eq!( - first(builder.cache.all::()), + first(cache.all::()), &[ compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, @@ -514,35 +531,6 @@ mod dist { ); } - #[test] - fn test_exclude() { - let mut config = configure(&["A"], &["A"]); - config.exclude = vec![TaskPath::parse("src/tools/tidy")]; - config.cmd = Subcommand::Test { - paths: Vec::new(), - test_args: Vec::new(), - rustc_args: Vec::new(), - fail_fast: true, - doc_tests: DocTests::No, - bless: false, - force_rerun: false, - compare_mode: None, - rustfix_coverage: false, - pass: None, - run: None, - }; - - let build = Build::new(config); - let builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); - - // Ensure we have really excluded tidy - assert!(!builder.cache.contains::()); - - // Ensure other tests are not affected. - assert!(builder.cache.contains::()); - } - #[test] fn doc_ci() { let mut config = configure(&["A"], &["A"]); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index f273fb42215e9..1638d3ed3c281 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -41,6 +41,7 @@ macro_rules! check_ci_llvm { /// each field, see the corresponding fields in /// `config.toml.example`. #[derive(Default)] +#[cfg_attr(test, derive(Clone))] pub struct Config { pub changelog_seen: Option, pub ccache: Option, @@ -330,6 +331,7 @@ impl PartialEq<&str> for TargetSelection { /// Per-target configuration stored in the global configuration structure. #[derive(Default)] +#[cfg_attr(test, derive(Clone))] pub struct Target { /// Some(path to llvm-config) if using an external LLVM. pub llvm_config: Option, diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index a82eb52e232b4..58571ea129c19 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -14,6 +14,7 @@ use crate::setup::Profile; use crate::util::t; use crate::{Build, DocTests}; +#[derive(Copy, Clone)] pub enum Color { Always, Never, @@ -79,6 +80,7 @@ pub struct Flags { pub llvm_profile_generate: bool, } +#[cfg_attr(test, derive(Clone))] pub enum Subcommand { Build { paths: Vec, @@ -668,6 +670,24 @@ Arguments: } impl Subcommand { + pub fn kind(&self) -> Kind { + match self { + Subcommand::Bench { .. } => Kind::Bench, + Subcommand::Build { .. } => Kind::Build, + Subcommand::Check { .. } => Kind::Check, + Subcommand::Clippy { .. } => Kind::Clippy, + Subcommand::Doc { .. } => Kind::Doc, + Subcommand::Fix { .. } => Kind::Fix, + Subcommand::Format { .. } => Kind::Format, + Subcommand::Test { .. } => Kind::Test, + Subcommand::Clean { .. } => Kind::Clean, + Subcommand::Dist { .. } => Kind::Dist, + Subcommand::Install { .. } => Kind::Install, + Subcommand::Run { .. } => Kind::Run, + Subcommand::Setup { .. } => Kind::Setup, + } + } + pub fn test_args(&self) -> Vec<&str> { match *self { Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {