1 use self::xml::XmlEscaped;
3 use crate::rustfmt_diff::{make_diff, DiffLine, Mismatch};
4 use std::io::{self, Write};
9 #[derive(Debug, Default)]
10 pub(crate) struct CheckstyleEmitter;
12 impl Emitter for CheckstyleEmitter {
13 fn emit_header(&self, output: &mut dyn Write) -> Result<(), io::Error> {
14 writeln!(output, r#"<?xml version="1.0" encoding="utf-8"?>"#)?;
15 write!(output, r#"<checkstyle version="4.3">"#)?;
19 fn emit_footer(&self, output: &mut dyn Write) -> Result<(), io::Error> {
20 writeln!(output, "</checkstyle>")
23 fn emit_formatted_file(
25 output: &mut dyn Write,
31 ) -> Result<EmitterResult, io::Error> {
32 const CONTEXT_SIZE: usize = 0;
33 let filename = ensure_real_path(filename);
34 let diff = make_diff(original_text, formatted_text, CONTEXT_SIZE);
35 output_checkstyle_file(output, filename, diff)?;
36 Ok(EmitterResult::default())
40 pub(crate) fn output_checkstyle_file<T>(
44 ) -> Result<(), io::Error>
48 write!(writer, r#"<file name="{}">"#, filename.display())?;
49 for mismatch in diff {
50 let begin_line = mismatch.line_number;
52 let mut line_counter = 0;
53 for line in mismatch.lines {
54 // Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.
55 if let DiffLine::Expected(message) = line {
56 current_line = begin_line + line_counter;
60 r#"<error line="{}" severity="warning" message="Should be `{}`" />"#,
67 write!(writer, "</file>")?;
74 use std::path::PathBuf;
77 fn emits_empty_record_on_file_with_no_mismatches() {
78 let file_name = "src/well_formatted.rs";
79 let mut writer = Vec::new();
80 let _ = output_checkstyle_file(&mut writer, &PathBuf::from(file_name), vec![]);
83 format!(r#"<file name="{}"></file>"#, file_name).as_bytes()
87 // https://github.com/rust-lang/rustfmt/issues/1636
89 fn emits_single_xml_tree_containing_all_files() {
90 let bin_file = "src/bin.rs";
91 let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"];
92 let bin_formatted = vec!["fn main() {", " println!(\"Hello, world!\");", "}"];
93 let lib_file = "src/lib.rs";
94 let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"];
95 let lib_formatted = vec!["fn greet() {", " println!(\"Greetings!\");", "}"];
96 let mut writer = Vec::new();
97 let mut emitter = CheckstyleEmitter::default();
98 let _ = emitter.emit_header(&mut writer);
100 .emit_formatted_file(
103 filename: &FileName::Real(PathBuf::from(bin_file)),
104 original_text: &bin_original.join("\n"),
105 formatted_text: &bin_formatted.join("\n"),
110 .emit_formatted_file(
113 filename: &FileName::Real(PathBuf::from(lib_file)),
114 original_text: &lib_original.join("\n"),
115 formatted_text: &lib_formatted.join("\n"),
119 let _ = emitter.emit_footer(&mut writer);
120 let exp_bin_xml = vec![
121 format!(r#"<file name="{}">"#, bin_file),
123 r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
124 XmlEscaped(&r#" println!("Hello, world!");"#),
126 String::from("</file>"),
128 let exp_lib_xml = vec![
129 format!(r#"<file name="{}">"#, lib_file),
131 r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
132 XmlEscaped(&r#" println!("Greetings!");"#),
134 String::from("</file>"),
137 String::from_utf8(writer).unwrap(),
139 r#"<?xml version="1.0" encoding="utf-8"?>"#,
141 r#"<checkstyle version="4.3">"#,
142 &format!("{}{}", exp_bin_xml.join(""), exp_lib_xml.join("")),