Skip to content

Commit 48548c9

Browse files
Rollup merge of #89477 - Nicholas-Baron:compute_diff_rs, r=Mark-Simulacrum
Move items related to computing diffs to a separate file Work towards #89475.
2 parents ab276b8 + 3760c91 commit 48548c9

File tree

3 files changed

+170
-142
lines changed

3 files changed

+170
-142
lines changed
+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use std::collections::VecDeque;
2+
use std::fs::{File, FileType};
3+
use std::path::Path;
4+
5+
#[derive(Debug, PartialEq)]
6+
pub enum DiffLine {
7+
Context(String),
8+
Expected(String),
9+
Resulting(String),
10+
}
11+
12+
#[derive(Debug, PartialEq)]
13+
pub struct Mismatch {
14+
pub line_number: u32,
15+
pub lines: Vec<DiffLine>,
16+
}
17+
18+
impl Mismatch {
19+
fn new(line_number: u32) -> Mismatch {
20+
Mismatch { line_number, lines: Vec::new() }
21+
}
22+
}
23+
24+
// Produces a diff between the expected output and actual output.
25+
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
26+
let mut line_number = 1;
27+
let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
28+
let mut lines_since_mismatch = context_size + 1;
29+
let mut results = Vec::new();
30+
let mut mismatch = Mismatch::new(0);
31+
32+
for result in diff::lines(expected, actual) {
33+
match result {
34+
diff::Result::Left(str) => {
35+
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
36+
results.push(mismatch);
37+
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
38+
}
39+
40+
while let Some(line) = context_queue.pop_front() {
41+
mismatch.lines.push(DiffLine::Context(line.to_owned()));
42+
}
43+
44+
mismatch.lines.push(DiffLine::Expected(str.to_owned()));
45+
line_number += 1;
46+
lines_since_mismatch = 0;
47+
}
48+
diff::Result::Right(str) => {
49+
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
50+
results.push(mismatch);
51+
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
52+
}
53+
54+
while let Some(line) = context_queue.pop_front() {
55+
mismatch.lines.push(DiffLine::Context(line.to_owned()));
56+
}
57+
58+
mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
59+
lines_since_mismatch = 0;
60+
}
61+
diff::Result::Both(str, _) => {
62+
if context_queue.len() >= context_size {
63+
let _ = context_queue.pop_front();
64+
}
65+
66+
if lines_since_mismatch < context_size {
67+
mismatch.lines.push(DiffLine::Context(str.to_owned()));
68+
} else if context_size > 0 {
69+
context_queue.push_back(str);
70+
}
71+
72+
line_number += 1;
73+
lines_since_mismatch += 1;
74+
}
75+
}
76+
}
77+
78+
results.push(mismatch);
79+
results.remove(0);
80+
81+
results
82+
}
83+
84+
pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> String {
85+
use std::fmt::Write;
86+
let mut output = String::new();
87+
let diff_results = make_diff(expected, actual, context_size);
88+
for result in diff_results {
89+
let mut line_number = result.line_number;
90+
for line in result.lines {
91+
match line {
92+
DiffLine::Expected(e) => {
93+
writeln!(output, "-\t{}", e).unwrap();
94+
line_number += 1;
95+
}
96+
DiffLine::Context(c) => {
97+
writeln!(output, "{}\t{}", line_number, c).unwrap();
98+
line_number += 1;
99+
}
100+
DiffLine::Resulting(r) => {
101+
writeln!(output, "+\t{}", r).unwrap();
102+
}
103+
}
104+
}
105+
writeln!(output).unwrap();
106+
}
107+
output
108+
}
109+
110+
/// Filters based on filetype and extension whether to diff a file.
111+
///
112+
/// Returns whether any data was actually written.
113+
pub(crate) fn write_filtered_diff<Filter>(
114+
diff_filename: &str,
115+
out_dir: &Path,
116+
compare_dir: &Path,
117+
verbose: bool,
118+
filter: Filter,
119+
) -> bool
120+
where
121+
Filter: Fn(FileType, Option<&str>) -> bool,
122+
{
123+
use std::io::{Read, Write};
124+
let mut diff_output = File::create(diff_filename).unwrap();
125+
let mut wrote_data = false;
126+
for entry in walkdir::WalkDir::new(out_dir) {
127+
let entry = entry.expect("failed to read file");
128+
let extension = entry.path().extension().and_then(|p| p.to_str());
129+
if filter(entry.file_type(), extension) {
130+
let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap());
131+
let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
132+
let actual_path = entry.path();
133+
let actual = std::fs::read(&actual_path).unwrap();
134+
let diff = unified_diff::diff(
135+
&expected,
136+
&expected_path.to_string_lossy(),
137+
&actual,
138+
&actual_path.to_string_lossy(),
139+
3,
140+
);
141+
wrote_data |= !diff.is_empty();
142+
diff_output.write_all(&diff).unwrap();
143+
}
144+
}
145+
146+
if !wrote_data {
147+
println!("note: diff is identical to nightly rustdoc");
148+
assert!(diff_output.metadata().unwrap().len() == 0);
149+
return false;
150+
} else if verbose {
151+
eprintln!("printing diff:");
152+
let mut buf = Vec::new();
153+
diff_output.read_to_end(&mut buf).unwrap();
154+
std::io::stderr().lock().write_all(&mut buf).unwrap();
155+
}
156+
true
157+
}

