From 068142a2e6d8a72e52091ccebd3368ffaf267643 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Mar 2016 17:49:02 -0400 Subject: [PATCH] add incremental test runner and some tests --- mk/tests.mk | 12 ++++- src/compiletest/common.rs | 5 +- src/compiletest/compiletest.rs | 3 +- src/compiletest/runtest.rs | 65 +++++++++++++++++++++++++ src/test/incremental/dirty_clean.rs | 54 ++++++++++++++++++++ src/test/incremental/hello_world.rs | 46 +++++++++++++++++ src/test/incremental/string_constant.rs | 58 ++++++++++++++++++++++ 7 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 src/test/incremental/dirty_clean.rs create mode 100644 src/test/incremental/hello_world.rs create mode 100644 src/test/incremental/string_constant.rs diff --git a/mk/tests.mk b/mk/tests.mk index 1a02b5c2281..0b8f0f80dea 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -305,6 +305,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \ check-stage$(1)-T-$(2)-H-$(3)-debuginfo-gdb-exec \ check-stage$(1)-T-$(2)-H-$(3)-debuginfo-lldb-exec \ + check-stage$(1)-T-$(2)-H-$(3)-incremental-exec \ check-stage$(1)-T-$(2)-H-$(3)-doc-exec \ check-stage$(1)-T-$(2)-H-$(3)-pretty-exec @@ -481,6 +482,7 @@ DEBUGINFO_LLDB_RS := $(call rwildcard,$(S)src/test/debuginfo/,*.rs) CODEGEN_RS := $(call rwildcard,$(S)src/test/codegen/,*.rs) CODEGEN_CC := $(call rwildcard,$(S)src/test/codegen/,*.cc) CODEGEN_UNITS_RS := $(call rwildcard,$(S)src/test/codegen-units/,*.rs) +INCREMENTAL_RS := $(call rwildcard,$(S)src/test/incremental/,*.rs) RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs) RPASS_TESTS := $(RPASS_RS) @@ -496,6 +498,7 @@ DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS) DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS) CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC) CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS) +INCREMENTAL_TESTS := $(INCREMENTAL_RS) RUSTDOCCK_TESTS := $(RUSTDOCCK_RS) CTEST_SRC_BASE_rpass = run-pass @@ -558,6 +561,11 @@ CTEST_BUILD_BASE_codegen-units = codegen-units CTEST_MODE_codegen-units = codegen-units CTEST_RUNTOOL_codegen-units = $(CTEST_RUNTOOL) +CTEST_SRC_BASE_incremental = incremental +CTEST_BUILD_BASE_incremental = incremental +CTEST_MODE_incremental = incremental +CTEST_RUNTOOL_incremental = $(CTEST_RUNTOOL) + CTEST_SRC_BASE_rustdocck = rustdoc CTEST_BUILD_BASE_rustdocck = rustdoc CTEST_MODE_rustdocck = rustdoc @@ -681,6 +689,7 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \ $(S)src/etc/lldb_rust_formatters.py CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS) CTEST_DEPS_codegen-units_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_UNITS_TESTS) +CTEST_DEPS_incremental_$(1)-T-$(2)-H-$(3) = $$(INCREMENTAL_TESTS) CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ $(S)src/etc/htmldocck.py @@ -747,7 +756,7 @@ endif endef CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \ - debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck + debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental $(foreach host,$(CFG_HOST), \ $(eval $(foreach target,$(CFG_TARGET), \ @@ -945,6 +954,7 @@ TEST_GROUPS = \ debuginfo-lldb \ codegen \ codegen-units \ + incremental \ doc \ $(foreach docname,$(DOC_NAMES),doc-$(docname)) \ pretty \ diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index bfcc1759b95..a6960ff1785 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -25,7 +25,8 @@ pub enum Mode { DebugInfoLldb, Codegen, Rustdoc, - CodegenUnits + CodegenUnits, + Incremental, } impl FromStr for Mode { @@ -43,6 +44,7 @@ impl FromStr for Mode { "codegen" => Ok(Codegen), "rustdoc" => Ok(Rustdoc), "codegen-units" => Ok(CodegenUnits), + "incremental" => Ok(Incremental), _ => Err(()), } } @@ -62,6 +64,7 @@ impl fmt::Display for Mode { Codegen => "codegen", Rustdoc => "rustdoc", CodegenUnits => "codegen-units", + Incremental => "incremental", }, f) } } diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 787d77bc56c..1c06b2a23d5 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -71,7 +71,8 @@ pub fn parse_config(args: Vec ) -> Config { reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"), reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"), reqopt("", "mode", "which sort of compile tests to run", - "(compile-fail|parse-fail|run-fail|run-pass|run-pass-valgrind|pretty|debug-info)"), + "(compile-fail|parse-fail|run-fail|run-pass|\ + run-pass-valgrind|pretty|debug-info|incremental)"), optflag("", "ignored", "run tests marked as ignored"), optopt("", "runtool", "supervisor program to run tests under \ (eg. emulator, valgrind)", "PROGRAM"), diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 24fd413ef09..802b967ed7d 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -11,6 +11,7 @@ use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits}; +use common::{Incremental}; use errors::{self, ErrorKind}; use header::TestProps; use header; @@ -59,6 +60,7 @@ pub fn run(config: Config, testpaths: &TestPaths) { Codegen => run_codegen_test(&config, &props, &testpaths), Rustdoc => run_rustdoc_test(&config, &props, &testpaths), CodegenUnits => run_codegen_units_test(&config, &props, &testpaths), + Incremental => run_incremental_test(&config, &props, &testpaths), } } @@ -1966,3 +1968,66 @@ fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPa panic!(); } } + +fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPaths) { + // Basic plan for a test incremental/foo/bar.rs: + // - load list of revisions pass1, fail2, pass3 + // - each should begin with `pass` or `fail` + // - if `pass`, expect compile to succeed + // - if `fail`, expect errors from file + // - create a directory build/foo/bar.incremental + // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C pass1 + // - because name of revision starts with "pass", expect success + // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C fail2 + // - because name of revision starts with "fail", expect an error + // - load expected errors as usual, but filter for those that end in `[fail2]` + // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C pass3 + // - because name of revision starts with "pass", expect success + // - execute build/foo/bar.exe and save output + // + // FIXME -- use non-incremental mode as an oracle? That doesn't apply + // to #[rustc_dirty] and clean tests I guess + + assert!(!props.revisions.is_empty(), "incremental tests require a list of revisions"); + + let output_base_name = output_base_name(config, testpaths); + + // Create the incremental workproduct directory. + let incremental_dir = output_base_name.with_extension("incremental"); + if incremental_dir.exists() { + fs::remove_dir_all(&incremental_dir).unwrap(); + } + fs::create_dir_all(&incremental_dir).unwrap(); + + if config.verbose { + print!("incremental_dir={}", incremental_dir.display()); + } + + for revision in &props.revisions { + let mut revision_props = props.clone(); + header::load_props_into(&mut revision_props, &testpaths.file, Some(&revision)); + + revision_props.compile_flags.extend(vec![ + format!("-Z"), + format!("incremental={}", incremental_dir.display()), + format!("--cfg"), + format!("{}", revision), + ]); + + if config.verbose { + print!("revision={:?} revision_props={:#?}", revision, revision_props); + } + + if revision.starts_with("rpass") { + run_rpass_test_revision(config, &revision_props, testpaths, Some(&revision)); + } else if revision.starts_with("rfail") { + run_rfail_test_revision(config, &revision_props, testpaths, Some(&revision)); + } else if revision.starts_with("cfail") { + run_cfail_test_revision(config, &revision_props, testpaths, Some(&revision)); + } else { + fatal( + Some(revision), + "revision name must begin with rpass, rfail, or cfail"); + } + } +} diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs new file mode 100644 index 00000000000..f0e596baa2d --- /dev/null +++ b/src/test/incremental/dirty_clean.rs @@ -0,0 +1,54 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: rpass1 cfail2 + +#![allow(warnings)] +#![feature(rustc_attrs)] + +// Sanity check for the dirty-clean system. Give the opposite +// annotations that we expect to see, so that we check that errors are +// reported. + +fn main() { } + +mod x { + #[cfg(rpass1)] + pub fn x() -> usize { + 22 + } + + #[cfg(cfail2)] + pub fn x() -> u32 { + 22 + } +} + +mod y { + use x; + + #[rustc_clean(label="TypeckItemBody", cfg="cfail2")] + #[rustc_clean(label="TransCrateItem", cfg="cfail2")] + pub fn y() { + //[cfail2]~^ ERROR `TypeckItemBody("y::y")` not found in dep graph, but should be clean + //[cfail2]~| ERROR `TransCrateItem("y::y")` not found in dep graph, but should be clean + x::x(); + } +} + +mod z { + #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")] + #[rustc_dirty(label="TransCrateItem", cfg="cfail2")] + pub fn z() { + //[cfail2]~^ ERROR `TypeckItemBody("z::z")` found in dep graph, but should be dirty + // FIXME(#32014) -- TransCrateItem ought to be clean, but it is in fact + // dirty, hence we don't see an error here. + } +} diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs new file mode 100644 index 00000000000..f98ae188bad --- /dev/null +++ b/src/test/incremental/hello_world.rs @@ -0,0 +1,46 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: rpass1 rpass2 + +#![allow(warnings)] +#![feature(rustc_attrs)] + +fn main() { } + +mod x { + #[cfg(rpass1)] + pub fn x() -> i32 { + 1 + } + + #[cfg(rpass2)] + pub fn x() -> i32 { + 2 + } +} + +mod y { + use x; + + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn y() { + x::x(); + } +} + +mod z { + use y; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn z() { + y::y(); + } +} diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs new file mode 100644 index 00000000000..1acca8b2952 --- /dev/null +++ b/src/test/incremental/string_constant.rs @@ -0,0 +1,58 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: rpass1 rpass2 + +#![allow(warnings)] +#![feature(rustc_attrs)] + +// Here the only thing which changes is the string constant in `x`. +// Therefore, the compiler deduces (correctly) that typeck is not +// needed even for callers of `x`. +// +// It is not entirely clear why `TransCrateItem` invalidates `y` and +// `z`, actually, I think it's because of the structure of +// trans. -nmatsakis + +fn main() { } + +mod x { + #[cfg(rpass1)] + pub fn x() { + println!("1"); + } + + #[cfg(rpass2)] + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_dirty(label="TransCrateItem", cfg="rpass2")] + pub fn x() { + println!("2"); + } +} + +mod y { + use x; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_dirty(label="TransCrateItem", cfg="rpass2")] + pub fn y() { + x::x(); + } +} + +mod z { + use y; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_dirty(label="TransCrateItem", cfg="rpass2")] + pub fn z() { + y::y(); + } +}