dump outputs, diff on UI test failure
This commit is contained in:
parent
cb112dc8cf
commit
225fa0faff
3 changed files with 98 additions and 14 deletions
|
@ -50,6 +50,7 @@ pub mod runtest;
|
|||
pub mod common;
|
||||
pub mod errors;
|
||||
mod raise_fd_limit;
|
||||
mod uidiff;
|
||||
|
||||
fn main() {
|
||||
#[cfg(cargobuild)]
|
||||
|
|
|
@ -18,6 +18,7 @@ use header::TestProps;
|
|||
use header;
|
||||
use procsrv;
|
||||
use test::TestPaths;
|
||||
use uidiff;
|
||||
use util::logv;
|
||||
|
||||
use std::env;
|
||||
|
@ -2115,8 +2116,8 @@ actual:\n\
|
|||
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);
|
||||
errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
|
||||
errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
|
||||
|
||||
if errors > 0 {
|
||||
println!("To update references, run this command from build directory:");
|
||||
|
@ -2127,7 +2128,8 @@ actual:\n\
|
|||
self.config.src_base.display(),
|
||||
self.config.build_base.display(),
|
||||
relative_path_to_file.display());
|
||||
self.fatal(&format!("{} errors occurred comparing output.", errors));
|
||||
self.fatal_proc_rec(&format!("{} errors occurred comparing output.", errors),
|
||||
&proc_res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2135,7 +2137,9 @@ actual:\n\
|
|||
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.
|
||||
.replace("\\", "/") // normalize for paths on windows
|
||||
.replace("\r\n", "\n") // normalize for linebreaks on windows
|
||||
.replace("\t", "\\t") // makes tabs visible
|
||||
}
|
||||
|
||||
fn expected_output_path(&self, kind: &str) -> PathBuf {
|
||||
|
@ -2146,13 +2150,13 @@ actual:\n\
|
|||
self.testpaths.file.with_extension(extension)
|
||||
}
|
||||
|
||||
fn load_expected_output(&self, path: &Path) -> Vec<u8> {
|
||||
fn load_expected_output(&self, path: &Path) -> String {
|
||||
if !path.exists() {
|
||||
return vec![];
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let mut result = Vec::new();
|
||||
match File::open(path).and_then(|mut f| f.read_to_end(&mut result)) {
|
||||
let mut result = String::new();
|
||||
match File::open(path).and_then(|mut f| f.read_to_string(&mut result)) {
|
||||
Ok(_) => result,
|
||||
Err(e) => {
|
||||
self.fatal(&format!("failed to load expected output from `{}`: {}", path.display(), e))
|
||||
|
@ -2160,17 +2164,20 @@ actual:\n\
|
|||
}
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
|
||||
if actual == expected {
|
||||
return 0;
|
||||
}
|
||||
|
||||
println!("normalized {}:\n{}\n", kind, actual);
|
||||
println!("expected {}:\n{}\n", kind, expected);
|
||||
println!("diff of {}:\n", kind);
|
||||
for line in uidiff::diff_lines(actual, expected) {
|
||||
println!("{}", line);
|
||||
}
|
||||
|
||||
let output_file = self.output_base_name().with_extension(kind);
|
||||
match File::create(&output_file).and_then(|mut f| f.write_all(actual)) {
|
||||
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 `{}`: {}",
|
||||
|
|
76
src/tools/compiletest/src/uidiff.rs
Normal file
76
src/tools/compiletest/src/uidiff.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2012-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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Code for checking whether the output of the compiler matches what is
|
||||
//! expected.
|
||||
|
||||
pub fn diff_lines(actual: &str, expected: &str) -> Vec<String> {
|
||||
// mega simplistic diff algorithm that just prints the things added/removed
|
||||
zip_all(actual.lines(), expected.lines()).enumerate().filter_map(|(i, (a,e))| {
|
||||
match (a, e) {
|
||||
(Some(a), Some(e)) => {
|
||||
if lines_match(e, a) {
|
||||
None
|
||||
} else {
|
||||
Some(format!("{:3} - |{}|\n + |{}|\n", i, e, a))
|
||||
}
|
||||
},
|
||||
(Some(a), None) => {
|
||||
Some(format!("{:3} -\n + |{}|\n", i, a))
|
||||
},
|
||||
(None, Some(e)) => {
|
||||
Some(format!("{:3} - |{}|\n +\n", i, e))
|
||||
},
|
||||
(None, None) => panic!("Cannot get here")
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn lines_match(expected: &str, mut actual: &str) -> bool {
|
||||
for (i, part) in expected.split("[..]").enumerate() {
|
||||
match actual.find(part) {
|
||||
Some(j) => {
|
||||
if i == 0 && j != 0 {
|
||||
return false
|
||||
}
|
||||
actual = &actual[j + part.len()..];
|
||||
}
|
||||
None => {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
actual.is_empty() || expected.ends_with("[..]")
|
||||
}
|
||||
|
||||
struct ZipAll<I1: Iterator, I2: Iterator> {
|
||||
first: I1,
|
||||
second: I2,
|
||||
}
|
||||
|
||||
impl<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>> Iterator for ZipAll<I1, I2> {
|
||||
type Item = (Option<T>, Option<T>);
|
||||
fn next(&mut self) -> Option<(Option<T>, Option<T>)> {
|
||||
let first = self.first.next();
|
||||
let second = self.second.next();
|
||||
|
||||
match (first, second) {
|
||||
(None, None) => None,
|
||||
(a, b) => Some((a, b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn zip_all<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>>(a: I1, b: I2) -> ZipAll<I1, I2> {
|
||||
ZipAll {
|
||||
first: a,
|
||||
second: b,
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue