2 use crate::rustfmt_diff
::{make_diff, DiffLine, Mismatch}
;
4 use serde_json
::to_string
as to_json_string
;
5 use std
::io
::{self, Write}
;
8 #[derive(Debug, Default)]
9 pub(crate) struct JsonEmitter
{
13 #[derive(Debug, Default, Serialize)]
14 struct MismatchedBlock
{
15 original_begin_line
: u32,
16 original_end_line
: u32,
17 expected_begin_line
: u32,
18 expected_end_line
: u32,
23 #[derive(Debug, Default, Serialize)]
24 struct MismatchedFile
{
26 mismatches
: Vec
<MismatchedBlock
>,
29 impl Emitter
for JsonEmitter
{
30 fn emit_header(&self, output
: &mut dyn Write
) -> Result
<(), io
::Error
> {
35 fn emit_footer(&self, output
: &mut dyn Write
) -> Result
<(), io
::Error
> {
40 fn emit_formatted_file(
42 output
: &mut dyn Write
,
48 ) -> Result
<EmitterResult
, io
::Error
> {
49 const CONTEXT_SIZE
: usize = 0;
50 let filename
= ensure_real_path(filename
);
51 let diff
= make_diff(original_text
, formatted_text
, CONTEXT_SIZE
);
52 let has_diff
= !diff
.is_empty();
55 output_json_file(output
, filename
, diff
, self.num_files
)?
;
59 Ok(EmitterResult { has_diff }
)
63 fn output_json_file
<T
>(
67 num_emitted_files
: u32,
68 ) -> Result
<(), io
::Error
>
72 let mut mismatches
= vec
![];
73 for mismatch
in diff
{
74 let original_begin_line
= mismatch
.line_number_orig
;
75 let expected_begin_line
= mismatch
.line_number
;
76 let mut original_end_line
= original_begin_line
;
77 let mut expected_end_line
= expected_begin_line
;
78 let mut original_line_counter
= 0;
79 let mut expected_line_counter
= 0;
80 let mut original_lines
= vec
![];
81 let mut expected_lines
= vec
![];
83 for line
in mismatch
.lines
{
85 DiffLine
::Expected(msg
) => {
86 expected_end_line
= expected_begin_line
+ expected_line_counter
;
87 expected_line_counter
+= 1;
88 expected_lines
.push(msg
)
90 DiffLine
::Resulting(msg
) => {
91 original_end_line
= original_begin_line
+ original_line_counter
;
92 original_line_counter
+= 1;
93 original_lines
.push(msg
)
95 DiffLine
::Context(_
) => continue,
99 mismatches
.push(MismatchedBlock
{
104 original
: original_lines
.join("\n"),
105 expected
: expected_lines
.join("\n"),
108 let json
= to_json_string(&MismatchedFile
{
109 name
: String
::from(filename
.to_str().unwrap()),
112 let prefix
= if num_emitted_files
> 0 { "," }
else { "" }
;
113 write
!(writer
, "{}{}", prefix
, &json
)?
;
121 use std
::path
::PathBuf
;
124 fn expected_line_range_correct_when_single_line_split() {
125 let file
= "foo/bar.rs";
126 let mismatched_file
= MismatchedFile
{
127 name
: String
::from(file
),
128 mismatches
: vec
![MismatchedBlock
{
129 original_begin_line
: 79,
130 original_end_line
: 79,
131 expected_begin_line
: 79,
132 expected_end_line
: 82,
133 original
: String
::from("fn Foo<T>() where T: Bar {"),
134 expected
: String
::from("fn Foo<T>()\nwhere\n T: Bar,\n{"),
137 let mismatch
= Mismatch
{
139 line_number_orig
: 79,
141 DiffLine
::Resulting(String
::from("fn Foo<T>() where T: Bar {")),
142 DiffLine
::Expected(String
::from("fn Foo<T>()")),
143 DiffLine
::Expected(String
::from("where")),
144 DiffLine
::Expected(String
::from(" T: Bar,")),
145 DiffLine
::Expected(String
::from("{")),
149 let mut writer
= Vec
::new();
150 let exp_json
= to_json_string(&mismatched_file
).unwrap();
151 let _
= output_json_file(&mut writer
, &PathBuf
::from(file
), vec
![mismatch
], 0);
152 assert_eq
!(&writer
[..], format
!("{}", exp_json
).as_bytes());
156 fn context_lines_ignored() {
157 let file
= "src/lib.rs";
158 let mismatched_file
= MismatchedFile
{
159 name
: String
::from(file
),
160 mismatches
: vec
![MismatchedBlock
{
161 original_begin_line
: 5,
162 original_end_line
: 5,
163 expected_begin_line
: 5,
164 expected_end_line
: 5,
165 original
: String
::from(
166 "fn foo(_x: &u64) -> Option<&(dyn::std::error::Error + 'static)> {",
168 expected
: String
::from(
169 "fn foo(_x: &u64) -> Option<&(dyn ::std::error::Error + 'static)> {",
173 let mismatch
= Mismatch
{
177 DiffLine
::Context(String
::new()),
178 DiffLine
::Resulting(String
::from(
179 "fn foo(_x: &u64) -> Option<&(dyn::std::error::Error + 'static)> {",
181 DiffLine
::Context(String
::new()),
182 DiffLine
::Expected(String
::from(
183 "fn foo(_x: &u64) -> Option<&(dyn ::std::error::Error + 'static)> {",
185 DiffLine
::Context(String
::new()),
189 let mut writer
= Vec
::new();
190 let exp_json
= to_json_string(&mismatched_file
).unwrap();
191 let _
= output_json_file(&mut writer
, &PathBuf
::from(file
), vec
![mismatch
], 0);
192 assert_eq
!(&writer
[..], format
!("{}", exp_json
).as_bytes());
196 fn emits_empty_array_on_no_diffs() {
197 let mut writer
= Vec
::new();
198 let mut emitter
= JsonEmitter
::default();
199 let _
= emitter
.emit_header(&mut writer
);
201 .emit_formatted_file(
204 filename
: &FileName
::Real(PathBuf
::from("src/lib.rs")),
205 original_text
: "fn empty() {}\n",
206 formatted_text
: "fn empty() {}\n",
210 let _
= emitter
.emit_footer(&mut writer
);
211 assert_eq
!(result
.has_diff
, false);
212 assert_eq
!(&writer
[..], "[]".as_bytes());
216 fn emits_array_with_files_with_diffs() {
217 let file_name
= "src/bin.rs";
220 "println!(\"Hello, world!\");",
227 " assert_eq!(2 + 2, 4);",
231 let formatted
= vec
![
233 " println!(\"Hello, world!\");",
240 " assert_eq!(2 + 2, 4);",
244 let mut writer
= Vec
::new();
245 let mut emitter
= JsonEmitter
::default();
246 let _
= emitter
.emit_header(&mut writer
);
248 .emit_formatted_file(
251 filename
: &FileName
::Real(PathBuf
::from(file_name
)),
252 original_text
: &original
.join("\n"),
253 formatted_text
: &formatted
.join("\n"),
257 let _
= emitter
.emit_footer(&mut writer
);
258 let exp_json
= to_json_string(&MismatchedFile
{
259 name
: String
::from(file_name
),
262 original_begin_line
: 2,
263 original_end_line
: 2,
264 expected_begin_line
: 2,
265 expected_end_line
: 2,
266 original
: String
::from("println!(\"Hello, world!\");"),
267 expected
: String
::from(" println!(\"Hello, world!\");"),
270 original_begin_line
: 7,
271 original_end_line
: 10,
272 expected_begin_line
: 7,
273 expected_end_line
: 10,
274 original
: String
::from(
275 "#[test]\nfn it_works() {\n assert_eq!(2 + 2, 4);\n}",
277 expected
: String
::from(
278 " #[test]\n fn it_works() {\n assert_eq!(2 + 2, 4);\n }",
284 assert_eq
!(result
.has_diff
, true);
285 assert_eq
!(&writer
[..], format
!("[{}]", exp_json
).as_bytes());
289 fn emits_valid_json_with_multiple_files() {
290 let bin_file
= "src/bin.rs";
291 let bin_original
= vec
!["fn main() {", "println!(\"Hello, world!\");", "}"];
292 let bin_formatted
= vec
!["fn main() {", " println!(\"Hello, world!\");", "}"];
293 let lib_file
= "src/lib.rs";
294 let lib_original
= vec
!["fn greet() {", "println!(\"Greetings!\");", "}"];
295 let lib_formatted
= vec
!["fn greet() {", " println!(\"Greetings!\");", "}"];
296 let mut writer
= Vec
::new();
297 let mut emitter
= JsonEmitter
::default();
298 let _
= emitter
.emit_header(&mut writer
);
300 .emit_formatted_file(
303 filename
: &FileName
::Real(PathBuf
::from(bin_file
)),
304 original_text
: &bin_original
.join("\n"),
305 formatted_text
: &bin_formatted
.join("\n"),
310 .emit_formatted_file(
313 filename
: &FileName
::Real(PathBuf
::from(lib_file
)),
314 original_text
: &lib_original
.join("\n"),
315 formatted_text
: &lib_formatted
.join("\n"),
319 let _
= emitter
.emit_footer(&mut writer
);
320 let exp_bin_json
= to_json_string(&MismatchedFile
{
321 name
: String
::from(bin_file
),
322 mismatches
: vec
![MismatchedBlock
{
323 original_begin_line
: 2,
324 original_end_line
: 2,
325 expected_begin_line
: 2,
326 expected_end_line
: 2,
327 original
: String
::from("println!(\"Hello, world!\");"),
328 expected
: String
::from(" println!(\"Hello, world!\");"),
332 let exp_lib_json
= to_json_string(&MismatchedFile
{
333 name
: String
::from(lib_file
),
334 mismatches
: vec
![MismatchedBlock
{
335 original_begin_line
: 2,
336 original_end_line
: 2,
337 expected_begin_line
: 2,
338 expected_end_line
: 2,
339 original
: String
::from("println!(\"Greetings!\");"),
340 expected
: String
::from(" println!(\"Greetings!\");"),
346 format
!("[{},{}]", exp_bin_json
, exp_lib_json
).as_bytes()