Refactor diff handling in tests
This splits the generation and display of mismatches. Mismatches now include a few lines of context. Finally, diffs are now coloured.
This commit is contained in:
parent
b59ab9c13f
commit
adeafb3e45
3 changed files with 124 additions and 23 deletions
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -6,6 +6,7 @@ dependencies = [
|
||||||
"regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strings 0.0.1 (git+https://github.com/nrc/strings.rs.git)",
|
"strings 0.0.1 (git+https://github.com/nrc/strings.rs.git)",
|
||||||
|
"term 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"toml 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"toml 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -22,6 +23,15 @@ name = "diff"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
@ -60,6 +70,15 @@ name = "strings"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
source = "git+https://github.com/nrc/strings.rs.git#6d748148fbe3bf2d9e5ac2ede65ac503d7491a4f"
|
source = "git+https://github.com/nrc/strings.rs.git#6d748148fbe3bf2d9e5ac2ede65ac503d7491a4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "term"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.1.21"
|
version = "0.1.21"
|
||||||
|
@ -68,3 +87,13 @@ dependencies = [
|
||||||
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-build"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,4 @@ rustc-serialize = "0.3.14"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
diff = "0.1.0"
|
diff = "0.1.0"
|
||||||
regex = "0.1"
|
regex = "0.1"
|
||||||
|
term = "0.2"
|
||||||
|
|
117
tests/system.rs
117
tests/system.rs
|
@ -13,14 +13,17 @@
|
||||||
extern crate rustfmt;
|
extern crate rustfmt;
|
||||||
extern crate diff;
|
extern crate diff;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
extern crate term;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{VecDeque, HashMap};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read, BufRead, BufReader};
|
use std::io::{self, Read, BufRead, BufReader};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use rustfmt::*;
|
use rustfmt::*;
|
||||||
use rustfmt::config::Config;
|
use rustfmt::config::Config;
|
||||||
|
|
||||||
|
static DIFF_CONTEXT_SIZE: usize = 3;
|
||||||
|
|
||||||
fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
|
fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
|
||||||
let path = dir_entry.ok().expect("Couldn't get DirEntry.").path();
|
let path = dir_entry.ok().expect("Couldn't get DirEntry.").path();
|
||||||
|
|
||||||
|
@ -87,16 +90,40 @@ fn check_files<I>(files: I) -> (u32, u32)
|
||||||
(count, fails)
|
(count, fails)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_mismatches(result: HashMap<String, String>) {
|
fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
|
||||||
for (_, fmt_text) in result {
|
let mut t = term::stdout().unwrap();
|
||||||
println!("{}", fmt_text);
|
|
||||||
|
for (file_name, diff) in result {
|
||||||
|
for mismatch in diff {
|
||||||
|
t.fg(term::color::BRIGHT_WHITE).unwrap();
|
||||||
|
writeln!(t, "\nMismatch at {}:{}:", file_name, mismatch.line_number).unwrap();
|
||||||
|
|
||||||
|
for line in mismatch.lines {
|
||||||
|
match line {
|
||||||
|
DiffLine::Context(ref str) => {
|
||||||
|
t.fg(term::color::WHITE).unwrap();
|
||||||
|
writeln!(t, " {}⏎", str).unwrap();
|
||||||
|
}
|
||||||
|
DiffLine::Expected(ref str) => {
|
||||||
|
t.fg(term::color::GREEN).unwrap();
|
||||||
|
writeln!(t, "+{}⏎", str).unwrap();
|
||||||
|
}
|
||||||
|
DiffLine::Resulting(ref str) => {
|
||||||
|
t.fg(term::color::RED).unwrap();
|
||||||
|
writeln!(t, "-{}⏎", str).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert!(t.reset().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ick, just needed to get a &'static to handle_result.
|
// Ick, just needed to get a &'static to handle_result.
|
||||||
static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;
|
static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;
|
||||||
|
|
||||||
pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, String>> {
|
pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, Vec<Mismatch>>> {
|
||||||
let sig_comments = read_significant_comments(&filename);
|
let sig_comments = read_significant_comments(&filename);
|
||||||
let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));
|
let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));
|
||||||
let args = vec!["rustfmt".to_owned(), filename];
|
let args = vec!["rustfmt".to_owned(), filename];
|
||||||
|
@ -179,10 +206,11 @@ fn handle_result(result: HashMap<String, String>) {
|
||||||
// TODO: speedup by running through bytes iterator
|
// TODO: speedup by running through bytes iterator
|
||||||
f.read_to_string(&mut text).ok().expect("Failed reading target.");
|
f.read_to_string(&mut text).ok().expect("Failed reading target.");
|
||||||
if fmt_text != text {
|
if fmt_text != text {
|
||||||
let diff_str = make_diff(&file_name, &fmt_text, &text);
|
let diff = make_diff(&fmt_text, &text, DIFF_CONTEXT_SIZE);
|
||||||
failures.insert(file_name, diff_str);
|
failures.insert(file_name, diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !failures.is_empty() {
|
if !failures.is_empty() {
|
||||||
panic!(failures);
|
panic!(failures);
|
||||||
}
|
}
|
||||||
|
@ -199,36 +227,79 @@ fn get_target(file_name: &str, target: Option<&str>) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produces a diff string between the expected output and actual output of
|
pub enum DiffLine {
|
||||||
// rustfmt on a given file
|
Context(String),
|
||||||
fn make_diff(file_name: &str, expected: &str, actual: &str) -> String {
|
Expected(String),
|
||||||
|
Resulting(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mismatch {
|
||||||
|
line_number: u32,
|
||||||
|
pub lines: Vec<DiffLine>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mismatch {
|
||||||
|
fn new(line_number: u32) -> Mismatch {
|
||||||
|
Mismatch { line_number: line_number, lines: Vec::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produces a diff between the expected output and actual output of rustfmt.
|
||||||
|
fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
|
||||||
let mut line_number = 1;
|
let mut line_number = 1;
|
||||||
let mut prev_both = true;
|
let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
|
||||||
let mut text = String::new();
|
let mut lines_since_mismatch = context_size + 1;
|
||||||
|
let mut results = Vec::new();
|
||||||
|
let mut mismatch = Mismatch::new(0);
|
||||||
|
|
||||||
for result in diff::lines(expected, actual) {
|
for result in diff::lines(expected, actual) {
|
||||||
match result {
|
match result {
|
||||||
diff::Result::Left(str) => {
|
diff::Result::Left(str) => {
|
||||||
if prev_both {
|
if lines_since_mismatch >= context_size {
|
||||||
text.push_str(&format!("Mismatch @ {}:{}\n", file_name, line_number));
|
results.push(mismatch);
|
||||||
|
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
|
||||||
}
|
}
|
||||||
text.push_str(&format!("-{}⏎\n", str));
|
|
||||||
prev_both = false;
|
while let Some(line) = context_queue.pop_front() {
|
||||||
|
mismatch.lines.push(DiffLine::Context(line.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
|
||||||
|
lines_since_mismatch = 0;
|
||||||
}
|
}
|
||||||
diff::Result::Right(str) => {
|
diff::Result::Right(str) => {
|
||||||
if prev_both {
|
if lines_since_mismatch >= context_size {
|
||||||
text.push_str(&format!("Mismatch @ {}:{}\n", file_name, line_number));
|
results.push(mismatch);
|
||||||
|
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
|
||||||
}
|
}
|
||||||
text.push_str(&format!("+{}⏎\n", str));
|
|
||||||
prev_both = false;
|
while let Some(line) = context_queue.pop_front() {
|
||||||
|
mismatch.lines.push(DiffLine::Context(line.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
mismatch.lines.push(DiffLine::Expected(str.to_owned()));
|
||||||
line_number += 1;
|
line_number += 1;
|
||||||
|
lines_since_mismatch = 0;
|
||||||
}
|
}
|
||||||
diff::Result::Both(..) => {
|
diff::Result::Both(str, _) => {
|
||||||
|
if context_queue.len() >= context_size {
|
||||||
|
let _ = context_queue.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if lines_since_mismatch < context_size {
|
||||||
|
mismatch.lines.push(DiffLine::Context(str.to_owned()));
|
||||||
|
} else {
|
||||||
|
context_queue.push_back(str);
|
||||||
|
}
|
||||||
|
|
||||||
line_number += 1;
|
line_number += 1;
|
||||||
prev_both = true;
|
lines_since_mismatch += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text
|
results.push(mismatch);
|
||||||
|
results.remove(0);
|
||||||
|
|
||||||
|
results
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue