From cb112dc8cfe105b9eec2a3e1b59dd66eca386ee6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 May 2016 12:28:52 -0700 Subject: add UI testing framework --- src/tools/compiletest/src/common.rs | 3 ++ src/tools/compiletest/src/runtest.rs | 88 +++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) (limited to 'src/tools/compiletest') diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index ae8beb83530..5ec62e06e37 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -28,6 +28,7 @@ pub enum Mode { CodegenUnits, Incremental, RunMake, + Ui, } impl FromStr for Mode { @@ -47,6 +48,7 @@ impl FromStr for Mode { "codegen-units" => Ok(CodegenUnits), "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), + "ui" => Ok(Ui), _ => Err(()), } } @@ -68,6 +70,7 @@ impl fmt::Display for Mode { CodegenUnits => "codegen-units", Incremental => "incremental", RunMake => "run-make", + Ui => "ui", }, f) } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index aa1b9d2bafb..9e4f331d16e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -11,7 +11,7 @@ use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits}; -use common::{Incremental, RunMake}; +use common::{Incremental, RunMake, Ui}; use errors::{self, ErrorKind, Error}; use json; use header::TestProps; @@ -29,6 +29,7 @@ use std::io::prelude::*; use std::net::TcpStream; use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; +use std::str; pub fn run(config: Config, testpaths: &TestPaths) { match &*config.target { @@ -118,6 +119,7 @@ impl<'test> TestCx<'test> { CodegenUnits => self.run_codegen_units_test(), Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), + Ui => self.run_ui_test(), } } @@ -1314,6 +1316,7 @@ actual:\n\ Codegen | Rustdoc | RunMake | + Ui | CodegenUnits => { // do not use JSON output } @@ -2096,6 +2099,89 @@ actual:\n\ } fs::remove_dir(path) } + + fn run_ui_test(&self) { + println!("ui: {}", self.testpaths.file.display()); + + let proc_res = self.compile_test(); + + let expected_stderr_path = self.expected_output_path("stderr"); + let expected_stderr = self.load_expected_output(&expected_stderr_path); + + let expected_stdout_path = self.expected_output_path("stdout"); + let expected_stdout = self.load_expected_output(&expected_stdout_path); + + let normalized_stdout = self.normalize_output(&proc_res.stdout); + let normalized_stderr = self.normalize_output(&proc_res.stderr); + + let mut errors = 0; + errors += self.compare_output("stdout", normalized_stdout.as_bytes(), &expected_stdout); + errors += self.compare_output("stderr", normalized_stderr.as_bytes(), &expected_stderr); + + if errors > 0 { + println!("To update references, run this command from build directory:"); + let relative_path_to_file = + self.testpaths.relative_dir + .join(self.testpaths.file.file_name().unwrap()); + println!("{}/update-references.sh '{}' '{}'", + self.config.src_base.display(), + self.config.build_base.display(), + relative_path_to_file.display()); + self.fatal(&format!("{} errors occurred comparing output.", errors)); + } + } + + fn normalize_output(&self, output: &str) -> String { + let parent_dir = self.testpaths.file.parent().unwrap(); + let parent_dir_str = parent_dir.display().to_string(); + output.replace(&parent_dir_str, "$DIR") + .replace("\\", "/") // windows, you know. + } + + fn expected_output_path(&self, kind: &str) -> PathBuf { + let extension = match self.revision { + Some(r) => format!("{}.{}", r, kind), + None => kind.to_string(), + }; + self.testpaths.file.with_extension(extension) + } + + fn load_expected_output(&self, path: &Path) -> Vec { + if !path.exists() { + return vec![]; + } + + let mut result = Vec::new(); + match File::open(path).and_then(|mut f| f.read_to_end(&mut result)) { + Ok(_) => result, + Err(e) => { + self.fatal(&format!("failed to load expected output from `{}`: {}", path.display(), e)) + } + } + } + + fn compare_output(&self, kind: &str, actual: &[u8], expected: &[u8]) -> usize { + if self.config.verbose { + println!("normalized {}:\n{}\n", kind, str::from_utf8(actual).unwrap_or("not utf8")); + println!("expected {}:\n{}\n", kind, str::from_utf8(expected).unwrap_or("not utf8")); + } + if actual == expected { + return 0; + } + + let output_file = self.output_base_name().with_extension(kind); + match File::create(&output_file).and_then(|mut f| f.write_all(actual)) { + 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 + } } struct ProcArgs { -- cgit 1.4.1-3-g733a5