src/tools/compiletest/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use self::header::{make_test_description, EarlyProps};
2828
mod tests;
2929

3030
pub mod common;
31+
pub mod compute_diff;
3132
pub mod errors;
3233
pub mod header;
3334
mod json;

src/tools/compiletest/src/runtest.rs

+12-142
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::common::{CompareMode, FailMode, PassMode};
88
use crate::common::{Config, TestPaths};
99
use crate::common::{Pretty, RunPassValgrind};
1010
use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
11+
use crate::compute_diff::{write_diff, write_filtered_diff};
1112
use crate::errors::{self, Error, ErrorKind};
1213
use crate::header::TestProps;
1314
use crate::json;
@@ -18,7 +19,7 @@ use regex::{Captures, Regex};
1819
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
1920

2021
use std::collections::hash_map::DefaultHasher;
21-
use std::collections::{HashMap, HashSet, VecDeque};
22+
use std::collections::{HashMap, HashSet};
2223
use std::env;
2324
use std::ffi::{OsStr, OsString};
2425
use std::fs::{self, create_dir_all, File, OpenOptions};
@@ -100,111 +101,6 @@ pub fn get_lib_name(lib: &str, dylib: bool) -> String {
100101
}
101102
}
102103

103-
#[derive(Debug, PartialEq)]
104-
pub enum DiffLine {
105-
Context(String),
106-
Expected(String),
107-
Resulting(String),
108-
}
109-
110-
#[derive(Debug, PartialEq)]
111-
pub struct Mismatch {
112-
pub line_number: u32,
113-
pub lines: Vec<DiffLine>,
114-
}
115-
116-
impl Mismatch {
117-
fn new(line_number: u32) -> Mismatch {
118-
Mismatch { line_number, lines: Vec::new() }
119-
}
120-
}
121-
122-
// Produces a diff between the expected output and actual output.
123-
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
124-
let mut line_number = 1;
125-
let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
126-
let mut lines_since_mismatch = context_size + 1;
127-
let mut results = Vec::new();
128-
let mut mismatch = Mismatch::new(0);
129-
130-
for result in diff::lines(expected, actual) {
131-
match result {
132-
diff::Result::Left(str) => {
133-
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
134-
results.push(mismatch);
135-
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
136-
}
137-
138-
while let Some(line) = context_queue.pop_front() {
139-
mismatch.lines.push(DiffLine::Context(line.to_owned()));
140-
}
141-
142-
mismatch.lines.push(DiffLine::Expected(str.to_owned()));
143-
line_number += 1;
144-
lines_since_mismatch = 0;
145-
}
146-
diff::Result::Right(str) => {
147-
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
148-
results.push(mismatch);
149-
mismatch = Mismatch::new(line_number - context_queue.len() as u32);
150-
}
151-
152-
while let Some(line) = context_queue.pop_front() {
153-
mismatch.lines.push(DiffLine::Context(line.to_owned()));
154-
}
155-
156-
mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
157-
lines_since_mismatch = 0;
158-
}
159-
diff::Result::Both(str, _) => {
160-
if context_queue.len() >= context_size {
161-
let _ = context_queue.pop_front();
162-
}
163-
164-
if lines_since_mismatch < context_size {
165-
mismatch.lines.push(DiffLine::Context(str.to_owned()));
166-
} else if context_size > 0 {
167-
context_queue.push_back(str);
168-
}
169-
170-
line_number += 1;
171-
lines_since_mismatch += 1;
172-
}
173-
}
174-
}
175-
176-
results.push(mismatch);
177-
results.remove(0);
178-
179-
results
180-
}
181-
182-
fn write_diff(expected: &str, actual: &str, context_size: usize) -> String {
183-
use std::fmt::Write;
184-
let mut output = String::new();
185-
let diff_results = make_diff(expected, actual, context_size);
186-
for result in diff_results {
187-
let mut line_number = result.line_number;
188-
for line in result.lines {
189-
match line {
190-
DiffLine::Expected(e) => {
191-
writeln!(output, "-\t{}", e).unwrap();
192-
line_number += 1;
193-
}
194-
DiffLine::Context(c) => {
195-
writeln!(output, "{}\t{}", line_number, c).unwrap();
196-
line_number += 1;
197-
}
198-
DiffLine::Resulting(r) => {
199-
writeln!(output, "+\t{}", r).unwrap();
200-
}
201-
}
202-
}
203-
writeln!(output).unwrap();
204-
}
205-
output
206-
}
207-
208104
pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
209105
match &*config.target {
210106
"arm-linux-androideabi"
@@ -2507,43 +2403,17 @@ impl<'test> TestCx<'test> {
25072403

25082404
let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id());
25092405

2510-
{
2511-
let mut diff_output = File::create(&diff_filename).unwrap();
2512-
let mut wrote_data = false;
2513-
for entry in walkdir::WalkDir::new(out_dir) {
2514-
let entry = entry.expect("failed to read file");
2515-
let extension = entry.path().extension().and_then(|p| p.to_str());
2516-
if entry.file_type().is_file()
2406+
if !write_filtered_diff(
2407+
&diff_filename,
2408+
out_dir,
2409+
&compare_dir,
2410+
self.config.verbose,
2411+
|file_type, extension| {
2412+
file_type.is_file()
25172413
&& (extension == Some("html".into()) || extension == Some("js".into()))
2518-
{
2519-
let expected_path =
2520-
compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap());
2521-
let expected =
2522-
if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
2523-
let actual_path = entry.path();
2524-
let actual = std::fs::read(&actual_path).unwrap();
2525-
let diff = unified_diff::diff(
2526-
&expected,
2527-
&expected_path.to_string_lossy(),
2528-
&actual,
2529-
&actual_path.to_string_lossy(),
2530-
3,
2531-
);
2532-
wrote_data |= !diff.is_empty();
2533-
diff_output.write_all(&diff).unwrap();
2534-
}
2535-
}
2536-
2537-
if !wrote_data {
2538-
println!("note: diff is identical to nightly rustdoc");
2539-
assert!(diff_output.metadata().unwrap().len() == 0);
2540-
return;
2541-
} else if self.config.verbose {
2542-
eprintln!("printing diff:");
2543-
let mut buf = Vec::new();
2544-
diff_output.read_to_end(&mut buf).unwrap();
2545-
std::io::stderr().lock().write_all(&mut buf).unwrap();
2546-
}
2414+
},
2415+
) {
2416+
return;
25472417
}
25482418

25492419
match self.config.color {

0 commit comments

Comments
 (0)