]> git.lizzy.rs Git - rust.git/blob - src/rustfmt_diff.rs
Cargo fmt and update tests
[rust.git] / src / rustfmt_diff.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use config::Color;
12 use diff;
13 use std::collections::VecDeque;
14 use std::io;
15 use term;
16 use utils::use_colored_tty;
17
18 #[derive(Debug, PartialEq)]
19 pub enum DiffLine {
20     Context(String),
21     Expected(String),
22     Resulting(String),
23 }
24
25 #[derive(Debug, PartialEq)]
26 pub struct Mismatch {
27     pub line_number: u32,
28     pub lines: Vec<DiffLine>,
29 }
30
31 impl Mismatch {
32     fn new(line_number: u32) -> Mismatch {
33         Mismatch {
34             line_number: line_number,
35             lines: Vec::new(),
36         }
37     }
38 }
39
40 // Produces a diff between the expected output and actual output of rustfmt.
41 pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
42     let mut line_number = 1;
43     let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
44     let mut lines_since_mismatch = context_size + 1;
45     let mut results = Vec::new();
46     let mut mismatch = Mismatch::new(0);
47
48     for result in diff::lines(expected, actual) {
49         match result {
50             diff::Result::Left(str) => {
51                 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
52                     results.push(mismatch);
53                     mismatch = Mismatch::new(line_number - context_queue.len() as u32);
54                 }
55
56                 while let Some(line) = context_queue.pop_front() {
57                     mismatch.lines.push(DiffLine::Context(line.to_owned()));
58                 }
59
60                 mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
61                 lines_since_mismatch = 0;
62             }
63             diff::Result::Right(str) => {
64                 if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
65                     results.push(mismatch);
66                     mismatch = Mismatch::new(line_number - context_queue.len() as u32);
67                 }
68
69                 while let Some(line) = context_queue.pop_front() {
70                     mismatch.lines.push(DiffLine::Context(line.to_owned()));
71                 }
72
73                 mismatch.lines.push(DiffLine::Expected(str.to_owned()));
74                 line_number += 1;
75                 lines_since_mismatch = 0;
76             }
77             diff::Result::Both(str, _) => {
78                 if context_queue.len() >= context_size {
79                     let _ = context_queue.pop_front();
80                 }
81
82                 if lines_since_mismatch < context_size {
83                     mismatch.lines.push(DiffLine::Context(str.to_owned()));
84                 } else if context_size > 0 {
85                     context_queue.push_back(str);
86                 }
87
88                 line_number += 1;
89                 lines_since_mismatch += 1;
90             }
91         }
92     }
93
94     results.push(mismatch);
95     results.remove(0);
96
97     results
98 }
99
100 pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F, color: Color)
101 where
102     F: Fn(u32) -> String,
103 {
104     match term::stdout() {
105         Some(ref t) if use_colored_tty(color) && t.supports_color() => {
106             print_diff_fancy(diff, get_section_title, term::stdout().unwrap())
107         }
108         _ => print_diff_basic(diff, get_section_title),
109     }
110 }
111
112 fn print_diff_fancy<F>(
113     diff: Vec<Mismatch>,
114     get_section_title: F,
115     mut t: Box<term::Terminal<Output = io::Stdout>>,
116 ) where
117     F: Fn(u32) -> String,
118 {
119     for mismatch in diff {
120         let title = get_section_title(mismatch.line_number);
121         writeln!(t, "{}", title).unwrap();
122
123         for line in mismatch.lines {
124             match line {
125                 DiffLine::Context(ref str) => {
126                     t.reset().unwrap();
127                     writeln!(t, " {}⏎", str).unwrap();
128                 }
129                 DiffLine::Expected(ref str) => {
130                     t.fg(term::color::GREEN).unwrap();
131                     writeln!(t, "+{}⏎", str).unwrap();
132                 }
133                 DiffLine::Resulting(ref str) => {
134                     t.fg(term::color::RED).unwrap();
135                     writeln!(t, "-{}⏎", str).unwrap();
136                 }
137             }
138         }
139         t.reset().unwrap();
140     }
141 }
142
143 pub fn print_diff_basic<F>(diff: Vec<Mismatch>, get_section_title: F)
144 where
145     F: Fn(u32) -> String,
146 {
147     for mismatch in diff {
148         let title = get_section_title(mismatch.line_number);
149         println!("{}", title);
150
151         for line in mismatch.lines {
152             match line {
153                 DiffLine::Context(ref str) => {
154                     println!(" {}⏎", str);
155                 }
156                 DiffLine::Expected(ref str) => {
157                     println!("+{}⏎", str);
158                 }
159                 DiffLine::Resulting(ref str) => {
160                     println!("-{}⏎", str);
161                 }
162             }
163         }
164     }
165 }
166
167 #[cfg(test)]
168 mod test {
169     use super::{make_diff, Mismatch};
170     use super::DiffLine::*;
171
172     #[test]
173     fn diff_simple() {
174         let src = "one\ntwo\nthree\nfour\nfive\n";
175         let dest = "one\ntwo\ntrois\nfour\nfive\n";
176         let diff = make_diff(src, dest, 1);
177         assert_eq!(
178             diff,
179             vec![
180                 Mismatch {
181                     line_number: 2,
182                     lines: vec![
183                         Context("two".into()),
184                         Resulting("three".into()),
185                         Expected("trois".into()),
186                         Context("four".into()),
187                     ],
188                 },
189             ]
190         );
191     }
192
193     #[test]
194     fn diff_simple2() {
195         let src = "one\ntwo\nthree\nfour\nfive\nsix\nseven\n";
196         let dest = "one\ntwo\ntrois\nfour\ncinq\nsix\nseven\n";
197         let diff = make_diff(src, dest, 1);
198         assert_eq!(
199             diff,
200             vec![
201                 Mismatch {
202                     line_number: 2,
203                     lines: vec![
204                         Context("two".into()),
205                         Resulting("three".into()),
206                         Expected("trois".into()),
207                         Context("four".into()),
208                     ],
209                 },
210                 Mismatch {
211                     line_number: 5,
212                     lines: vec![
213                         Resulting("five".into()),
214                         Expected("cinq".into()),
215                         Context("six".into()),
216                     ],
217                 },
218             ]
219         );
220     }
221
222     #[test]
223     fn diff_zerocontext() {
224         let src = "one\ntwo\nthree\nfour\nfive\n";
225         let dest = "one\ntwo\ntrois\nfour\nfive\n";
226         let diff = make_diff(src, dest, 0);
227         assert_eq!(
228             diff,
229             vec![
230                 Mismatch {
231                     line_number: 3,
232                     lines: vec![Resulting("three".into()), Expected("trois".into())],
233                 },
234             ]
235         );
236     }
237
238     #[test]
239     fn diff_trailing_newline() {
240         let src = "one\ntwo\nthree\nfour\nfive";
241         let dest = "one\ntwo\nthree\nfour\nfive\n";
242         let diff = make_diff(src, dest, 1);
243         assert_eq!(
244             diff,
245             vec![
246                 Mismatch {
247                     line_number: 5,
248                     lines: vec![Context("five".into()), Expected("".into())],
249                 },
250             ]
251         );
252     }
253 }