Add bless x.py subcommand for easy ui test replacement

This commit is contained in:
Oliver Schneider 2018-05-16 17:18:19 +02:00
parent e3150564f8
commit 37dee69dac
7 changed files with 111 additions and 59 deletions

View file

@ -297,7 +297,12 @@ fn main() {
}
if verbose > 1 {
eprintln!("rustc command: {:?}", cmd);
eprintln!(
"rustc command: {:?}={:?} {:?}",
bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap(),
cmd,
);
eprintln!("sysroot: {:?}", sysroot);
eprintln!("libdir: {:?}", libdir);
}

View file

@ -311,6 +311,8 @@ impl<'a> ShouldRun<'a> {
pub enum Kind {
Build,
Check,
/// Run tests and replace any failing tests' output files (stderr/stout) with the correct ones
Bless,
Test,
Bench,
Dist,
@ -334,6 +336,7 @@ impl<'a> Builder<'a> {
native::Llvm, tool::Rustfmt, tool::Miri, native::Lld),
Kind::Check => describe!(check::Std, check::Test, check::Rustc, check::CodegenBackend,
check::Rustdoc),
Kind::Bless |
Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass,
test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind,
test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo,
@ -367,6 +370,7 @@ impl<'a> Builder<'a> {
let kind = match subcommand {
"build" => Kind::Build,
"doc" => Kind::Doc,
"bless" => Kind::Bless,
"test" => Kind::Test,
"bench" => Kind::Bench,
"dist" => Kind::Dist,
@ -408,6 +412,7 @@ impl<'a> Builder<'a> {
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
Subcommand::Test { ref paths, bless: true, .. } => (Kind::Bless, &paths[..]),
Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),

View file

@ -59,6 +59,8 @@ pub enum Subcommand {
},
Test {
paths: Vec<PathBuf>,
/// Whether to automatically update stderr/stdout files
bless: bool,
test_args: Vec<String>,
rustc_args: Vec<String>,
fail_fast: bool,
@ -142,6 +144,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
let subcommand = args.iter().find(|&s|
(s == "build")
|| (s == "check")
|| (s == "bless")
|| (s == "test")
|| (s == "bench")
|| (s == "doc")
@ -162,6 +165,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
// Some subcommands get extra options
match subcommand.as_str() {
"bless" |
"test" => {
opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
opts.optmulti("", "test-args", "extra arguments", "ARGS");
@ -248,6 +252,12 @@ Arguments:
compilation, so there's no need to pass it separately, though it won't hurt. We also completely
ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
the compiler.");
}
"bless" => {
subcommand_help.push_str("\n
Arguments:
This subcommand works exactly like the `test` subcommand, but also updates stderr/stdout files
before they cause a test failure");
}
"test" => {
subcommand_help.push_str("\n
@ -319,9 +329,11 @@ Arguments:
"check" => {
Subcommand::Check { paths: paths }
}
"bless" |
"test" => {
Subcommand::Test {
paths,
bless: subcommand.as_str() == "bless",
test_args: matches.opt_strs("test-args"),
rustc_args: matches.opt_strs("rustc-args"),
fail_fast: !matches.opt_present("no-fail-fast"),

View file

@ -41,16 +41,31 @@ const ADB_TEST_DIR: &str = "/data/tmp/work";
/// The two modes of the test runner; tests or benchmarks.
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
pub enum TestKind {
/// Run `cargo bless`
Bless,
/// Run `cargo test`
Test,
/// Run `cargo bench`
Bench,
}
impl From<Kind> for TestKind {
fn from(kind: Kind) -> Self {
match kind {
Kind::Test => TestKind::Test,
Kind::Bless => TestKind::Bless,
Kind::Bench => TestKind::Bench,
_ => panic!("unexpected kind in crate: {:?}", kind)
}
}
}
impl TestKind {
// Return the cargo subcommand for this test kind
fn subcommand(self) -> &'static str {
match self {
// bless and test are both `test` for folder names and cargo subcommands
TestKind::Bless |
TestKind::Test => "test",
TestKind::Bench => "bench",
}
@ -60,6 +75,7 @@ impl TestKind {
impl fmt::Display for TestKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
TestKind::Bless => "Testing (bless)",
TestKind::Test => "Testing",
TestKind::Bench => "Benchmarking",
})
@ -951,6 +967,10 @@ impl Step for Compiletest {
cmd.arg("--host").arg(&*compiler.host);
cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
if builder.kind == Kind::Bless {
cmd.arg("--bless");
}
if let Some(ref nodejs) = builder.config.nodejs {
cmd.arg("--nodejs").arg(nodejs);
}
@ -1342,13 +1362,7 @@ impl Step for CrateLibrustc {
for krate in builder.in_tree_crates("rustc-main") {
if run.path.ends_with(&krate.path) {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(CrateLibrustc {
compiler,
@ -1394,13 +1408,7 @@ impl Step for CrateNotDefault {
let builder = run.builder;
let compiler = builder.compiler(builder.top_stage, run.host);
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(CrateNotDefault {
compiler,
@ -1461,13 +1469,7 @@ impl Step for Crate {
let compiler = builder.compiler(builder.top_stage, run.host);
let make = |mode: Mode, krate: &CargoCrate| {
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(Crate {
compiler,
@ -1625,13 +1627,7 @@ impl Step for CrateRustdoc {
fn make_run(run: RunConfig) {
let builder = run.builder;
let test_kind = if builder.kind == Kind::Test {
TestKind::Test
} else if builder.kind == Kind::Bench {
TestKind::Bench
} else {
panic!("unexpected builder.kind in crate: {:?}", builder.kind);
};
let test_kind = builder.kind.into();
builder.ensure(CrateRustdoc {
host: run.host,

View file

@ -118,6 +118,9 @@ impl CompareMode {
#[derive(Clone)]
pub struct Config {
/// Whether to overwrite stderr/stdout files instead of complaining about changes in output
pub bless: bool,
/// The library paths required for running the compiler
pub compile_lib_path: PathBuf,

View file

@ -166,6 +166,11 @@ pub fn parse_config(args: Vec<String>) -> Config {
"FLAGS",
)
.optflag("", "verbose", "run tests verbosely, showing all output")
.optflag(
"",
"bless",
"overwrite stderr/stdout files instead of complaining about a mismatch",
)
.optflag(
"",
"quiet",
@ -290,6 +295,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
let src_base = opt_path(matches, "src-base");
let run_ignored = matches.opt_present("ignored");
Config {
bless: matches.opt_present("bless"),
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
rustc_path: opt_path(matches, "rustc-path"),

View file

@ -2926,29 +2926,31 @@ impl<'test> TestCx<'test> {
return 0;
}
if expected.is_empty() {
println!("normalized {}:\n{}\n", kind, actual);
} else {
println!("diff of {}:\n", kind);
let diff_results = make_diff(expected, actual, 3);
for result in diff_results {
let mut line_number = result.line_number;
for line in result.lines {
match line {
DiffLine::Expected(e) => {
println!("-\t{}", e);
line_number += 1;
}
DiffLine::Context(c) => {
println!("{}\t{}", line_number, c);
line_number += 1;
}
DiffLine::Resulting(r) => {
println!("+\t{}", r);
if !self.config.bless {
if expected.is_empty() {
println!("normalized {}:\n{}\n", kind, actual);
} else {
println!("diff of {}:\n", kind);
let diff_results = make_diff(expected, actual, 3);
for result in diff_results {
let mut line_number = result.line_number;
for line in result.lines {
match line {
DiffLine::Expected(e) => {
println!("-\t{}", e);
line_number += 1;
}
DiffLine::Context(c) => {
println!("{}\t{}", line_number, c);
line_number += 1;
}
DiffLine::Resulting(r) => {
println!("+\t{}", r);
}
}
}
println!("");
}
println!("");
}
}
@ -2958,19 +2960,42 @@ impl<'test> TestCx<'test> {
.with_extra_extension(mode)
.with_extra_extension(kind);
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
Ok(()) => {}
Err(e) => self.fatal(&format!(
"failed to write {} to `{}`: {}",
kind,
output_file.display(),
e
)),
let mut files = vec![output_file];
if self.config.bless {
files.push(self.expected_output_path(kind));
}
for output_file in &files {
if actual.is_empty() {
if let Err(e) = ::std::fs::remove_file(output_file) {
self.fatal(&format!(
"failed to delete `{}`: {}",
output_file.display(),
e,
));
}
} else {
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
Ok(()) => {}
Err(e) => self.fatal(&format!(
"failed to write {} to `{}`: {}",
kind,
output_file.display(),
e
)),
}
}
}
println!("\nThe actual {0} differed from the expected {0}.", kind);
println!("Actual {} saved to {}", kind, output_file.display());
1
for output_file in files {
println!("Actual {} saved to {}", kind, output_file.display());
}
if self.config.bless {
0
} else {
1
}
}
fn create_stamp(&self) {