]> git.lizzy.rs Git - rust.git/blob - src/tools/rustfmt/src/emitter/diff.rs
Auto merge of #82973 - ijackson:exitstatuserror, r=yaahc
[rust.git] / src / tools / rustfmt / src / emitter / diff.rs
1 use super::*;
2 use crate::config::Config;
3 use crate::rustfmt_diff::{make_diff, print_diff};
4
5 pub(crate) struct DiffEmitter {
6     config: Config,
7 }
8
9 impl DiffEmitter {
10     pub(crate) fn new(config: Config) -> Self {
11         Self { config }
12     }
13 }
14
15 impl Emitter for DiffEmitter {
16     fn emit_formatted_file(
17         &mut self,
18         output: &mut dyn Write,
19         FormattedFile {
20             filename,
21             original_text,
22             formatted_text,
23         }: FormattedFile<'_>,
24     ) -> Result<EmitterResult, io::Error> {
25         const CONTEXT_SIZE: usize = 3;
26         let mismatch = make_diff(&original_text, formatted_text, CONTEXT_SIZE);
27         let has_diff = !mismatch.is_empty();
28
29         if has_diff {
30             if self.config.print_misformatted_file_names() {
31                 writeln!(output, "{}", ensure_real_path(filename).display())?;
32             } else {
33                 print_diff(
34                     mismatch,
35                     |line_num| format!("Diff in {} at line {}:", filename, line_num),
36                     &self.config,
37                 );
38             }
39         } else if original_text != formatted_text {
40             // This occurs when the only difference between the original and formatted values
41             // is the newline style. This happens because The make_diff function compares the
42             // original and formatted values line by line, independent of line endings.
43             let file_path = ensure_real_path(filename);
44             writeln!(output, "Incorrect newline style in {}", file_path.display())?;
45             return Ok(EmitterResult { has_diff: true });
46         }
47
48         return Ok(EmitterResult { has_diff });
49     }
50 }
51
52 #[cfg(test)]
53 mod tests {
54     use super::*;
55     use crate::config::Config;
56     use crate::FileName;
57     use std::path::PathBuf;
58
59     #[test]
60     fn does_not_print_when_no_files_reformatted() {
61         let mut writer = Vec::new();
62         let config = Config::default();
63         let mut emitter = DiffEmitter::new(config);
64         let result = emitter
65             .emit_formatted_file(
66                 &mut writer,
67                 FormattedFile {
68                     filename: &FileName::Real(PathBuf::from("src/lib.rs")),
69                     original_text: "fn empty() {}\n",
70                     formatted_text: "fn empty() {}\n",
71                 },
72             )
73             .unwrap();
74         assert_eq!(result.has_diff, false);
75         assert_eq!(writer.len(), 0);
76     }
77
78     #[test]
79     fn prints_file_names_when_config_is_enabled() {
80         let bin_file = "src/bin.rs";
81         let bin_original = "fn main() {\nprintln!(\"Hello, world!\");\n}";
82         let bin_formatted = "fn main() {\n    println!(\"Hello, world!\");\n}";
83         let lib_file = "src/lib.rs";
84         let lib_original = "fn greet() {\nprintln!(\"Greetings!\");\n}";
85         let lib_formatted = "fn greet() {\n    println!(\"Greetings!\");\n}";
86
87         let mut writer = Vec::new();
88         let mut config = Config::default();
89         config.set().print_misformatted_file_names(true);
90         let mut emitter = DiffEmitter::new(config);
91         let _ = emitter
92             .emit_formatted_file(
93                 &mut writer,
94                 FormattedFile {
95                     filename: &FileName::Real(PathBuf::from(bin_file)),
96                     original_text: bin_original,
97                     formatted_text: bin_formatted,
98                 },
99             )
100             .unwrap();
101         let _ = emitter
102             .emit_formatted_file(
103                 &mut writer,
104                 FormattedFile {
105                     filename: &FileName::Real(PathBuf::from(lib_file)),
106                     original_text: lib_original,
107                     formatted_text: lib_formatted,
108                 },
109             )
110             .unwrap();
111
112         assert_eq!(
113             String::from_utf8(writer).unwrap(),
114             format!("{}\n{}\n", bin_file, lib_file),
115         )
116     }
117
118     #[test]
119     fn prints_newline_message_with_only_newline_style_diff() {
120         let mut writer = Vec::new();
121         let config = Config::default();
122         let mut emitter = DiffEmitter::new(config);
123         let _ = emitter
124             .emit_formatted_file(
125                 &mut writer,
126                 FormattedFile {
127                     filename: &FileName::Real(PathBuf::from("src/lib.rs")),
128                     original_text: "fn empty() {}\n",
129                     formatted_text: "fn empty() {}\r\n",
130                 },
131             )
132             .unwrap();
133         assert_eq!(
134             String::from_utf8(writer).unwrap(),
135             String::from("Incorrect newline style in src/lib.rs\n")
136         );
137     }
138 }