blob: a367aa53496677e30c3a4ff1415cfa57bf428b62 [file] [log] [blame]
use super::*;
use crate::config::{Config, TargetSelection};
use std::thread;
fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
let mut config = Config::parse(&[cmd.to_owned()]);
// don't save toolstates
config.save_toolstates = None;
config.dry_run = true;
config.ninja_in_file = false;
// try to avoid spurious failures in dist where we create/delete each others file
config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
let dir = config
.out
.join("tmp-rustbuild-tests")
.join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
t!(fs::create_dir_all(&dir));
config.out = dir;
config.build = TargetSelection::from_user("A");
config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect();
config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect();
config
}
fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
}
mod defaults {
use super::{configure, first};
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 a = TargetSelection::from_user("A");
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
]
);
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
// Make sure rustdoc is only built once.
assert_eq!(
first(builder.cache.all::<tool::Rustdoc>()),
// 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::<compile::Rustc>()),
&[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
}
#[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 a = TargetSelection::from_user("A");
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
assert_eq!(
first(builder.cache.all::<tool::Rustdoc>()),
// 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::<compile::Rustc>().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 a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
// Ideally, this build wouldn't actually have `target: a`
// rustdoc/rustcc/std here (the user only requested a host=B build, so
// there's not really a need for us to build for target A in this case
// (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::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
]
);
assert_eq!(
first(builder.cache.all::<compile::Assemble>()),
&[
compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } },
]
);
assert_eq!(
first(builder.cache.all::<tool::Rustdoc>()),
&[
tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } },
],
);
assert_eq!(
first(builder.cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b },
]
);
}
#[test]
fn doc_default() {
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 a = TargetSelection::from_user("A");
// error_index_generator uses stage 0 to share rustdoc artifacts with the
// rustdoc tool.
assert_eq!(
first(builder.cache.all::<doc::ErrorIndex>()),
&[doc::ErrorIndex { compiler: Compiler { host: a, stage: 0 }, target: a },]
);
assert_eq!(
first(builder.cache.all::<tool::ErrorIndex>()),
&[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::<tool::Rustdoc>()),
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },]
);
}
}
mod dist {
use super::{first, Config};
use crate::builder::*;
use pretty_assertions::assert_eq;
fn configure(host: &[&str], target: &[&str]) -> Config {
Config { stage: 2, ..super::configure("dist", host, target) }
}
#[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 a = TargetSelection::from_user("A");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
assert_eq!(
first(builder.cache.all::<dist::Rustc>()),
&[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
);
assert_eq!(
first(builder.cache.all::<dist::Std>()),
&[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },]
);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
// Make sure rustdoc is only built once.
assert_eq!(
first(builder.cache.all::<tool::Rustdoc>()),
&[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 a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
assert_eq!(
first(builder.cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b },]
);
assert_eq!(
first(builder.cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b },]
);
assert_eq!(
first(builder.cache.all::<dist::Rustc>()),
&[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
);
assert_eq!(
first(builder.cache.all::<dist::Std>()),
&[
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>()), &[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 a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
assert_eq!(
first(builder.cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b },]
);
assert_eq!(
first(builder.cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b },]
);
assert_eq!(
first(builder.cache.all::<dist::Rustc>()),
&[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]
);
assert_eq!(
first(builder.cache.all::<dist::Std>()),
&[
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::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
],
);
assert_eq!(first(builder.cache.all::<dist::Src>()), &[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), &[]);
assert_eq!(
first(builder.cache.all::<dist::Rustc>()),
&[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },]
);
assert_eq!(
first(builder.cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
]
);
}
#[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 a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
let c = TargetSelection::from_user("C");
assert_eq!(
first(builder.cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
);
assert_eq!(
first(builder.cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
);
assert_eq!(
first(builder.cache.all::<dist::Rustc>()),
&[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]
);
assert_eq!(
first(builder.cache.all::<dist::Std>()),
&[
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>()), &[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 a = TargetSelection::from_user("A");
let c = TargetSelection::from_user("C");
assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: c },]);
assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: c },]);
assert_eq!(
first(builder.cache.all::<dist::Std>()),
&[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 a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
assert_eq!(
first(builder.cache.all::<dist::Docs>()),
&[dist::Docs { host: a }, dist::Docs { host: b },]
);
assert_eq!(
first(builder.cache.all::<dist::Mingw>()),
&[dist::Mingw { host: a }, dist::Mingw { host: b },]
);
assert_eq!(
first(builder.cache.all::<dist::Rustc>()),
&[
dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
]
);
assert_eq!(
first(builder.cache.all::<dist::Std>()),
&[
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>()), &[dist::Src]);
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
]
);
assert_eq!(
first(builder.cache.all::<compile::Assemble>()),
&[
compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } },
]
);
}
#[test]
fn build_all() {
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::Build),
&["compiler/rustc".into(), "library/std".into()],
);
let a = TargetSelection::from_user("A");
let b = TargetSelection::from_user("B");
let c = TargetSelection::from_user("C");
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
]
);
assert!(!builder.cache.all::<compile::Assemble>().is_empty());
assert_eq!(
first(builder.cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b },
]
);
}
#[test]
fn build_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::Build), &[]);
let a = TargetSelection::from_user("A");
let c = TargetSelection::from_user("C");
assert_eq!(
first(builder.cache.all::<compile::Std>()),
&[
compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
]
);
assert_eq!(
first(builder.cache.all::<compile::Assemble>()),
&[
compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
]
);
assert_eq!(
first(builder.cache.all::<compile::Rustc>()),
&[
compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
]
);
}
#[test]
fn test_with_no_doc_stage0() {
let mut config = configure(&["A"], &["A"]);
config.stage = 0;
config.cmd = Subcommand::Test {
paths: vec!["library/std".into()],
test_args: vec![],
rustc_args: vec![],
fail_fast: true,
doc_tests: DocTests::No,
bless: false,
compare_mode: None,
rustfix_coverage: false,
pass: None,
};
let build = Build::new(config);
let mut builder = Builder::new(&build);
let host = TargetSelection::from_user("A");
builder.run_step_descriptions(
&[StepDescription::from::<test::Crate>()],
&["library/std".into()],
);
// Ensure we don't build any compiler artifacts.
assert!(!builder.cache.contains::<compile::Rustc>());
assert_eq!(
first(builder.cache.all::<test::Crate>()),
&[test::Crate {
compiler: Compiler { host, stage: 0 },
target: host,
mode: Mode::Std,
test_kind: test::TestKind::Test,
krate: INTERNER.intern_str("std"),
},]
);
}
#[test]
fn test_exclude() {
let mut config = configure(&["A"], &["A"]);
config.exclude = vec!["src/tools/tidy".into()];
config.cmd = Subcommand::Test {
paths: Vec::new(),
test_args: Vec::new(),
rustc_args: Vec::new(),
fail_fast: true,
doc_tests: DocTests::No,
bless: false,
compare_mode: None,
rustfix_coverage: false,
pass: 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::<test::Tidy>());
// Ensure other tests are not affected.
assert!(builder.cache.contains::<test::RustdocUi>());
}
#[test]
fn doc_ci() {
let mut config = configure(&["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 a = TargetSelection::from_user("A");
// error_index_generator uses stage 1 to share rustdoc artifacts with the
// rustdoc tool.
assert_eq!(
first(builder.cache.all::<doc::ErrorIndex>()),
&[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },]
);
assert_eq!(
first(builder.cache.all::<tool::ErrorIndex>()),
&[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
);
// This is actually stage 1, but Rustdoc::run swaps out the compiler with
// stage minus 1 if --stage is not 0. Very confusing!
assert_eq!(
first(builder.cache.all::<tool::Rustdoc>()),
&[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
);
}
#[test]
fn test_docs() {
// Behavior of `x.py test` doing various documentation tests.
let mut config = configure(&["A"], &["A"]);
config.cmd = Subcommand::Test {
paths: vec![],
test_args: vec![],
rustc_args: vec![],
fail_fast: true,
doc_tests: DocTests::Yes,
bless: false,
compare_mode: None,
rustfix_coverage: false,
pass: None,
};
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
let a = TargetSelection::from_user("A");
// error_index_generator uses stage 1 to share rustdoc artifacts with the
// rustdoc tool.
assert_eq!(
first(builder.cache.all::<doc::ErrorIndex>()),
&[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },]
);
assert_eq!(
first(builder.cache.all::<tool::ErrorIndex>()),
&[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
);
// Unfortunately rustdoc is built twice. Once from stage1 for compiletest
// (and other things), and once from stage0 for std crates. Ideally it
// would only be built once. If someone wants to fix this, it might be
// worth investigating if it would be possible to test std from stage1.
// Note that the stages here are +1 than what they actually are because
// Rustdoc::run swaps out the compiler with stage minus 1 if --stage is
// not 0.
assert_eq!(
first(builder.cache.all::<tool::Rustdoc>()),
&[
tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },
]
);
}
}