/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pretty_assertions-1.4.1/src/printer.rs
Line | Count | Source |
1 | | #[cfg(feature = "alloc")] |
2 | | use alloc::format; |
3 | | use core::fmt; |
4 | | use yansi::Color::{Green, Red}; |
5 | | use yansi::{Paint, Style}; |
6 | | |
7 | | macro_rules! paint { |
8 | | ($f:expr, $style:expr, $fmt:expr, $($args:tt)*) => ( |
9 | | write!($f, "{}", format!($fmt, $($args)*).paint($style)) |
10 | | ) |
11 | | } |
12 | | |
13 | | const SIGN_RIGHT: char = '>'; // + > → |
14 | | const SIGN_LEFT: char = '<'; // - < ← |
15 | | |
16 | | /// Present the diff output for two mutliline strings in a pretty, colorised manner. |
17 | 0 | pub(crate) fn write_header(f: &mut fmt::Formatter) -> fmt::Result { |
18 | 0 | writeln!( |
19 | 0 | f, |
20 | 0 | "{} {} {} / {} {} :", |
21 | 0 | "Diff".bold(), |
22 | 0 | SIGN_LEFT.red().linger(), |
23 | 0 | "left".resetting(), |
24 | 0 | "right".green().linger(), |
25 | 0 | SIGN_RIGHT.resetting(), |
26 | | ) |
27 | 0 | } |
28 | | |
29 | | /// Delay formatting this deleted chunk until later. |
30 | | /// |
31 | | /// It can be formatted as a whole chunk by calling `flush`, or the inner value |
32 | | /// obtained with `take` for further processing (such as an inline diff). |
33 | | #[derive(Default)] |
34 | | struct LatentDeletion<'a> { |
35 | | // The most recent deleted line we've seen |
36 | | value: Option<&'a str>, |
37 | | // The number of deleted lines we've seen, including the current value |
38 | | count: usize, |
39 | | } |
40 | | |
41 | | impl<'a> LatentDeletion<'a> { |
42 | | /// Set the chunk value. |
43 | 0 | fn set(&mut self, value: &'a str) { |
44 | 0 | self.value = Some(value); |
45 | 0 | self.count += 1; |
46 | 0 | } |
47 | | |
48 | | /// Take the underlying chunk value, if it's suitable for inline diffing. |
49 | | /// |
50 | | /// If there is no value or we've seen more than one line, return `None`. |
51 | 0 | fn take(&mut self) -> Option<&'a str> { |
52 | 0 | if self.count == 1 { |
53 | 0 | self.value.take() |
54 | | } else { |
55 | 0 | None |
56 | | } |
57 | 0 | } |
58 | | |
59 | | /// If a value is set, print it as a whole chunk, using the given formatter. |
60 | | /// |
61 | | /// If a value is not set, reset the count to zero (as we've called `flush` twice, |
62 | | /// without seeing another deletion. Therefore the line in the middle was something else). |
63 | 0 | fn flush<TWrite: fmt::Write>(&mut self, f: &mut TWrite) -> fmt::Result { |
64 | 0 | if let Some(value) = self.value { |
65 | 0 | paint!(f, Red, "{}{}", SIGN_LEFT, value)?; |
66 | 0 | writeln!(f)?; |
67 | 0 | self.value = None; |
68 | 0 | } else { |
69 | 0 | self.count = 0; |
70 | 0 | } |
71 | | |
72 | 0 | Ok(()) |
73 | 0 | } Unexecuted instantiation: <pretty_assertions::printer::LatentDeletion>::flush::<core::fmt::Formatter> Unexecuted instantiation: <pretty_assertions::printer::LatentDeletion>::flush::<_> |
74 | | } |
75 | | |
76 | | // Adapted from: |
77 | | // https://github.com/johannhof/difference.rs/blob/c5749ad7d82aa3d480c15cb61af9f6baa08f116f/examples/github-style.rs |
78 | | // Credits johannhof (MIT License) |
79 | | |
80 | | /// Present the diff output for two mutliline strings in a pretty, colorised manner. |
81 | 0 | pub(crate) fn write_lines<TWrite: fmt::Write>( |
82 | 0 | f: &mut TWrite, |
83 | 0 | left: &str, |
84 | 0 | right: &str, |
85 | 0 | ) -> fmt::Result { |
86 | 0 | let diff = ::diff::lines(left, right); |
87 | | |
88 | 0 | let mut changes = diff.into_iter().peekable(); |
89 | 0 | let mut previous_deletion = LatentDeletion::default(); |
90 | | |
91 | 0 | while let Some(change) = changes.next() { |
92 | 0 | match (change, changes.peek()) { |
93 | | // If the text is unchanged, just print it plain |
94 | 0 | (::diff::Result::Both(value, _), _) => { |
95 | 0 | previous_deletion.flush(f)?; |
96 | 0 | writeln!(f, " {}", value)?; |
97 | | } |
98 | | // Defer any deletions to next loop |
99 | 0 | (::diff::Result::Left(deleted), _) => { |
100 | 0 | previous_deletion.flush(f)?; |
101 | 0 | previous_deletion.set(deleted); |
102 | | } |
103 | | // If we're being followed by more insertions, don't inline diff |
104 | 0 | (::diff::Result::Right(inserted), Some(::diff::Result::Right(_))) => { |
105 | 0 | previous_deletion.flush(f)?; |
106 | 0 | paint!(f, Green, "{}{}", SIGN_RIGHT, inserted)?; |
107 | 0 | writeln!(f)?; |
108 | | } |
109 | | // Otherwise, check if we need to inline diff with the previous line (if it was a deletion) |
110 | 0 | (::diff::Result::Right(inserted), _) => { |
111 | 0 | if let Some(deleted) = previous_deletion.take() { |
112 | 0 | write_inline_diff(f, deleted, inserted)?; |
113 | | } else { |
114 | 0 | previous_deletion.flush(f)?; |
115 | 0 | paint!(f, Green, "{}{}", SIGN_RIGHT, inserted)?; |
116 | 0 | writeln!(f)?; |
117 | | } |
118 | | } |
119 | | }; |
120 | | } |
121 | | |
122 | 0 | previous_deletion.flush(f)?; |
123 | 0 | Ok(()) |
124 | 0 | } Unexecuted instantiation: pretty_assertions::printer::write_lines::<core::fmt::Formatter> Unexecuted instantiation: pretty_assertions::printer::write_lines::<_> |
125 | | |
126 | | /// Group character styling for an inline diff, to prevent wrapping each single |
127 | | /// character in terminal styling codes. |
128 | | /// |
129 | | /// Styles are applied automatically each time a new style is given in `write_with_style`. |
130 | | struct InlineWriter<'a, Writer> { |
131 | | f: &'a mut Writer, |
132 | | style: Style, |
133 | | } |
134 | | |
135 | | impl<'a, Writer> InlineWriter<'a, Writer> |
136 | | where |
137 | | Writer: fmt::Write, |
138 | | { |
139 | 0 | fn new(f: &'a mut Writer) -> Self { |
140 | 0 | InlineWriter { |
141 | 0 | f, |
142 | 0 | style: Style::new(), |
143 | 0 | } |
144 | 0 | } Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<core::fmt::Formatter>>::new Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<_>>::new |
145 | | |
146 | | /// Push a new character into the buffer, specifying the style it should be written in. |
147 | 0 | fn write_with_style<T: Into<Style>>(&mut self, c: &char, style: T) -> fmt::Result { |
148 | | // If the style is the same as previously, just write character |
149 | 0 | let style = style.into(); |
150 | 0 | if style == self.style { |
151 | 0 | write!(self.f, "{}", c)?; |
152 | | } else { |
153 | | // Close out previous style |
154 | 0 | self.style.fmt_suffix(self.f)?; |
155 | | |
156 | | // Store new style and start writing it |
157 | 0 | style.fmt_prefix(self.f)?; |
158 | 0 | write!(self.f, "{}", c)?; |
159 | 0 | self.style = style; |
160 | | } |
161 | 0 | Ok(()) |
162 | 0 | } Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<core::fmt::Formatter>>::write_with_style::<yansi::color::Color> Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<core::fmt::Formatter>>::write_with_style::<yansi::style::Style> Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<_>>::write_with_style::<_> |
163 | | |
164 | | /// Finish any existing style and reset to default state. |
165 | 0 | fn finish(&mut self) -> fmt::Result { |
166 | | // Close out previous style |
167 | 0 | self.style.fmt_suffix(self.f)?; |
168 | 0 | writeln!(self.f)?; |
169 | 0 | self.style = Style::new(); |
170 | 0 | Ok(()) |
171 | 0 | } Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<core::fmt::Formatter>>::finish Unexecuted instantiation: <pretty_assertions::printer::InlineWriter<_>>::finish |
172 | | } |
173 | | |
174 | | /// Format a single line to show an inline diff of the two strings given. |
175 | | /// |
176 | | /// The given strings should not have a trailing newline. |
177 | | /// |
178 | | /// The output of this function will be two lines, each with a trailing newline. |
179 | 0 | fn write_inline_diff<TWrite: fmt::Write>(f: &mut TWrite, left: &str, right: &str) -> fmt::Result { |
180 | 0 | let diff = ::diff::chars(left, right); |
181 | 0 | let mut writer = InlineWriter::new(f); |
182 | | |
183 | | // Print the left string on one line, with differences highlighted |
184 | 0 | let light = Red; |
185 | 0 | let heavy = Red.on_fixed(52).bold(); |
186 | 0 | writer.write_with_style(&SIGN_LEFT, light)?; |
187 | 0 | for change in diff.iter() { |
188 | 0 | match change { |
189 | 0 | ::diff::Result::Both(value, _) => writer.write_with_style(value, light)?, |
190 | 0 | ::diff::Result::Left(value) => writer.write_with_style(value, heavy)?, |
191 | 0 | _ => (), |
192 | | } |
193 | | } |
194 | 0 | writer.finish()?; |
195 | | |
196 | | // Print the right string on one line, with differences highlighted |
197 | 0 | let light = Green; |
198 | 0 | let heavy = Green.on_fixed(22).bold(); |
199 | 0 | writer.write_with_style(&SIGN_RIGHT, light)?; |
200 | 0 | for change in diff.iter() { |
201 | 0 | match change { |
202 | 0 | ::diff::Result::Both(value, _) => writer.write_with_style(value, light)?, |
203 | 0 | ::diff::Result::Right(value) => writer.write_with_style(value, heavy)?, |
204 | 0 | _ => (), |
205 | | } |
206 | | } |
207 | 0 | writer.finish() |
208 | 0 | } Unexecuted instantiation: pretty_assertions::printer::write_inline_diff::<core::fmt::Formatter> Unexecuted instantiation: pretty_assertions::printer::write_inline_diff::<_> |
209 | | |
210 | | #[cfg(test)] |
211 | | mod test { |
212 | | use super::*; |
213 | | |
214 | | #[cfg(feature = "alloc")] |
215 | | use alloc::string::String; |
216 | | |
217 | | // ANSI terminal codes used in our outputs. |
218 | | // |
219 | | // Interpolate these into test strings to make expected values easier to read. |
220 | | const RED_LIGHT: &str = "\u{1b}[31m"; |
221 | | const GREEN_LIGHT: &str = "\u{1b}[32m"; |
222 | | const RED_HEAVY: &str = "\u{1b}[1;48;5;52;31m"; |
223 | | const GREEN_HEAVY: &str = "\u{1b}[1;48;5;22;32m"; |
224 | | const RESET: &str = "\u{1b}[0m"; |
225 | | |
226 | | /// Given that both of our diff printing functions have the same |
227 | | /// type signature, we can reuse the same test code for them. |
228 | | /// |
229 | | /// This could probably be nicer with traits! |
230 | | fn check_printer<TPrint>(printer: TPrint, left: &str, right: &str, expected: &str) |
231 | | where |
232 | | TPrint: Fn(&mut String, &str, &str) -> fmt::Result, |
233 | | { |
234 | | let mut actual = String::new(); |
235 | | printer(&mut actual, left, right).expect("printer function failed"); |
236 | | |
237 | | // Cannot use IO without stdlib |
238 | | #[cfg(feature = "std")] |
239 | | println!( |
240 | | "## left ##\n\ |
241 | | {}\n\ |
242 | | ## right ##\n\ |
243 | | {}\n\ |
244 | | ## actual diff ##\n\ |
245 | | {}\n\ |
246 | | ## expected diff ##\n\ |
247 | | {}", |
248 | | left, right, actual, expected |
249 | | ); |
250 | | assert_eq!(actual, expected); |
251 | | } |
252 | | |
253 | | #[test] |
254 | | fn write_inline_diff_empty() { |
255 | | let left = ""; |
256 | | let right = ""; |
257 | | let expected = format!( |
258 | | "{red_light}<{reset}\n\ |
259 | | {green_light}>{reset}\n", |
260 | | red_light = RED_LIGHT, |
261 | | green_light = GREEN_LIGHT, |
262 | | reset = RESET, |
263 | | ); |
264 | | |
265 | | check_printer(write_inline_diff, left, right, &expected); |
266 | | } |
267 | | |
268 | | #[test] |
269 | | fn write_inline_diff_added() { |
270 | | let left = ""; |
271 | | let right = "polymerase"; |
272 | | let expected = format!( |
273 | | "{red_light}<{reset}\n\ |
274 | | {green_light}>{reset}{green_heavy}polymerase{reset}\n", |
275 | | red_light = RED_LIGHT, |
276 | | green_light = GREEN_LIGHT, |
277 | | green_heavy = GREEN_HEAVY, |
278 | | reset = RESET, |
279 | | ); |
280 | | |
281 | | check_printer(write_inline_diff, left, right, &expected); |
282 | | } |
283 | | |
284 | | #[test] |
285 | | fn write_inline_diff_removed() { |
286 | | let left = "polyacrylamide"; |
287 | | let right = ""; |
288 | | let expected = format!( |
289 | | "{red_light}<{reset}{red_heavy}polyacrylamide{reset}\n\ |
290 | | {green_light}>{reset}\n", |
291 | | red_light = RED_LIGHT, |
292 | | green_light = GREEN_LIGHT, |
293 | | red_heavy = RED_HEAVY, |
294 | | reset = RESET, |
295 | | ); |
296 | | |
297 | | check_printer(write_inline_diff, left, right, &expected); |
298 | | } |
299 | | |
300 | | #[test] |
301 | | fn write_inline_diff_changed() { |
302 | | let left = "polymerase"; |
303 | | let right = "polyacrylamide"; |
304 | | let expected = format!( |
305 | | "{red_light}<poly{reset}{red_heavy}me{reset}{red_light}ra{reset}{red_heavy}s{reset}{red_light}e{reset}\n\ |
306 | | {green_light}>poly{reset}{green_heavy}ac{reset}{green_light}r{reset}{green_heavy}yl{reset}{green_light}a{reset}{green_heavy}mid{reset}{green_light}e{reset}\n", |
307 | | red_light = RED_LIGHT, |
308 | | green_light = GREEN_LIGHT, |
309 | | red_heavy = RED_HEAVY, |
310 | | green_heavy = GREEN_HEAVY, |
311 | | reset = RESET, |
312 | | ); |
313 | | |
314 | | check_printer(write_inline_diff, left, right, &expected); |
315 | | } |
316 | | |
317 | | /// If one of our strings is empty, it should not be shown at all in the output. |
318 | | #[test] |
319 | | fn write_lines_empty_string() { |
320 | | let left = ""; |
321 | | let right = "content"; |
322 | | let expected = format!( |
323 | | "{green_light}>content{reset}\n", |
324 | | green_light = GREEN_LIGHT, |
325 | | reset = RESET, |
326 | | ); |
327 | | |
328 | | check_printer(write_lines, left, right, &expected); |
329 | | } |
330 | | |
331 | | /// Realistic multiline struct diffing case. |
332 | | #[test] |
333 | | fn write_lines_struct() { |
334 | | let left = r#"Some( |
335 | | Foo { |
336 | | lorem: "Hello World!", |
337 | | ipsum: 42, |
338 | | dolor: Ok( |
339 | | "hey", |
340 | | ), |
341 | | }, |
342 | | )"#; |
343 | | let right = r#"Some( |
344 | | Foo { |
345 | | lorem: "Hello Wrold!", |
346 | | ipsum: 42, |
347 | | dolor: Ok( |
348 | | "hey ho!", |
349 | | ), |
350 | | }, |
351 | | )"#; |
352 | | let expected = format!( |
353 | | r#" Some( |
354 | | Foo {{ |
355 | | {red_light}< lorem: "Hello W{reset}{red_heavy}o{reset}{red_light}rld!",{reset} |
356 | | {green_light}> lorem: "Hello Wr{reset}{green_heavy}o{reset}{green_light}ld!",{reset} |
357 | | ipsum: 42, |
358 | | dolor: Ok( |
359 | | {red_light}< "hey",{reset} |
360 | | {green_light}> "hey{reset}{green_heavy} ho!{reset}{green_light}",{reset} |
361 | | ), |
362 | | }}, |
363 | | ) |
364 | | "#, |
365 | | red_light = RED_LIGHT, |
366 | | red_heavy = RED_HEAVY, |
367 | | green_light = GREEN_LIGHT, |
368 | | green_heavy = GREEN_HEAVY, |
369 | | reset = RESET, |
370 | | ); |
371 | | |
372 | | check_printer(write_lines, left, right, &expected); |
373 | | } |
374 | | |
375 | | /// Relistic multiple line chunks |
376 | | /// |
377 | | /// We can't support realistic line diffing in large blocks |
378 | | /// (also, it's unclear how usefult this is) |
379 | | /// |
380 | | /// So if we have more than one line in a single removal chunk, disable inline diffing. |
381 | | #[test] |
382 | | fn write_lines_multiline_block() { |
383 | | let left = r#"Proboscis |
384 | | Cabbage"#; |
385 | | let right = r#"Probed |
386 | | Caravaggio"#; |
387 | | let expected = format!( |
388 | | r#"{red_light}<Proboscis{reset} |
389 | | {red_light}<Cabbage{reset} |
390 | | {green_light}>Probed{reset} |
391 | | {green_light}>Caravaggio{reset} |
392 | | "#, |
393 | | red_light = RED_LIGHT, |
394 | | green_light = GREEN_LIGHT, |
395 | | reset = RESET, |
396 | | ); |
397 | | |
398 | | check_printer(write_lines, left, right, &expected); |
399 | | } |
400 | | |
401 | | /// Single deletion line, multiple insertions - no inline diffing. |
402 | | #[test] |
403 | | fn write_lines_multiline_insert() { |
404 | | let left = r#"Cabbage"#; |
405 | | let right = r#"Probed |
406 | | Caravaggio"#; |
407 | | let expected = format!( |
408 | | r#"{red_light}<Cabbage{reset} |
409 | | {green_light}>Probed{reset} |
410 | | {green_light}>Caravaggio{reset} |
411 | | "#, |
412 | | red_light = RED_LIGHT, |
413 | | green_light = GREEN_LIGHT, |
414 | | reset = RESET, |
415 | | ); |
416 | | |
417 | | check_printer(write_lines, left, right, &expected); |
418 | | } |
419 | | |
420 | | /// Multiple deletion, single insertion - no inline diffing. |
421 | | #[test] |
422 | | fn write_lines_multiline_delete() { |
423 | | let left = r#"Proboscis |
424 | | Cabbage"#; |
425 | | let right = r#"Probed"#; |
426 | | let expected = format!( |
427 | | r#"{red_light}<Proboscis{reset} |
428 | | {red_light}<Cabbage{reset} |
429 | | {green_light}>Probed{reset} |
430 | | "#, |
431 | | red_light = RED_LIGHT, |
432 | | green_light = GREEN_LIGHT, |
433 | | reset = RESET, |
434 | | ); |
435 | | |
436 | | check_printer(write_lines, left, right, &expected); |
437 | | } |
438 | | |
439 | | /// Regression test for multiline highlighting issue |
440 | | #[test] |
441 | | fn write_lines_issue12() { |
442 | | let left = r#"[ |
443 | | 0, |
444 | | 0, |
445 | | 0, |
446 | | 128, |
447 | | 10, |
448 | | 191, |
449 | | 5, |
450 | | 64, |
451 | | ]"#; |
452 | | let right = r#"[ |
453 | | 84, |
454 | | 248, |
455 | | 45, |
456 | | 64, |
457 | | ]"#; |
458 | | let expected = format!( |
459 | | r#" [ |
460 | | {red_light}< 0,{reset} |
461 | | {red_light}< 0,{reset} |
462 | | {red_light}< 0,{reset} |
463 | | {red_light}< 128,{reset} |
464 | | {red_light}< 10,{reset} |
465 | | {red_light}< 191,{reset} |
466 | | {red_light}< 5,{reset} |
467 | | {green_light}> 84,{reset} |
468 | | {green_light}> 248,{reset} |
469 | | {green_light}> 45,{reset} |
470 | | 64, |
471 | | ] |
472 | | "#, |
473 | | red_light = RED_LIGHT, |
474 | | green_light = GREEN_LIGHT, |
475 | | reset = RESET, |
476 | | ); |
477 | | |
478 | | check_printer(write_lines, left, right, &expected); |
479 | | } |
480 | | |
481 | | mod write_lines_edge_newlines { |
482 | | use super::*; |
483 | | |
484 | | #[test] |
485 | | fn both_trailing() { |
486 | | let left = "fan\n"; |
487 | | let right = "mug\n"; |
488 | | // Note the additional space at the bottom is caused by a trailing newline |
489 | | // adding an additional line with zero content to both sides of the diff |
490 | | let expected = format!( |
491 | | r#"{red_light}<{reset}{red_heavy}fan{reset} |
492 | | {green_light}>{reset}{green_heavy}mug{reset} |
493 | | |
494 | | "#, |
495 | | red_light = RED_LIGHT, |
496 | | red_heavy = RED_HEAVY, |
497 | | green_light = GREEN_LIGHT, |
498 | | green_heavy = GREEN_HEAVY, |
499 | | reset = RESET, |
500 | | ); |
501 | | |
502 | | check_printer(write_lines, left, right, &expected); |
503 | | } |
504 | | |
505 | | #[test] |
506 | | fn both_leading() { |
507 | | let left = "\nfan"; |
508 | | let right = "\nmug"; |
509 | | // Note the additional space at the top is caused by a leading newline |
510 | | // adding an additional line with zero content to both sides of the diff |
511 | | let expected = format!( |
512 | | r#" |
513 | | {red_light}<{reset}{red_heavy}fan{reset} |
514 | | {green_light}>{reset}{green_heavy}mug{reset} |
515 | | "#, |
516 | | red_light = RED_LIGHT, |
517 | | red_heavy = RED_HEAVY, |
518 | | green_light = GREEN_LIGHT, |
519 | | green_heavy = GREEN_HEAVY, |
520 | | reset = RESET, |
521 | | ); |
522 | | |
523 | | check_printer(write_lines, left, right, &expected); |
524 | | } |
525 | | |
526 | | #[test] |
527 | | fn leading_added() { |
528 | | let left = "fan"; |
529 | | let right = "\nmug"; |
530 | | let expected = format!( |
531 | | r#"{red_light}<fan{reset} |
532 | | {green_light}>{reset} |
533 | | {green_light}>mug{reset} |
534 | | "#, |
535 | | red_light = RED_LIGHT, |
536 | | green_light = GREEN_LIGHT, |
537 | | reset = RESET, |
538 | | ); |
539 | | |
540 | | check_printer(write_lines, left, right, &expected); |
541 | | } |
542 | | |
543 | | #[test] |
544 | | fn leading_deleted() { |
545 | | let left = "\nfan"; |
546 | | let right = "mug"; |
547 | | let expected = format!( |
548 | | r#"{red_light}<{reset} |
549 | | {red_light}<fan{reset} |
550 | | {green_light}>mug{reset} |
551 | | "#, |
552 | | red_light = RED_LIGHT, |
553 | | green_light = GREEN_LIGHT, |
554 | | reset = RESET, |
555 | | ); |
556 | | |
557 | | check_printer(write_lines, left, right, &expected); |
558 | | } |
559 | | |
560 | | #[test] |
561 | | fn trailing_added() { |
562 | | let left = "fan"; |
563 | | let right = "mug\n"; |
564 | | let expected = format!( |
565 | | r#"{red_light}<fan{reset} |
566 | | {green_light}>mug{reset} |
567 | | {green_light}>{reset} |
568 | | "#, |
569 | | red_light = RED_LIGHT, |
570 | | green_light = GREEN_LIGHT, |
571 | | reset = RESET, |
572 | | ); |
573 | | |
574 | | check_printer(write_lines, left, right, &expected); |
575 | | } |
576 | | |
577 | | /// Regression test for double abort |
578 | | /// |
579 | | /// See: https://github.com/rust-pretty-assertions/rust-pretty-assertions/issues/96 |
580 | | #[test] |
581 | | fn trailing_deleted() { |
582 | | // The below inputs caused an abort via double panic |
583 | | // we panicked at 'insertion followed by deletion' |
584 | | let left = "fan\n"; |
585 | | let right = "mug"; |
586 | | let expected = format!( |
587 | | r#"{red_light}<{reset}{red_heavy}fan{reset} |
588 | | {green_light}>{reset}{green_heavy}mug{reset} |
589 | | {red_light}<{reset} |
590 | | "#, |
591 | | red_light = RED_LIGHT, |
592 | | red_heavy = RED_HEAVY, |
593 | | green_light = GREEN_LIGHT, |
594 | | green_heavy = GREEN_HEAVY, |
595 | | reset = RESET, |
596 | | ); |
597 | | |
598 | | check_printer(write_lines, left, right, &expected); |
599 | | } |
600 | | } |
601 | | } |