trybuild_internals_api/
message.rs

1use crate::diff::{Diff, Render};
2use crate::error::Error;
3use crate::{normalize, term, Expected, Test};
4use std::env;
5use std::path::Path;
6use std::process::Output;
7use termcolor::Color::{self, *};
8
9pub enum Level {
10    Fail,
11    Warn,
12}
13
14pub use self::Level::*;
15
16pub fn prepare_fail(err: Error) {
17    if err.already_printed() {
18        return;
19    }
20
21    term::bold_color(Red);
22    print!("ERROR");
23    term::reset();
24    println!(": {}", err);
25    println!();
26}
27
28pub fn test_fail(err: Error) {
29    if err.already_printed() {
30        return;
31    }
32
33    term::bold_color(Red);
34    println!("error");
35    term::color(Red);
36    println!("{}", err);
37    term::reset();
38    println!();
39}
40
41pub fn no_tests_enabled() {
42    term::color(Yellow);
43    println!("There are no trybuild tests enabled yet.");
44    term::reset();
45}
46
47pub fn ok() {
48    term::color(Green);
49    println!("ok");
50    term::reset();
51}
52
53pub fn begin_test(test: &Test, show_expected: bool) {
54    let display_name = test.path.as_os_str().to_string_lossy();
55
56    print!("test ");
57    term::bold();
58    print!("{}", display_name);
59    term::reset();
60
61    if show_expected {
62        match test.expected {
63            Expected::Pass => print!(" [should pass]"),
64            Expected::CompileFail => print!(" [should fail to compile]"),
65        }
66    }
67
68    print!(" ... ");
69}
70
71pub fn failed_to_build(stderr: &str) {
72    term::bold_color(Red);
73    println!("error");
74    snippet(Red, stderr);
75    println!();
76}
77
78pub fn should_not_have_compiled() {
79    term::bold_color(Red);
80    println!("error");
81    term::color(Red);
82    println!("Expected test case to fail to compile, but it succeeded.");
83    term::reset();
84    println!();
85}
86
87pub fn write_stderr_wip(wip_path: &Path, stderr_path: &Path, stderr: &str) {
88    let wip_path = wip_path.to_string_lossy();
89    let stderr_path = stderr_path.to_string_lossy();
90
91    term::bold_color(Yellow);
92    println!("wip");
93    println!();
94    print!("NOTE");
95    term::reset();
96    println!(": writing the following output to `{}`.", wip_path);
97    println!(
98        "Move this file to `{}` to accept it as correct.",
99        stderr_path,
100    );
101    snippet(Yellow, stderr);
102    println!();
103}
104
105pub fn overwrite_stderr(stderr_path: &Path, stderr: &str) {
106    let stderr_path = stderr_path.to_string_lossy();
107
108    term::bold_color(Yellow);
109    println!("wip");
110    println!();
111    print!("NOTE");
112    term::reset();
113    println!(": writing the following output to `{}`.", stderr_path);
114    snippet(Yellow, stderr);
115    println!();
116}
117
118pub fn mismatch(expected: &str, actual: &str) {
119    term::bold_color(Red);
120    println!("mismatch");
121    term::reset();
122    println!();
123    let diff = if env::var_os("TERM").map_or(true, |term| term == "dumb") {
124        // No diff in dumb terminal or when TERM is unset.
125        None
126    } else {
127        Diff::compute(expected, actual)
128    };
129    term::bold_color(Blue);
130    println!("EXPECTED:");
131    snippet_diff(Blue, expected, diff.as_ref());
132    println!();
133    term::bold_color(Red);
134    println!("ACTUAL OUTPUT:");
135    snippet_diff(Red, actual, diff.as_ref());
136    print!("note: If the ");
137    term::color(Red);
138    print!("actual output");
139    term::reset();
140    println!(" is the correct output you can bless it by rerunning");
141    println!("      your test with the environment variable TRYBUILD=overwrite");
142    println!();
143}
144
145pub fn output(warnings: &str, output: &Output) {
146    let success = output.status.success();
147    let stdout = normalize::trim(&output.stdout);
148    let stderr = normalize::trim(&output.stderr);
149    let has_output = !stdout.is_empty() || !stderr.is_empty();
150
151    if success {
152        ok();
153        if has_output || !warnings.is_empty() {
154            println!();
155        }
156    } else {
157        term::bold_color(Red);
158        println!("error");
159        term::color(Red);
160        if has_output {
161            println!("Test case failed at runtime.");
162        } else {
163            println!("Execution of the test case was unsuccessful but there was no output.");
164        }
165        term::reset();
166        println!();
167    }
168
169    self::warnings(warnings);
170
171    let color = if success { Yellow } else { Red };
172
173    for (name, content) in &[("STDOUT", stdout), ("STDERR", stderr)] {
174        if !content.is_empty() {
175            term::bold_color(color);
176            println!("{}:", name);
177            snippet(color, &normalize::trim(content));
178            println!();
179        }
180    }
181}
182
183pub fn fail_output(level: Level, stdout: &str) {
184    let color = match level {
185        Fail => Red,
186        Warn => Yellow,
187    };
188
189    if !stdout.is_empty() {
190        term::bold_color(color);
191        println!("STDOUT:");
192        snippet(color, &normalize::trim(stdout));
193        println!();
194    }
195}
196
197pub fn warnings(warnings: &str) {
198    if warnings.is_empty() {
199        return;
200    }
201
202    term::bold_color(Yellow);
203    println!("WARNINGS:");
204    snippet(Yellow, warnings);
205    println!();
206}
207
208fn snippet(color: Color, content: &str) {
209    snippet_diff(color, content, None);
210}
211
212fn snippet_diff(color: Color, content: &str, diff: Option<&Diff>) {
213    fn dotted_line() {
214        println!("{}", "┈".repeat(60));
215    }
216
217    term::color(color);
218    dotted_line();
219
220    match diff {
221        Some(diff) => {
222            for chunk in diff.iter(content) {
223                match chunk {
224                    Render::Common(s) => {
225                        term::color(color);
226                        print!("{}", s);
227                    }
228                    Render::Unique(s) => {
229                        term::bold_color(color);
230                        print!("\x1B[7m{}", s);
231                    }
232                }
233            }
234        }
235        None => print!("{}", content),
236    }
237
238    term::color(color);
239    dotted_line();
240    term::reset();
241}