]> git.lizzy.rs Git - rust.git/blob - library/std/src/error/tests.rs
:arrow_up: rust-analyzer
[rust.git] / library / std / src / error / tests.rs
1 use super::Error;
2 use crate::fmt;
3
4 #[derive(Debug, PartialEq)]
5 struct A;
6 #[derive(Debug, PartialEq)]
7 struct B;
8
9 impl fmt::Display for A {
10     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11         write!(f, "A")
12     }
13 }
14 impl fmt::Display for B {
15     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16         write!(f, "B")
17     }
18 }
19
20 impl Error for A {}
21 impl Error for B {}
22
23 #[test]
24 fn downcasting() {
25     let mut a = A;
26     let a = &mut a as &mut (dyn Error + 'static);
27     assert_eq!(a.downcast_ref::<A>(), Some(&A));
28     assert_eq!(a.downcast_ref::<B>(), None);
29     assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
30     assert_eq!(a.downcast_mut::<B>(), None);
31
32     let a: Box<dyn Error> = Box::new(A);
33     match a.downcast::<B>() {
34         Ok(..) => panic!("expected error"),
35         Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
36     }
37 }
38
39 use crate::backtrace::Backtrace;
40 use crate::error::Report;
41
42 #[derive(Debug)]
43 struct SuperError {
44     source: SuperErrorSideKick,
45 }
46
47 impl fmt::Display for SuperError {
48     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49         write!(f, "SuperError is here!")
50     }
51 }
52
53 impl Error for SuperError {
54     fn source(&self) -> Option<&(dyn Error + 'static)> {
55         Some(&self.source)
56     }
57 }
58
59 #[derive(Debug)]
60 struct SuperErrorSideKick;
61
62 impl fmt::Display for SuperErrorSideKick {
63     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64         write!(f, "SuperErrorSideKick is here!")
65     }
66 }
67
68 impl Error for SuperErrorSideKick {}
69
70 #[test]
71 fn single_line_formatting() {
72     let error = SuperError { source: SuperErrorSideKick };
73     let report = Report::new(&error);
74     let actual = report.to_string();
75     let expected = String::from("SuperError is here!: SuperErrorSideKick is here!");
76
77     assert_eq!(expected, actual);
78 }
79
80 #[test]
81 fn multi_line_formatting() {
82     let error = SuperError { source: SuperErrorSideKick };
83     let report = Report::new(&error).pretty(true);
84     let actual = report.to_string();
85     let expected = String::from(
86         "\
87 SuperError is here!
88
89 Caused by:
90       SuperErrorSideKick is here!",
91     );
92
93     assert_eq!(expected, actual);
94 }
95
96 #[test]
97 fn error_with_no_sources_formats_single_line_correctly() {
98     let report = Report::new(SuperErrorSideKick);
99     let actual = report.to_string();
100     let expected = String::from("SuperErrorSideKick is here!");
101
102     assert_eq!(expected, actual);
103 }
104
105 #[test]
106 fn error_with_no_sources_formats_multi_line_correctly() {
107     let report = Report::new(SuperErrorSideKick).pretty(true);
108     let actual = report.to_string();
109     let expected = String::from("SuperErrorSideKick is here!");
110
111     assert_eq!(expected, actual);
112 }
113
114 #[test]
115 fn error_with_backtrace_outputs_correctly_with_one_source() {
116     let trace = Backtrace::force_capture();
117     let expected = format!(
118         "\
119 The source of the error
120
121 Caused by:
122       Error with backtrace
123
124 Stack backtrace:
125 {}",
126         trace
127     );
128     let error = GenericError::new("Error with backtrace");
129     let mut error = GenericError::new_with_source("The source of the error", error);
130     error.backtrace = Some(trace);
131     let report = Report::new(error).pretty(true).show_backtrace(true);
132
133     println!("Error: {report}");
134     assert_eq!(expected.trim_end(), report.to_string());
135 }
136
137 #[test]
138 fn error_with_backtrace_outputs_correctly_with_two_sources() {
139     let trace = Backtrace::force_capture();
140     let expected = format!(
141         "\
142 Error with two sources
143
144 Caused by:
145    0: The source of the error
146    1: Error with backtrace
147
148 Stack backtrace:
149 {}",
150         trace
151     );
152     let mut error = GenericError::new("Error with backtrace");
153     error.backtrace = Some(trace);
154     let error = GenericError::new_with_source("The source of the error", error);
155     let error = GenericError::new_with_source("Error with two sources", error);
156     let report = Report::new(error).pretty(true).show_backtrace(true);
157
158     println!("Error: {report}");
159     assert_eq!(expected.trim_end(), report.to_string());
160 }
161
162 #[derive(Debug)]
163 struct GenericError<D> {
164     message: D,
165     backtrace: Option<Backtrace>,
166     source: Option<Box<dyn Error + 'static>>,
167 }
168
169 impl<D> GenericError<D> {
170     fn new(message: D) -> GenericError<D> {
171         Self { message, backtrace: None, source: None }
172     }
173
174     fn new_with_source<E>(message: D, source: E) -> GenericError<D>
175     where
176         E: Error + 'static,
177     {
178         let source: Box<dyn Error + 'static> = Box::new(source);
179         let source = Some(source);
180         GenericError { message, backtrace: None, source }
181     }
182 }
183
184 impl<D> fmt::Display for GenericError<D>
185 where
186     D: fmt::Display,
187 {
188     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189         fmt::Display::fmt(&self.message, f)
190     }
191 }
192
193 impl<D> Error for GenericError<D>
194 where
195     D: fmt::Debug + fmt::Display,
196 {
197     fn source(&self) -> Option<&(dyn Error + 'static)> {
198         self.source.as_deref()
199     }
200
201     fn backtrace(&self) -> Option<&Backtrace> {
202         self.backtrace.as_ref()
203     }
204 }
205
206 #[test]
207 fn error_formats_single_line_with_rude_display_impl() {
208     #[derive(Debug)]
209     struct MyMessage;
210
211     impl fmt::Display for MyMessage {
212         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213             f.write_str("line 1\nline 2")?;
214             f.write_str("\nline 3\nline 4\n")?;
215             f.write_str("line 5\nline 6")?;
216             Ok(())
217         }
218     }
219
220     let error = GenericError::new(MyMessage);
221     let error = GenericError::new_with_source(MyMessage, error);
222     let error = GenericError::new_with_source(MyMessage, error);
223     let error = GenericError::new_with_source(MyMessage, error);
224     let report = Report::new(error);
225     let expected = "\
226 line 1
227 line 2
228 line 3
229 line 4
230 line 5
231 line 6: line 1
232 line 2
233 line 3
234 line 4
235 line 5
236 line 6: line 1
237 line 2
238 line 3
239 line 4
240 line 5
241 line 6: line 1
242 line 2
243 line 3
244 line 4
245 line 5
246 line 6";
247
248     let actual = report.to_string();
249     assert_eq!(expected, actual);
250 }
251
252 #[test]
253 fn error_formats_multi_line_with_rude_display_impl() {
254     #[derive(Debug)]
255     struct MyMessage;
256
257     impl fmt::Display for MyMessage {
258         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259             f.write_str("line 1\nline 2")?;
260             f.write_str("\nline 3\nline 4\n")?;
261             f.write_str("line 5\nline 6")?;
262             Ok(())
263         }
264     }
265
266     let error = GenericError::new(MyMessage);
267     let error = GenericError::new_with_source(MyMessage, error);
268     let error = GenericError::new_with_source(MyMessage, error);
269     let error = GenericError::new_with_source(MyMessage, error);
270     let report = Report::new(error).pretty(true);
271     let expected = "line 1
272 line 2
273 line 3
274 line 4
275 line 5
276 line 6
277
278 Caused by:
279    0: line 1
280       line 2
281       line 3
282       line 4
283       line 5
284       line 6
285    1: line 1
286       line 2
287       line 3
288       line 4
289       line 5
290       line 6
291    2: line 1
292       line 2
293       line 3
294       line 4
295       line 5
296       line 6";
297
298     let actual = report.to_string();
299     assert_eq!(expected, actual);
300 }
301
302 #[test]
303 fn errors_that_start_with_newline_formats_correctly() {
304     #[derive(Debug)]
305     struct MyMessage;
306
307     impl fmt::Display for MyMessage {
308         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309             f.write_str("\nThe message\n")
310         }
311     }
312
313     let error = GenericError::new(MyMessage);
314     let error = GenericError::new_with_source(MyMessage, error);
315     let error = GenericError::new_with_source(MyMessage, error);
316     let report = Report::new(error).pretty(true);
317     let expected = "
318 The message
319
320
321 Caused by:
322    0: \
323 \n      The message
324       \
325 \n   1: \
326 \n      The message
327       ";
328
329     let actual = report.to_string();
330     assert_eq!(expected, actual);
331 }
332
333 #[test]
334 fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() {
335     #[derive(Debug)]
336     struct MyMessage;
337
338     impl fmt::Display for MyMessage {
339         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340             f.write_str("The message")?;
341             f.write_str(" goes on")?;
342             f.write_str(" and on.")
343         }
344     }
345
346     let error = GenericError::new(MyMessage);
347     let error = GenericError::new_with_source(MyMessage, error);
348     let error = GenericError::new_with_source(MyMessage, error);
349     let report = Report::new(error).pretty(true);
350     let expected = "\
351 The message goes on and on.
352
353 Caused by:
354    0: The message goes on and on.
355    1: The message goes on and on.";
356
357     let actual = report.to_string();
358     println!("{actual}");
359     assert_eq!(expected, actual);
360 }
361
362 #[test]
363 fn errors_with_string_interpolation_formats_correctly() {
364     #[derive(Debug)]
365     struct MyMessage(usize);
366
367     impl fmt::Display for MyMessage {
368         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369             write!(f, "Got an error code: ({}). ", self.0)?;
370             write!(f, "What would you like to do in response?")
371         }
372     }
373
374     let error = GenericError::new(MyMessage(10));
375     let error = GenericError::new_with_source(MyMessage(20), error);
376     let report = Report::new(error).pretty(true);
377     let expected = "\
378 Got an error code: (20). What would you like to do in response?
379
380 Caused by:
381       Got an error code: (10). What would you like to do in response?";
382     let actual = report.to_string();
383     assert_eq!(expected, actual);
384 }
385
386 #[test]
387 fn empty_lines_mid_message() {
388     #[derive(Debug)]
389     struct MyMessage;
390
391     impl fmt::Display for MyMessage {
392         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393             f.write_str("line 1\n\nline 2")
394         }
395     }
396
397     let error = GenericError::new(MyMessage);
398     let error = GenericError::new_with_source(MyMessage, error);
399     let error = GenericError::new_with_source(MyMessage, error);
400     let report = Report::new(error).pretty(true);
401     let expected = "\
402 line 1
403
404 line 2
405
406 Caused by:
407    0: line 1
408       \
409 \n      line 2
410    1: line 1
411       \
412 \n      line 2";
413
414     let actual = report.to_string();
415     assert_eq!(expected, actual);
416 }
417
418 #[test]
419 fn only_one_source() {
420     #[derive(Debug)]
421     struct MyMessage;
422
423     impl fmt::Display for MyMessage {
424         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425             f.write_str("line 1\nline 2")
426         }
427     }
428
429     let error = GenericError::new(MyMessage);
430     let error = GenericError::new_with_source(MyMessage, error);
431     let report = Report::new(error).pretty(true);
432     let expected = "\
433 line 1
434 line 2
435
436 Caused by:
437       line 1
438       line 2";
439
440     let actual = report.to_string();
441     assert_eq!(expected, actual);
442 }