Skip to content

Commit

Permalink
Modify MIR testing to require continuous lines
Browse files Browse the repository at this point in the history
Mir testing now requires that lines be continuous. To achive this,
instead of collecting the expected mir as a string, it is now wrapped in
an `ExpectedLine` enum, that is either `Elision` or `Text(T)` where `T:
AsRef<str>`. `Text` lines must be matched in order, unless separated by
`Elision` lines. Matches occur greedily, that is, an Elision will skip
as few lines as possible.

To add a new elision marker. Put a comment containing only "..." and
whitespace in any MIR testing block. Like so:

```
// fn write_42(_1: *mut i32) -> bool {
//     ...
//     bb0: {
//         Validate(Acquire, [_1: *mut i32]);
//         Validate(Release, [_1: *mut i32]);
//         ...
//         return;
//     }
// }
```

Right now, all input before the line right after `// START` is elided,
and all input after the line right before `// END` is also not tested.

Many tests need to be updated. That will follow in the next commit.

cc rust-lang#45153
  • Loading branch information
chrisvittal committed Oct 10, 2017
1 parent 692b94a commit a5e8a0e
Showing 1 changed file with 94 additions and 32 deletions.
126 changes: 94 additions & 32 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use std::collections::HashSet;
use std::env;
use std::ffi::OsString;
use std::fs::{self, File, create_dir_all};
use std::fmt;
use std::io::prelude::*;
use std::io::{self, BufReader};
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -2237,7 +2238,7 @@ actual:\n\
let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
let tests_text_str = String::from(tests_text);
let mut curr_test : Option<&str> = None;
let mut curr_test_contents = Vec::new();
let mut curr_test_contents = vec![ExpectedLine::Elision];
for l in tests_text_str.lines() {
debug!("line: {:?}", l);
if l.starts_with("// START ") {
Expand All @@ -2251,11 +2252,14 @@ actual:\n\
self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
curr_test = None;
curr_test_contents.clear();
curr_test_contents.push(ExpectedLine::Elision);
} else if l.is_empty() {
// ignore
} else if l.starts_with("//") && l.split_at("//".len()).1.trim() == "..." {
curr_test_contents.push(ExpectedLine::Elision)
} else if l.starts_with("// ") {
let (_, test_content) = l.split_at("// ".len());
curr_test_contents.push(test_content);
curr_test_contents.push(ExpectedLine::Text(test_content));
}
}
}
Expand All @@ -2273,7 +2277,7 @@ actual:\n\
}
}

fn compare_mir_test_output(&self, test_name: &str, expected_content: &[&str]) {
fn compare_mir_test_output(&self, test_name: &str, expected_content: &[ExpectedLine<&str>]) {
let mut output_file = PathBuf::new();
output_file.push(self.get_mir_dump_dir());
output_file.push(test_name);
Expand All @@ -2285,38 +2289,77 @@ actual:\n\
let mut dumped_string = String::new();
dumped_file.read_to_string(&mut dumped_string).unwrap();
let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty());
let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty());
let mut expected_lines = expected_content.iter().filter(|&l| {
if let &ExpectedLine::Text(l) = l {
!l.is_empty()
} else {
true
}
}).peekable();

// We expect each non-empty line from expected_content to appear
// in the dump in order, but there may be extra lines interleaved
while let Some(expected_line) = expected_lines.next() {
let compare = |expected_line, dumped_line| {
let e_norm = normalize_mir_line(expected_line);
if e_norm.is_empty() {
continue;
let d_norm = normalize_mir_line(dumped_line);
debug!("found: {:?}", d_norm);
debug!("expected: {:?}", e_norm);
e_norm == d_norm
};

let error = |expected_line, extra_msg| {
let normalize_all = dumped_string.lines()
.map(nocomment_mir_line)
.filter(|l| !l.is_empty())
.collect::<Vec<_>>()
.join("\n");
let f = |l: &ExpectedLine<_>| match l {
&ExpectedLine::Elision => "... (elided)".into(),
&ExpectedLine::Text(t) => t
};
let mut found = false;
while let Some(dumped_line) = dumped_lines.next() {
let d_norm = normalize_mir_line(dumped_line);
debug!("found: {:?}", d_norm);
debug!("expected: {:?}", e_norm);
if e_norm == d_norm {
found = true;
break;
};
}
if !found {
let normalize_all = dumped_string.lines()
.map(nocomment_mir_line)
.filter(|l| !l.is_empty())
.collect::<Vec<_>>()
.join("\n");
panic!("ran out of mir dump output to match against.\n\
Did not find expected line: {:?}\n\
Expected:\n{}\n\
Actual:\n{}",
expected_line,
expected_content.join("\n"),
normalize_all);
let expected_content = expected_content.iter()
.map(|l| f(l))
.collect::<Vec<_>>()
.join("\n");
panic!("Did not find expected line, error: {}\n\
Actual Line: {:?}\n\
Expected:\n{}\n\
Actual:\n{}",
extra_msg,
expected_line,
expected_content,
normalize_all);
};

// We expect each non-empty line to appear consecutively, non-consecutive lines
// must be separated by at least one Elision
while let Some(dumped_line) = dumped_lines.next() {
match expected_lines.next() {
Some(&ExpectedLine::Text(expected_line)) =>
if !compare(expected_line, dumped_line) {
error(expected_line,
format!("Mismatch in lines\nExpected Line: {:?}", dumped_line));
},
Some(&ExpectedLine::Elision) => {
// skip any number of elisions in a row.
while let Some(&&ExpectedLine::Elision) = expected_lines.peek() {
expected_lines.next();
}
if let Some(&ExpectedLine::Text(expected_line)) = expected_lines.next() {
let mut found = compare(expected_line, dumped_line);
if found {
continue;
}
while let Some(dumped_line) = dumped_lines.next() {
found = compare(expected_line, dumped_line);
if found {
break;
}
}
if !found {
error(expected_line, "ran out of mir dump to match against".into());
}
}
},
None => {},
}
}
}
Expand Down Expand Up @@ -2439,6 +2482,25 @@ enum TargetLocation {
ThisDirectory(PathBuf),
}

#[derive(Clone, PartialEq, Eq)]
enum ExpectedLine<T: AsRef<str>> {
Elision,
Text(T)
}

impl<T> fmt::Debug for ExpectedLine<T>
where
T: AsRef<str> + fmt::Debug
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
if let &ExpectedLine::Text(ref t) = self {
write!(formatter, "{:?}", t)
} else {
write!(formatter, "\"...\" (Elision)")
}
}
}

fn normalize_mir_line(line: &str) -> String {
nocomment_mir_line(line).replace(char::is_whitespace, "")
}
Expand Down

0 comments on commit a5e8a0e

Please sign in to comment.