Skip to content

Commit 459be3e

Browse files
committed
compiletest: add a new diff for compare-out-by-lines tests.
Previously, when comparing output by lines, only the actual diff was shown. This is unhelpful since we expect lines to be shuffled around. With this new print, we can see the exact lines that are missing or have appeared without the noise of the moved around lines.
1 parent 14196db commit 459be3e

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/tools/compiletest/src/runtest.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::directives::{AuxCrate, TestProps};
2222
use crate::errors::{Error, ErrorKind, load_errors};
2323
use crate::output_capture::ConsoleOut;
2424
use crate::read2::{Truncated, read2_abbreviated};
25-
use crate::runtest::compute_diff::{DiffLine, make_diff, write_diff};
25+
use crate::runtest::compute_diff::{DiffLine, diff_by_lines, make_diff, write_diff};
2626
use crate::util::{Utf8PathBufExt, add_dylib_path, static_regex};
2727
use crate::{json, stamp_file_path};
2828

@@ -2794,6 +2794,7 @@ impl<'test> TestCx<'test> {
27942794
expected,
27952795
actual,
27962796
actual_unnormalized,
2797+
compare_output_by_lines || compare_output_by_lines_subset,
27972798
);
27982799
}
27992800
} else {
@@ -2831,6 +2832,7 @@ impl<'test> TestCx<'test> {
28312832
expected: &str,
28322833
actual: &str,
28332834
actual_unnormalized: &str,
2835+
show_diff_by_lines: bool,
28342836
) {
28352837
writeln!(self.stderr, "diff of {stream}:\n");
28362838
if let Some(diff_command) = self.config.diff_command.as_deref() {
@@ -2897,6 +2899,10 @@ impl<'test> TestCx<'test> {
28972899
write_diff(&mismatches_unnormalized, &mismatches_normalized, 0)
28982900
);
28992901
}
2902+
2903+
if show_diff_by_lines {
2904+
write!(self.stderr, "{}", diff_by_lines(expected, actual));
2905+
}
29002906
}
29012907

29022908
fn check_and_prune_duplicate_outputs(

src/tools/compiletest/src/runtest/compute_diff.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,54 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S
104104
}
105105
output
106106
}
107+
108+
pub(crate) fn diff_by_lines(expected: &str, actual: &str) -> String {
109+
use std::collections::HashMap;
110+
use std::fmt::Write;
111+
let mut output = String::new();
112+
let mut expected_counts: HashMap<&str, usize> = HashMap::new();
113+
let mut actual_counts: HashMap<&str, usize> = HashMap::new();
114+
115+
for line in expected.lines() {
116+
*expected_counts.entry(line).or_insert(0) += 1;
117+
}
118+
for line in actual.lines() {
119+
*actual_counts.entry(line).or_insert(0) += 1;
120+
}
121+
122+
fn write_expected_only_lines(
123+
output: &mut String,
124+
expected_lines: &HashMap<&str, usize>,
125+
actual_lines: &HashMap<&str, usize>,
126+
) {
127+
let mut expected_only: Vec<(&str, usize)> = expected_lines
128+
.iter()
129+
.filter_map(|(&line, &expected_count)| {
130+
let actual_count = actual_lines.get(line).copied().unwrap_or(0);
131+
if expected_count > actual_count {
132+
Some((line, expected_count - actual_count))
133+
} else {
134+
None
135+
}
136+
})
137+
.collect();
138+
expected_only.sort_by(|(a, _), (b, _)| a.cmp(b));
139+
140+
if expected_only.is_empty() {
141+
writeln!(output, "(no lines found)").unwrap();
142+
} else {
143+
for (line, diff) in expected_only {
144+
for _ in 0..diff {
145+
writeln!(output, "{line}").unwrap();
146+
}
147+
}
148+
}
149+
}
150+
151+
writeln!(output, "Compare output by lines enabled, diff by lines:").unwrap();
152+
writeln!(output, "Expected contains these lines that are not in actual:").unwrap();
153+
write_expected_only_lines(&mut output, &expected_counts, &actual_counts);
154+
writeln!(output, "Actual contains these lines that are not in expected:").unwrap();
155+
write_expected_only_lines(&mut output, &actual_counts, &expected_counts);
156+
output
157+
}

0 commit comments

Comments
 (0)