Skip to content

Commit 225fa0f

Browse files
committed
dump outputs, diff on UI test failure
1 parent cb112dc commit 225fa0f

File tree

3 files changed

+98
-14
lines changed

3 files changed

+98
-14
lines changed

src/tools/compiletest/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub mod runtest;
5050
pub mod common;
5151
pub mod errors;
5252
mod raise_fd_limit;
53+
mod uidiff;
5354

5455
fn main() {
5556
#[cfg(cargobuild)]

src/tools/compiletest/src/runtest.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use header::TestProps;
1818
use header;
1919
use procsrv;
2020
use test::TestPaths;
21+
use uidiff;
2122
use util::logv;
2223

2324
use std::env;
@@ -2115,8 +2116,8 @@ actual:\n\
21152116
let normalized_stderr = self.normalize_output(&proc_res.stderr);
21162117

21172118
let mut errors = 0;
2118-
errors += self.compare_output("stdout", normalized_stdout.as_bytes(), &expected_stdout);
2119-
errors += self.compare_output("stderr", normalized_stderr.as_bytes(), &expected_stderr);
2119+
errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
2120+
errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
21202121

21212122
if errors > 0 {
21222123
println!("To update references, run this command from build directory:");
@@ -2127,15 +2128,18 @@ actual:\n\
21272128
self.config.src_base.display(),
21282129
self.config.build_base.display(),
21292130
relative_path_to_file.display());
2130-
self.fatal(&format!("{} errors occurred comparing output.", errors));
2131+
self.fatal_proc_rec(&format!("{} errors occurred comparing output.", errors),
2132+
&proc_res);
21312133
}
21322134
}
21332135

21342136
fn normalize_output(&self, output: &str) -> String {
21352137
let parent_dir = self.testpaths.file.parent().unwrap();
21362138
let parent_dir_str = parent_dir.display().to_string();
21372139
output.replace(&parent_dir_str, "$DIR")
2138-
.replace("\\", "/") // windows, you know.
2140+
.replace("\\", "/") // normalize for paths on windows
2141+
.replace("\r\n", "\n") // normalize for linebreaks on windows
2142+
.replace("\t", "\\t") // makes tabs visible
21392143
}
21402144

21412145
fn expected_output_path(&self, kind: &str) -> PathBuf {
@@ -2146,31 +2150,34 @@ actual:\n\
21462150
self.testpaths.file.with_extension(extension)
21472151
}
21482152

2149-
fn load_expected_output(&self, path: &Path) -> Vec<u8> {
2153+
fn load_expected_output(&self, path: &Path) -> String {
21502154
if !path.exists() {
2151-
return vec![];
2155+
return String::new();
21522156
}
21532157

2154-
let mut result = Vec::new();
2155-
match File::open(path).and_then(|mut f| f.read_to_end(&mut result)) {
2158+
let mut result = String::new();
2159+
match File::open(path).and_then(|mut f| f.read_to_string(&mut result)) {
21562160
Ok(_) => result,
21572161
Err(e) => {
21582162
self.fatal(&format!("failed to load expected output from `{}`: {}", path.display(), e))
21592163
}
21602164
}
21612165
}
21622166

2163-
fn compare_output(&self, kind: &str, actual: &[u8], expected: &[u8]) -> usize {
2164-
if self.config.verbose {
2165-
println!("normalized {}:\n{}\n", kind, str::from_utf8(actual).unwrap_or("not utf8"));
2166-
println!("expected {}:\n{}\n", kind, str::from_utf8(expected).unwrap_or("not utf8"));
2167-
}
2167+
fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
21682168
if actual == expected {
21692169
return 0;
21702170
}
21712171

2172+
println!("normalized {}:\n{}\n", kind, actual);
2173+
println!("expected {}:\n{}\n", kind, expected);
2174+
println!("diff of {}:\n", kind);
2175+
for line in uidiff::diff_lines(actual, expected) {
2176+
println!("{}", line);
2177+
}
2178+
21722179
let output_file = self.output_base_name().with_extension(kind);
2173-
match File::create(&output_file).and_then(|mut f| f.write_all(actual)) {
2180+
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
21742181
Ok(()) => { }
21752182
Err(e) => {
21762183
self.fatal(&format!("failed to write {} to `{}`: {}",

src/tools/compiletest/src/uidiff.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Code for checking whether the output of the compiler matches what is
12+
//! expected.
13+
14+
pub fn diff_lines(actual: &str, expected: &str) -> Vec<String> {
15+
// mega simplistic diff algorithm that just prints the things added/removed
16+
zip_all(actual.lines(), expected.lines()).enumerate().filter_map(|(i, (a,e))| {
17+
match (a, e) {
18+
(Some(a), Some(e)) => {
19+
if lines_match(e, a) {
20+
None
21+
} else {
22+
Some(format!("{:3} - |{}|\n + |{}|\n", i, e, a))
23+
}
24+
},
25+
(Some(a), None) => {
26+
Some(format!("{:3} -\n + |{}|\n", i, a))
27+
},
28+
(None, Some(e)) => {
29+
Some(format!("{:3} - |{}|\n +\n", i, e))
30+
},
31+
(None, None) => panic!("Cannot get here")
32+
}
33+
}).collect()
34+
}
35+
36+
fn lines_match(expected: &str, mut actual: &str) -> bool {
37+
for (i, part) in expected.split("[..]").enumerate() {
38+
match actual.find(part) {
39+
Some(j) => {
40+
if i == 0 && j != 0 {
41+
return false
42+
}
43+
actual = &actual[j + part.len()..];
44+
}
45+
None => {
46+
return false
47+
}
48+
}
49+
}
50+
actual.is_empty() || expected.ends_with("[..]")
51+
}
52+
53+
struct ZipAll<I1: Iterator, I2: Iterator> {
54+
first: I1,
55+
second: I2,
56+
}
57+
58+
impl<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>> Iterator for ZipAll<I1, I2> {
59+
type Item = (Option<T>, Option<T>);
60+
fn next(&mut self) -> Option<(Option<T>, Option<T>)> {
61+
let first = self.first.next();
62+
let second = self.second.next();
63+
64+
match (first, second) {
65+
(None, None) => None,
66+
(a, b) => Some((a, b))
67+
}
68+
}
69+
}
70+
71+
fn zip_all<T, I1: Iterator<Item=T>, I2: Iterator<Item=T>>(a: I1, b: I2) -> ZipAll<I1, I2> {
72+
ZipAll {
73+
first: a,
74+
second: b,
75+
}
76+
}

0 commit comments

Comments
 (0)