Auto merge of #68533 - tmiasko:compiletest, r=nikomatsakis

compiletest: Unit tests for `EarlyProps` (+ small cleanup)

* Parse `EarlyProps` from a reader
* Add unit tests for `EarlyProps`
* Remove unused `llvm-cxxflags` option
* Remove unnecessary memory allocations in `iter_header`
* Update mode list displayed in `--help`
This commit is contained in:
bors 2020-01-28 16:25:35 +00:00
commit ac2f3fa41a
6 changed files with 280 additions and 125 deletions

View File

@ -1149,7 +1149,6 @@ impl Step for Compiletest {
// requires that a C++ compiler was configured which isn't always the case.
if !builder.config.dry_run && suite == "run-make-fulldeps" {
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
cmd.arg("--cc")
.arg(builder.cc(target))
.arg("--cxx")
@ -1157,9 +1156,7 @@ impl Step for Compiletest {
.arg("--cflags")
.arg(builder.cflags(target, GitRepo::Rustc).join(" "))
.arg("--llvm-components")
.arg(llvm_components.trim())
.arg("--llvm-cxxflags")
.arg(llvm_cxxflags.trim());
.arg(llvm_components.trim());
if let Some(ar) = builder.ar(target) {
cmd.arg("--ar").arg(ar);
}
@ -1197,8 +1194,6 @@ impl Step for Compiletest {
.arg("--cflags")
.arg("")
.arg("--llvm-components")
.arg("")
.arg("--llvm-cxxflags")
.arg("");
}

View File

@ -319,7 +319,6 @@ pub struct Config {
pub ar: String,
pub linker: Option<String>,
pub llvm_components: String,
pub llvm_cxxflags: String,
/// Path to a NodeJS executable. Used for JS doctests, emscripten and WASM tests
pub nodejs: Option<String>,

View File

@ -24,6 +24,7 @@ enum ParsedNameDirective {
/// Properties which must be known very early, before actually running
/// the test.
#[derive(Default)]
pub struct EarlyProps {
pub ignore: bool,
pub should_fail: bool,
@ -34,18 +35,16 @@ pub struct EarlyProps {
impl EarlyProps {
pub fn from_file(config: &Config, testfile: &Path) -> Self {
let mut props = EarlyProps {
ignore: false,
should_fail: false,
aux: Vec::new(),
aux_crate: Vec::new(),
revisions: vec![],
};
let file = File::open(testfile).unwrap();
Self::from_reader(config, testfile, file)
}
pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
let mut props = EarlyProps::default();
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
iter_header(testfile, None, &mut |ln| {
iter_header(testfile, None, rdr, &mut |ln| {
// we should check if any only-<platform> exists and if it exists
// and does not matches the current platform, skip the test
if !props.ignore {
@ -392,138 +391,143 @@ impl TestProps {
/// `//[foo]`), then the property is ignored unless `cfg` is
/// `Some("foo")`.
fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
iter_header(testfile, cfg, &mut |ln| {
if let Some(ep) = config.parse_error_pattern(ln) {
self.error_patterns.push(ep);
}
if !testfile.is_dir() {
let file = File::open(testfile).unwrap();
if let Some(flags) = config.parse_compile_flags(ln) {
self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
}
iter_header(testfile, cfg, file, &mut |ln| {
if let Some(ep) = config.parse_error_pattern(ln) {
self.error_patterns.push(ep);
}
if let Some(edition) = config.parse_edition(ln) {
self.compile_flags.push(format!("--edition={}", edition));
}
if let Some(flags) = config.parse_compile_flags(ln) {
self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
}
if let Some(r) = config.parse_revisions(ln) {
self.revisions.extend(r);
}
if let Some(edition) = config.parse_edition(ln) {
self.compile_flags.push(format!("--edition={}", edition));
}
if self.run_flags.is_none() {
self.run_flags = config.parse_run_flags(ln);
}
if let Some(r) = config.parse_revisions(ln) {
self.revisions.extend(r);
}
if self.pp_exact.is_none() {
self.pp_exact = config.parse_pp_exact(ln, testfile);
}
if self.run_flags.is_none() {
self.run_flags = config.parse_run_flags(ln);
}
if !self.should_ice {
self.should_ice = config.parse_should_ice(ln);
}
if self.pp_exact.is_none() {
self.pp_exact = config.parse_pp_exact(ln, testfile);
}
if !self.build_aux_docs {
self.build_aux_docs = config.parse_build_aux_docs(ln);
}
if !self.should_ice {
self.should_ice = config.parse_should_ice(ln);
}
if !self.force_host {
self.force_host = config.parse_force_host(ln);
}
if !self.build_aux_docs {
self.build_aux_docs = config.parse_build_aux_docs(ln);
}
if !self.check_stdout {
self.check_stdout = config.parse_check_stdout(ln);
}
if !self.force_host {
self.force_host = config.parse_force_host(ln);
}
if !self.check_run_results {
self.check_run_results = config.parse_check_run_results(ln);
}
if !self.check_stdout {
self.check_stdout = config.parse_check_stdout(ln);
}
if !self.dont_check_compiler_stdout {
self.dont_check_compiler_stdout = config.parse_dont_check_compiler_stdout(ln);
}
if !self.check_run_results {
self.check_run_results = config.parse_check_run_results(ln);
}
if !self.dont_check_compiler_stderr {
self.dont_check_compiler_stderr = config.parse_dont_check_compiler_stderr(ln);
}
if !self.dont_check_compiler_stdout {
self.dont_check_compiler_stdout = config.parse_dont_check_compiler_stdout(ln);
}
if !self.no_prefer_dynamic {
self.no_prefer_dynamic = config.parse_no_prefer_dynamic(ln);
}
if !self.dont_check_compiler_stderr {
self.dont_check_compiler_stderr = config.parse_dont_check_compiler_stderr(ln);
}
if !self.pretty_expanded {
self.pretty_expanded = config.parse_pretty_expanded(ln);
}
if !self.no_prefer_dynamic {
self.no_prefer_dynamic = config.parse_no_prefer_dynamic(ln);
}
if let Some(m) = config.parse_pretty_mode(ln) {
self.pretty_mode = m;
}
if !self.pretty_expanded {
self.pretty_expanded = config.parse_pretty_expanded(ln);
}
if !self.pretty_compare_only {
self.pretty_compare_only = config.parse_pretty_compare_only(ln);
}
if let Some(m) = config.parse_pretty_mode(ln) {
self.pretty_mode = m;
}
if let Some(ab) = config.parse_aux_build(ln) {
self.aux_builds.push(ab);
}
if !self.pretty_compare_only {
self.pretty_compare_only = config.parse_pretty_compare_only(ln);
}
if let Some(ac) = config.parse_aux_crate(ln) {
self.aux_crates.push(ac);
}
if let Some(ab) = config.parse_aux_build(ln) {
self.aux_builds.push(ab);
}
if let Some(ee) = config.parse_env(ln, "exec-env") {
self.exec_env.push(ee);
}
if let Some(ac) = config.parse_aux_crate(ln) {
self.aux_crates.push(ac);
}
if let Some(ee) = config.parse_env(ln, "rustc-env") {
self.rustc_env.push(ee);
}
if let Some(ee) = config.parse_env(ln, "exec-env") {
self.exec_env.push(ee);
}
if let Some(ev) = config.parse_name_value_directive(ln, "unset-rustc-env") {
self.unset_rustc_env.push(ev);
}
if let Some(ee) = config.parse_env(ln, "rustc-env") {
self.rustc_env.push(ee);
}
if let Some(cl) = config.parse_check_line(ln) {
self.check_lines.push(cl);
}
if let Some(ev) = config.parse_name_value_directive(ln, "unset-rustc-env") {
self.unset_rustc_env.push(ev);
}
if let Some(of) = config.parse_forbid_output(ln) {
self.forbid_output.push(of);
}
if let Some(cl) = config.parse_check_line(ln) {
self.check_lines.push(cl);
}
if !self.check_test_line_numbers_match {
self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln);
}
if let Some(of) = config.parse_forbid_output(ln) {
self.forbid_output.push(of);
}
self.update_pass_mode(ln, cfg, config);
self.update_fail_mode(ln, config);
if !self.check_test_line_numbers_match {
self.check_test_line_numbers_match =
config.parse_check_test_line_numbers_match(ln);
}
if !self.ignore_pass {
self.ignore_pass = config.parse_ignore_pass(ln);
}
self.update_pass_mode(ln, cfg, config);
self.update_fail_mode(ln, config);
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") {
self.normalize_stdout.push(rule);
}
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") {
self.normalize_stderr.push(rule);
}
if !self.ignore_pass {
self.ignore_pass = config.parse_ignore_pass(ln);
}
if let Some(code) = config.parse_failure_status(ln) {
self.failure_status = code;
}
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") {
self.normalize_stdout.push(rule);
}
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") {
self.normalize_stderr.push(rule);
}
if !self.run_rustfix {
self.run_rustfix = config.parse_run_rustfix(ln);
}
if let Some(code) = config.parse_failure_status(ln) {
self.failure_status = code;
}
if !self.rustfix_only_machine_applicable {
self.rustfix_only_machine_applicable =
config.parse_rustfix_only_machine_applicable(ln);
}
if !self.run_rustfix {
self.run_rustfix = config.parse_run_rustfix(ln);
}
if self.assembly_output.is_none() {
self.assembly_output = config.parse_assembly_output(ln);
}
});
if !self.rustfix_only_machine_applicable {
self.rustfix_only_machine_applicable =
config.parse_rustfix_only_machine_applicable(ln);
}
if self.assembly_output.is_none() {
self.assembly_output = config.parse_assembly_output(ln);
}
});
}
if self.failure_status == -1 {
self.failure_status = match config.mode {
@ -617,7 +621,7 @@ impl TestProps {
}
}
fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
fn iter_header<R: Read>(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn FnMut(&str)) {
if testfile.is_dir() {
return;
}
@ -628,12 +632,18 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
// It took me like 2 days to debug why compile-flags werent taken into account for my test :)
let comment_with_brace = comment.to_string() + "[";
let rdr = BufReader::new(File::open(testfile).unwrap());
for ln in rdr.lines() {
let mut rdr = BufReader::new(rdr);
let mut ln = String::new();
loop {
ln.clear();
if rdr.read_line(&mut ln).unwrap() == 0 {
break;
}
// Assume that any directives will be found before the first
// module or function. This doesn't seem to be an optimization
// with a warm page cache. Maybe with a cold one.
let ln = ln.unwrap();
let ln = ln.trim();
if ln.starts_with("fn") || ln.starts_with("mod") {
return;

View File

@ -1,4 +1,7 @@
use super::*;
use std::path::Path;
use crate::common::{Config, Debugger};
use crate::header::{parse_normalization_string, EarlyProps};
#[test]
fn test_parse_normalization_string() {
@ -25,3 +28,153 @@ fn test_parse_normalization_string() {
assert_eq!(first, Some("something (32 bits)".to_owned()));
assert_eq!(s, " -> \"something ($WORD bits).");
}
fn config() -> Config {
let args = &[
"compiletest",
"--mode=ui",
"--compile-lib-path=",
"--run-lib-path=",
"--rustc-path=",
"--lldb-python=",
"--docck-python=",
"--src-base=",
"--build-base=",
"--stage-id=stage2",
"--cc=c",
"--cxx=c++",
"--cflags=",
"--llvm-components=",
"--android-cross-path=",
"--target=x86_64-unknown-linux-gnu",
];
let args = args.iter().map(ToString::to_string).collect();
crate::parse_config(args)
}
fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
let bytes = contents.as_bytes();
EarlyProps::from_reader(config, Path::new("a.rs"), bytes)
}
fn parse_makefile(config: &Config, contents: &str) -> EarlyProps {
let bytes = contents.as_bytes();
EarlyProps::from_reader(config, Path::new("Makefile"), bytes)
}
#[test]
fn should_fail() {
let config = config();
assert!(!parse_rs(&config, "").should_fail);
assert!(parse_rs(&config, "// should-fail").should_fail);
}
#[test]
fn revisions() {
let config = config();
assert_eq!(parse_rs(&config, "// revisions: a b c").revisions, vec!["a", "b", "c"],);
assert_eq!(
parse_makefile(&config, "# revisions: hello there").revisions,
vec!["hello", "there"],
);
}
#[test]
fn aux_build() {
let config = config();
assert_eq!(
parse_rs(
&config,
r"
// aux-build: a.rs
// aux-build: b.rs
"
)
.aux,
vec!["a.rs", "b.rs"],
);
}
#[test]
fn no_system_llvm() {
let mut config = config();
config.system_llvm = false;
assert!(!parse_rs(&config, "// no-system-llvm").ignore);
config.system_llvm = true;
assert!(parse_rs(&config, "// no-system-llvm").ignore);
}
#[test]
fn ignore_target() {
let mut config = config();
config.target = "x86_64-unknown-linux-gnu".to_owned();
assert!(parse_rs(&config, "// ignore-x86_64-unknown-linux-gnu").ignore);
assert!(parse_rs(&config, "// ignore-x86_64").ignore);
assert!(parse_rs(&config, "// ignore-linux").ignore);
assert!(parse_rs(&config, "// ignore-gnu").ignore);
assert!(parse_rs(&config, "// ignore-64bit").ignore);
assert!(!parse_rs(&config, "// ignore-i686").ignore);
assert!(!parse_rs(&config, "// ignore-windows").ignore);
assert!(!parse_rs(&config, "// ignore-msvc").ignore);
assert!(!parse_rs(&config, "// ignore-32bit").ignore);
}
#[test]
fn only_target() {
let mut config = config();
config.target = "x86_64-pc-windows-gnu".to_owned();
assert!(parse_rs(&config, "// only-i686").ignore);
assert!(parse_rs(&config, "// only-linux").ignore);
assert!(parse_rs(&config, "// only-msvc").ignore);
assert!(parse_rs(&config, "// only-32bit").ignore);
assert!(!parse_rs(&config, "// only-x86_64-pc-windows-gnu").ignore);
assert!(!parse_rs(&config, "// only-x86_64").ignore);
assert!(!parse_rs(&config, "// only-windows").ignore);
assert!(!parse_rs(&config, "// only-gnu").ignore);
assert!(!parse_rs(&config, "// only-64bit").ignore);
}
#[test]
fn stage() {
let mut config = config();
config.stage_id = "stage1".to_owned();
assert!(parse_rs(&config, "// ignore-stage1").ignore);
assert!(!parse_rs(&config, "// ignore-stage2").ignore);
}
#[test]
fn cross_compile() {
let mut config = config();
config.host = "x86_64-apple-darwin".to_owned();
config.target = "wasm32-unknown-unknown".to_owned();
assert!(parse_rs(&config, "// ignore-cross-compile").ignore);
config.target = config.host.clone();
assert!(!parse_rs(&config, "// ignore-cross-compile").ignore);
}
#[test]
fn debugger() {
let mut config = config();
config.debugger = None;
assert!(!parse_rs(&config, "// ignore-cdb").ignore);
config.debugger = Some(Debugger::Cdb);
assert!(parse_rs(&config, "// ignore-cdb").ignore);
config.debugger = Some(Debugger::Gdb);
assert!(parse_rs(&config, "// ignore-gdb").ignore);
config.debugger = Some(Debugger::Lldb);
assert!(parse_rs(&config, "// ignore-lldb").ignore);
}

View File

@ -70,7 +70,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
"",
"mode",
"which sort of compile tests to run",
"(compile-fail|run-fail|run-pass-valgrind|pretty|debug-info|incremental|mir-opt)",
"compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly",
)
.optopt(
"",
@ -115,7 +116,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
.optopt("", "ar", "path to an archiver", "PATH")
.optopt("", "linker", "path to a linker", "PATH")
.reqopt("", "llvm-components", "list of LLVM components built in", "LIST")
.reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS")
.optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH")
.optopt("", "nodejs", "the name of nodejs", "PATH")
.optopt("", "remote-test-client", "path to the remote test client", "PATH")
@ -239,7 +239,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
ar: matches.opt_str("ar").unwrap_or("ar".into()),
linker: matches.opt_str("linker"),
llvm_components: matches.opt_str("llvm-components").unwrap(),
llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
nodejs: matches.opt_str("nodejs"),
}
}

View File

@ -2651,7 +2651,6 @@ impl<'test> TestCx<'test> {
.env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path))
.env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path))
.env("LLVM_COMPONENTS", &self.config.llvm_components)
.env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags)
// We for sure don't want these tests to run in parallel, so make
// sure they don't have access to these vars if we run via `make`
// at the top level