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