Skip to content

Commit 776baf9

Browse files
refactor: update json emitter to better handle errors (#3953)
1 parent 34263cd commit 776baf9

File tree

3 files changed

+80
-93
lines changed

3 files changed

+80
-93
lines changed

Diff for: src/emitter/json.rs

+78-91
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use std::io::{self, Write};
66

77
#[derive(Debug, Default)]
88
pub(crate) struct JsonEmitter {
9-
num_files: u32,
9+
mismatched_files: Vec<MismatchedFile>,
1010
}
1111

12-
#[derive(Debug, Default, Serialize)]
12+
#[derive(Debug, Default, PartialEq, Serialize)]
1313
struct MismatchedBlock {
1414
original_begin_line: u32,
1515
original_end_line: u32,
@@ -19,26 +19,20 @@ struct MismatchedBlock {
1919
expected: String,
2020
}
2121

22-
#[derive(Debug, Default, Serialize)]
22+
#[derive(Debug, Default, PartialEq, Serialize)]
2323
struct MismatchedFile {
2424
name: String,
2525
mismatches: Vec<MismatchedBlock>,
2626
}
2727

2828
impl Emitter for JsonEmitter {
29-
fn emit_header(&self, output: &mut dyn Write) -> Result<(), io::Error> {
30-
write!(output, "[")?;
31-
Ok(())
32-
}
33-
3429
fn emit_footer(&self, output: &mut dyn Write) -> Result<(), io::Error> {
35-
write!(output, "]")?;
36-
Ok(())
30+
writeln!(output, "{}", &to_json_string(&self.mismatched_files)?)
3731
}
3832

3933
fn emit_formatted_file(
4034
&mut self,
41-
output: &mut dyn Write,
35+
_output: &mut dyn Write,
4236
FormattedFile {
4337
filename,
4438
original_text,
@@ -50,66 +44,61 @@ impl Emitter for JsonEmitter {
5044
let has_diff = !diff.is_empty();
5145

5246
if has_diff {
53-
output_json_file(output, filename, diff, self.num_files)?;
54-
self.num_files += 1;
47+
self.add_misformatted_file(filename, diff)?;
5548
}
5649

5750
Ok(EmitterResult { has_diff })
5851
}
5952
}
6053

61-
fn output_json_file<T>(
62-
mut writer: T,
63-
filename: &FileName,
64-
diff: Vec<Mismatch>,
65-
num_emitted_files: u32,
66-
) -> Result<(), io::Error>
67-
where
68-
T: Write,
69-
{
70-
let mut mismatches = vec![];
71-
for mismatch in diff {
72-
let original_begin_line = mismatch.line_number_orig;
73-
let expected_begin_line = mismatch.line_number;
74-
let mut original_end_line = original_begin_line;
75-
let mut expected_end_line = expected_begin_line;
76-
let mut original_line_counter = 0;
77-
let mut expected_line_counter = 0;
78-
let mut original_lines = vec![];
79-
let mut expected_lines = vec![];
54+
impl JsonEmitter {
55+
fn add_misformatted_file(
56+
&mut self,
57+
filename: &FileName,
58+
diff: Vec<Mismatch>,
59+
) -> Result<(), io::Error> {
60+
let mut mismatches = vec![];
61+
for mismatch in diff {
62+
let original_begin_line = mismatch.line_number_orig;
63+
let expected_begin_line = mismatch.line_number;
64+
let mut original_end_line = original_begin_line;
65+
let mut expected_end_line = expected_begin_line;
66+
let mut original_line_counter = 0;
67+
let mut expected_line_counter = 0;
68+
let mut original_lines = vec![];
69+
let mut expected_lines = vec![];
8070

81-
for line in mismatch.lines {
82-
match line {
83-
DiffLine::Expected(msg) => {
84-
expected_end_line = expected_begin_line + expected_line_counter;
85-
expected_line_counter += 1;
86-
expected_lines.push(msg)
87-
}
88-
DiffLine::Resulting(msg) => {
89-
original_end_line = original_begin_line + original_line_counter;
90-
original_line_counter += 1;
91-
original_lines.push(msg)
71+
for line in mismatch.lines {
72+
match line {
73+
DiffLine::Expected(msg) => {
74+
expected_end_line = expected_begin_line + expected_line_counter;
75+
expected_line_counter += 1;
76+
expected_lines.push(msg)
77+
}
78+
DiffLine::Resulting(msg) => {
79+
original_end_line = original_begin_line + original_line_counter;
80+
original_line_counter += 1;
81+
original_lines.push(msg)
82+
}
83+
DiffLine::Context(_) => continue,
9284
}
93-
DiffLine::Context(_) => continue,
9485
}
95-
}
9686

97-
mismatches.push(MismatchedBlock {
98-
original_begin_line,
99-
original_end_line,
100-
expected_begin_line,
101-
expected_end_line,
102-
original: original_lines.join("\n"),
103-
expected: expected_lines.join("\n"),
87+
mismatches.push(MismatchedBlock {
88+
original_begin_line,
89+
original_end_line,
90+
expected_begin_line,
91+
expected_end_line,
92+
original: original_lines.join("\n"),
93+
expected: expected_lines.join("\n"),
94+
});
95+
}
96+
self.mismatched_files.push(MismatchedFile {
97+
name: format!("{}", filename),
98+
mismatches,
10499
});
100+
Ok(())
105101
}
106-
let json = to_json_string(&MismatchedFile {
107-
name: format!("{}", filename),
108-
mismatches,
109-
})?;
110-
let prefix = if num_emitted_files > 0 { "," } else { "" };
111-
write!(writer, "{}{}", prefix, &json)?;
112-
Ok(())
113102
}
114103

115104
#[cfg(test)]
@@ -120,6 +109,9 @@ mod tests {
120109

121110
#[test]
122111
fn expected_line_range_correct_when_single_line_split() {
112+
let mut emitter = JsonEmitter {
113+
mismatched_files: vec![],
114+
};
123115
let file = "foo/bar.rs";
124116
let mismatched_file = MismatchedFile {
125117
name: String::from(file),
@@ -144,19 +136,19 @@ mod tests {
144136
],
145137
};
146138

147-
let mut writer = Vec::new();
148-
let exp_json = to_json_string(&mismatched_file).unwrap();
149-
let _ = output_json_file(
150-
&mut writer,
151-
&FileName::Real(PathBuf::from(file)),
152-
vec![mismatch],
153-
0,
154-
);
155-
assert_eq!(&writer[..], format!("{}", exp_json).as_bytes());
139+
let _ = emitter
140+
.add_misformatted_file(&FileName::Real(PathBuf::from(file)), vec![mismatch])
141+
.unwrap();
142+
143+
assert_eq!(emitter.mismatched_files.len(), 1);
144+
assert_eq!(emitter.mismatched_files[0], mismatched_file);
156145
}
157146

158147
#[test]
159148
fn context_lines_ignored() {
149+
let mut emitter = JsonEmitter {
150+
mismatched_files: vec![],
151+
};
160152
let file = "src/lib.rs";
161153
let mismatched_file = MismatchedFile {
162154
name: String::from(file),
@@ -189,15 +181,12 @@ mod tests {
189181
],
190182
};
191183

192-
let mut writer = Vec::new();
193-
let exp_json = to_json_string(&mismatched_file).unwrap();
194-
let _ = output_json_file(
195-
&mut writer,
196-
&FileName::Real(PathBuf::from(file)),
197-
vec![mismatch],
198-
0,
199-
);
200-
assert_eq!(&writer[..], format!("{}", exp_json).as_bytes());
184+
let _ = emitter
185+
.add_misformatted_file(&FileName::Real(PathBuf::from(file)), vec![mismatch])
186+
.unwrap();
187+
188+
assert_eq!(emitter.mismatched_files.len(), 1);
189+
assert_eq!(emitter.mismatched_files[0], mismatched_file);
201190
}
202191

203192
#[test]
@@ -217,7 +206,7 @@ mod tests {
217206
.unwrap();
218207
let _ = emitter.emit_footer(&mut writer);
219208
assert_eq!(result.has_diff, false);
220-
assert_eq!(&writer[..], "[]".as_bytes());
209+
assert_eq!(&writer[..], "[]\n".as_bytes());
221210
}
222211

223212
#[test]
@@ -263,7 +252,7 @@ mod tests {
263252
)
264253
.unwrap();
265254
let _ = emitter.emit_footer(&mut writer);
266-
let exp_json = to_json_string(&MismatchedFile {
255+
let exp_json = to_json_string(&vec![MismatchedFile {
267256
name: String::from(file_name),
268257
mismatches: vec![
269258
MismatchedBlock {
@@ -287,10 +276,10 @@ mod tests {
287276
),
288277
},
289278
],
290-
})
279+
}])
291280
.unwrap();
292281
assert_eq!(result.has_diff, true);
293-
assert_eq!(&writer[..], format!("[{}]", exp_json).as_bytes());
282+
assert_eq!(&writer[..], format!("{}\n", exp_json).as_bytes());
294283
}
295284

296285
#[test]
@@ -325,7 +314,7 @@ mod tests {
325314
)
326315
.unwrap();
327316
let _ = emitter.emit_footer(&mut writer);
328-
let exp_bin_json = to_json_string(&MismatchedFile {
317+
let exp_bin = MismatchedFile {
329318
name: String::from(bin_file),
330319
mismatches: vec![MismatchedBlock {
331320
original_begin_line: 2,
@@ -335,9 +324,9 @@ mod tests {
335324
original: String::from("println!(\"Hello, world!\");"),
336325
expected: String::from(" println!(\"Hello, world!\");"),
337326
}],
338-
})
339-
.unwrap();
340-
let exp_lib_json = to_json_string(&MismatchedFile {
327+
};
328+
329+
let exp_lib = MismatchedFile {
341330
name: String::from(lib_file),
342331
mismatches: vec![MismatchedBlock {
343332
original_begin_line: 2,
@@ -347,11 +336,9 @@ mod tests {
347336
original: String::from("println!(\"Greetings!\");"),
348337
expected: String::from(" println!(\"Greetings!\");"),
349338
}],
350-
})
351-
.unwrap();
352-
assert_eq!(
353-
&writer[..],
354-
format!("[{},{}]", exp_bin_json, exp_lib_json).as_bytes()
355-
);
339+
};
340+
341+
let exp_json = to_json_string(&vec![exp_bin, exp_lib]).unwrap();
342+
assert_eq!(&writer[..], format!("{}\n", exp_json).as_bytes());
356343
}
357344
}

Diff for: tests/writemode/target/output.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"name":"tests/writemode/source/json.rs","mismatches":[{"original_begin_line":5,"original_end_line":7,"expected_begin_line":5,"expected_end_line":5,"original":"fn foo_expr() {\n 1\n}","expected":"fn foo_expr() { 1 }"},{"original_begin_line":9,"original_end_line":11,"expected_begin_line":7,"expected_end_line":7,"original":"fn foo_stmt() {\n foo();\n}","expected":"fn foo_stmt() { foo(); }"},{"original_begin_line":13,"original_end_line":15,"expected_begin_line":9,"expected_end_line":9,"original":"fn foo_decl_local() {\n let z = 5;\n }","expected":"fn foo_decl_local() { let z = 5; }"},{"original_begin_line":17,"original_end_line":19,"expected_begin_line":11,"expected_end_line":11,"original":"fn foo_decl_item(x: &mut i32) {\n x = 3;\n}","expected":"fn foo_decl_item(x: &mut i32) { x = 3; }"},{"original_begin_line":21,"original_end_line":21,"expected_begin_line":13,"expected_end_line":13,"original":" fn empty() {","expected":"fn empty() {}"},{"original_begin_line":23,"original_end_line":23,"expected_begin_line":15,"expected_end_line":15,"original":"}","expected":"fn foo_return() -> String { \"yay\" }"},{"original_begin_line":25,"original_end_line":29,"expected_begin_line":17,"expected_end_line":20,"original":"fn foo_return() -> String {\n \"yay\"\n}\n\nfn foo_where() -> T where T: Sync {","expected":"fn foo_where() -> T\nwhere\n T: Sync,\n{"},{"original_begin_line":64,"original_end_line":66,"expected_begin_line":55,"expected_end_line":55,"original":"fn lots_of_space () {\n 1 \n}","expected":"fn lots_of_space() { 1 }"},{"original_begin_line":71,"original_end_line":72,"expected_begin_line":60,"expected_end_line":60,"original":" fn dummy(&self) {\n }","expected":" fn dummy(&self) {}"},{"original_begin_line":75,"original_end_line":75,"expected_begin_line":63,"expected_end_line":64,"original":"trait CoolerTypes { fn dummy(&self) { ","expected":"trait CoolerTypes {\n fn dummy(&self) {}"},{"original_begin_line":77,"original_end_line":77,"expected_begin_line":66,"expected_end_line":66,"original":"}","expected":""},{"original_begin_line":79,"original_end_line":79,"expected_begin_line":67,"expected_end_line":70,"original":"fn Foo<T>() where T: Bar {","expected":"fn Foo<T>()\nwhere\n T: Bar,\n{"}]}]
1+
[{"name":"tests/writemode/source/json.rs","mismatches":[{"original_begin_line":5,"original_end_line":7,"expected_begin_line":5,"expected_end_line":5,"original":"fn foo_expr() {\n 1\n}","expected":"fn foo_expr() { 1 }"},{"original_begin_line":9,"original_end_line":11,"expected_begin_line":7,"expected_end_line":7,"original":"fn foo_stmt() {\n foo();\n}","expected":"fn foo_stmt() { foo(); }"},{"original_begin_line":13,"original_end_line":15,"expected_begin_line":9,"expected_end_line":9,"original":"fn foo_decl_local() {\n let z = 5;\n }","expected":"fn foo_decl_local() { let z = 5; }"},{"original_begin_line":17,"original_end_line":19,"expected_begin_line":11,"expected_end_line":11,"original":"fn foo_decl_item(x: &mut i32) {\n x = 3;\n}","expected":"fn foo_decl_item(x: &mut i32) { x = 3; }"},{"original_begin_line":21,"original_end_line":21,"expected_begin_line":13,"expected_end_line":13,"original":" fn empty() {","expected":"fn empty() {}"},{"original_begin_line":23,"original_end_line":23,"expected_begin_line":15,"expected_end_line":15,"original":"}","expected":"fn foo_return() -> String { \"yay\" }"},{"original_begin_line":25,"original_end_line":29,"expected_begin_line":17,"expected_end_line":20,"original":"fn foo_return() -> String {\n \"yay\"\n}\n\nfn foo_where() -> T where T: Sync {","expected":"fn foo_where() -> T\nwhere\n T: Sync,\n{"},{"original_begin_line":64,"original_end_line":66,"expected_begin_line":55,"expected_end_line":55,"original":"fn lots_of_space () {\n 1 \n}","expected":"fn lots_of_space() { 1 }"},{"original_begin_line":71,"original_end_line":72,"expected_begin_line":60,"expected_end_line":60,"original":" fn dummy(&self) {\n }","expected":" fn dummy(&self) {}"},{"original_begin_line":75,"original_end_line":75,"expected_begin_line":63,"expected_end_line":64,"original":"trait CoolerTypes { fn dummy(&self) { ","expected":"trait CoolerTypes {\n fn dummy(&self) {}"},{"original_begin_line":77,"original_end_line":77,"expected_begin_line":66,"expected_end_line":66,"original":"}","expected":""},{"original_begin_line":79,"original_end_line":79,"expected_begin_line":67,"expected_end_line":70,"original":"fn Foo<T>() where T: Bar {","expected":"fn Foo<T>()\nwhere\n T: Bar,\n{"}]}]

Diff for: tests/writemode/target/stdin.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"name":"stdin","mismatches":[{"original_begin_line":1,"original_end_line":6,"expected_begin_line":1,"expected_end_line":2,"original":"\nfn\n some( )\n{\n}\nfn main () {}","expected":"fn some() {}\nfn main() {}"}]}]
1+
[{"name":"stdin","mismatches":[{"original_begin_line":1,"original_end_line":6,"expected_begin_line":1,"expected_end_line":2,"original":"\nfn\n some( )\n{\n}\nfn main () {}","expected":"fn some() {}\nfn main() {}"}]}]

0 commit comments

Comments
 (0)