1 | use crate::diff::{Diff, Render}; |
2 | use crate::error::Error; |
3 | use crate::{normalize, term, Expected, Test}; |
4 | use std::env; |
5 | use std::path::Path; |
6 | use std::process::Output; |
7 | use termcolor::Color::{self, *}; |
8 | |
9 | pub(crate) enum Level { |
10 | Fail, |
11 | Warn, |
12 | } |
13 | |
14 | pub(crate) use self::Level::*; |
15 | |
16 | pub(crate) 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 | |
28 | pub(crate) 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 | |
41 | pub(crate) fn no_tests_enabled() { |
42 | term::color(Yellow); |
43 | println!("There are no trybuild tests enabled yet." ); |
44 | term::reset(); |
45 | } |
46 | |
47 | pub(crate) fn ok() { |
48 | term::color(Green); |
49 | println!("ok" ); |
50 | term::reset(); |
51 | } |
52 | |
53 | pub(crate) 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 | |
71 | pub(crate) fn failed_to_build(stderr: &str) { |
72 | term::bold_color(Red); |
73 | println!("error" ); |
74 | snippet(Red, stderr); |
75 | println!(); |
76 | } |
77 | |
78 | pub(crate) 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 | |
87 | pub(crate) 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 | |
105 | pub(crate) 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 | |
118 | pub(crate) 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 | |
145 | pub(crate) 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 | |
183 | pub(crate) 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 | |
197 | pub(crate) 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 | |
208 | fn snippet(color: Color, content: &str) { |
209 | snippet_diff(color, content, None); |
210 | } |
211 | |
212 | fn 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 | } |
242 | |