xref: /wasmtime-44.0.1/crates/core/tests/tests.rs (revision bda02c19)
1 extern crate alloc;
2 #[cfg(feature = "std")]
3 extern crate std;
4 
5 use alloc::{
6     format,
7     string::{String, ToString},
8     sync::Arc,
9 };
10 use core::{
11     fmt,
12     sync::atomic::{AtomicU32, Ordering::SeqCst},
13 };
14 #[cfg(feature = "std")]
15 use std::backtrace::BacktraceStatus;
16 use wasmtime_internal_core::error::{
17     Context, Error, OutOfMemory, Result, bail, ensure, format_err,
18 };
19 
20 #[derive(Debug)]
21 struct TestError(u32);
22 
23 impl fmt::Display for TestError {
24     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25         fmt::Debug::fmt(self, f)
26     }
27 }
28 
29 impl core::error::Error for TestError {}
30 
31 #[derive(Debug)]
32 struct CountDrops(Arc<AtomicU32>);
33 
34 impl CountDrops {
35     fn new(drops: &Arc<AtomicU32>) -> Self {
36         CountDrops(drops.clone())
37     }
38 }
39 
40 impl Drop for CountDrops {
41     fn drop(&mut self) {
42         self.0.fetch_add(1, SeqCst);
43     }
44 }
45 
46 impl fmt::Display for CountDrops {
47     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48         fmt::Debug::fmt(self, f)
49     }
50 }
51 
52 impl core::error::Error for CountDrops {}
53 
54 #[derive(Debug)]
55 struct ChainError {
56     message: String,
57     source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
58 }
59 
60 impl fmt::Display for ChainError {
61     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62         f.write_str(&self.message)
63     }
64 }
65 
66 impl core::error::Error for ChainError {
67     fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
68         let source = self.source.as_ref()?;
69         Some(&**source)
70     }
71 }
72 
73 impl ChainError {
74     fn new(
75         message: impl Into<String>,
76         source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
77     ) -> Self {
78         let message = message.into();
79         Self { message, source }
80     }
81 }
82 
83 #[test]
84 fn new() {
85     let mut error = Error::new(TestError(42));
86     assert!(error.is::<TestError>());
87     assert_eq!(error.downcast_ref::<TestError>().unwrap().0, 42);
88     error.downcast_mut::<TestError>().unwrap().0 += 1;
89     assert_eq!(error.downcast_ref::<TestError>().unwrap().0, 43);
90 }
91 
92 #[test]
93 fn new_drops() {
94     let drops = Arc::new(AtomicU32::new(0));
95     let error = Error::new(CountDrops::new(&drops));
96     assert_eq!(drops.load(SeqCst), 0);
97     drop(error);
98     assert_eq!(drops.load(SeqCst), 1);
99 }
100 
101 #[test]
102 fn from_error_with_large_align() {
103     // The `{ConcreteError,DynError}::error` fields are not at the same
104     // offset when the concrete error's type requires greater-than-pointer
105     // alignment. Exercise our various conversions and accesses to make sure
106     // that we do the right thing in this case (that is morally cast `*mut
107     // DynError` to `*mut ConcreteError<E>` rather than casting `*mut
108     // TypeErasedError` to `*mut E`).
109     #[derive(Debug)]
110     #[repr(align(16))]
111     struct LargeAlign {
112         value: u128,
113     }
114 
115     impl fmt::Display for LargeAlign {
116         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117             fmt::Debug::fmt(self, f)
118         }
119     }
120 
121     impl core::error::Error for LargeAlign {}
122 
123     let value = 0x1234_6578_1234_5678_1234_6578_1234_5678;
124     let error = Error::from(LargeAlign { value });
125     assert!(error.is::<LargeAlign>());
126     assert_eq!(error.downcast_ref::<LargeAlign>().unwrap().value, value);
127 }
128 
129 #[test]
130 fn msg() {
131     let error = Error::msg("uh oh!");
132     assert!(error.is::<&str>());
133     let msg = error.to_string();
134     assert_eq!(msg, "uh oh!");
135 }
136 
137 #[test]
138 fn msg_drops() {
139     let drops = Arc::new(AtomicU32::new(0));
140     let error = Error::msg(CountDrops::new(&drops));
141     assert_eq!(drops.load(SeqCst), 0);
142     drop(error);
143     assert_eq!(drops.load(SeqCst), 1);
144 }
145 
146 #[test]
147 fn from_error() {
148     let error = Error::from(TestError(42));
149     assert!(error.is::<TestError>());
150     assert_eq!(error.downcast_ref::<TestError>().unwrap().0, 42);
151 }
152 
153 #[test]
154 fn into_boxed_dyn_error() {
155     let error = ChainError::new("ouch", None);
156     let error = ChainError::new("whoops", Some(Box::new(error)));
157     let error = Error::new(error).context("yikes");
158 
159     let error = error.into_boxed_dyn_error();
160     assert_eq!(error.to_string(), "yikes");
161 
162     let error = error.source().unwrap();
163     assert_eq!(error.to_string(), "whoops");
164 
165     let error = error.source().unwrap();
166     assert_eq!(error.to_string(), "ouch");
167 
168     assert!(error.source().is_none());
169 }
170 
171 #[test]
172 fn is() {
173     // `is<T>` is true for `Error::msg(T)`
174     let e = Error::msg("str");
175     assert!(e.is::<&str>());
176     assert!(!e.is::<TestError>());
177     assert!(!e.is::<OutOfMemory>());
178 
179     // `is<T>` is true for `T` in the context chain.
180     let e = e.context(TestError(42));
181     assert!(e.is::<&str>());
182     assert!(e.is::<TestError>());
183     assert!(!e.is::<OutOfMemory>());
184 
185     // `is<T>` is still true when there are multiple `T`s and `U`s in the
186     // chain.
187     let e = e.context(TestError(36)).context("another str");
188     assert!(e.is::<&str>());
189     assert!(e.is::<TestError>());
190     assert!(!e.is::<OutOfMemory>());
191 
192     // `is<T>` is true for `Error::from(T)`.
193     let e = Error::from(TestError(36));
194     assert!(e.is::<TestError>());
195     assert!(!e.is::<&str>());
196     assert!(!e.is::<OutOfMemory>());
197 
198     // `is<T>` is true for `Error::from(OutOfMemory)`.
199     let e = Error::from(OutOfMemory::new(5));
200     assert!(e.is::<OutOfMemory>());
201     assert!(!e.is::<TestError>());
202     assert!(!e.is::<&str>());
203 }
204 
205 #[test]
206 fn is_for_root_cause_with_initial_error_source() {
207     let error = std::fmt::Error;
208     let error = ChainError::new("whoops", Some(Box::new(error)));
209     let error = Error::new(error);
210     assert!(error.root_cause().is::<std::fmt::Error>());
211 }
212 
213 #[test]
214 #[cfg(feature = "backtrace")]
215 fn backtrace() {
216     // Backtrace on OOM.
217     let e = Error::from(OutOfMemory::new(5));
218     assert_eq!(e.backtrace().status(), BacktraceStatus::Disabled);
219 
220     let backtraces_enabled =
221         match std::env::var("RUST_LIB_BACKTRACE").or_else(|_| std::env::var("RUST_BACKTRACE")) {
222             Err(_) => false,
223             Ok(s) if s == "0" => false,
224             Ok(_) => true,
225         };
226 
227     let assert_backtrace = |e: Error| {
228         if backtraces_enabled {
229             assert!(matches!(
230                 e.backtrace().status(),
231                 BacktraceStatus::Unsupported | BacktraceStatus::Captured
232             ));
233         } else {
234             assert_eq!(e.backtrace().status(), BacktraceStatus::Disabled);
235         }
236     };
237 
238     // Backtrace on `Error::msg`.
239     assert_backtrace(Error::msg("whoops"));
240 
241     // Backtrace on `Error::new`.
242     assert_backtrace(Error::new(TestError(42)));
243 
244     // Backtrace on context chain.
245     assert_backtrace(Error::new(TestError(42)).context("yikes"));
246 }
247 
248 #[test]
249 fn format_err_macro_string_literal() {
250     let error = format_err!("literal");
251     assert_eq!(error.to_string(), "literal");
252 }
253 
254 #[test]
255 fn format_err_macro_format_implicit_args() {
256     let x = 42;
257     let y = 36;
258     let error = format_err!("implicit args {x} {y}");
259     assert_eq!(error.to_string(), "implicit args 42 36");
260 }
261 
262 #[test]
263 fn format_err_macro_format_explicit_args() {
264     let a = 84;
265     let b = 72;
266     let error = format_err!("explicit args {x} {y}", x = a / 2, y = b / 2);
267     assert_eq!(error.to_string(), "explicit args 42 36");
268 }
269 
270 #[test]
271 fn format_err_macro_core_error() {
272     let error = TestError(42);
273     let error = format_err!(error);
274     assert!(error.is::<TestError>());
275     assert_eq!(error.to_string(), "TestError(42)");
276 }
277 
278 #[test]
279 fn format_err_macro_core_error_chain() {
280     let error = ChainError::new("ouch", None);
281     let error = ChainError::new("yikes", Some(Box::new(error)));
282     let error = ChainError::new("whoops", Some(Box::new(error)));
283     let error = format_err!(error);
284 
285     let mut chain = error.chain();
286 
287     let e = chain.next().unwrap();
288     assert_eq!(e.to_string(), "whoops");
289 
290     let e = chain.next().unwrap();
291     assert_eq!(e.to_string(), "yikes");
292 
293     let e = chain.next().unwrap();
294     assert_eq!(e.to_string(), "ouch");
295 
296     assert!(chain.next().is_none());
297 }
298 
299 #[test]
300 fn format_err_macro_msg() {
301     let error = 42;
302     let error = format_err!(error);
303     assert_eq!(error.to_string(), "42");
304 }
305 
306 #[test]
307 #[cfg(feature = "anyhow")]
308 fn format_err_is_anyhow() {
309     let error: anyhow::Error = anyhow::anyhow!("oof");
310     let error: Error = format_err!(error);
311     assert!(error.is::<anyhow::Error>());
312     assert_eq!(error.to_string(), "oof");
313 }
314 
315 #[test]
316 fn bail_macro() {
317     fn bail_string_literal() -> Result<()> {
318         bail!("whoops")
319     }
320     assert_eq!(bail_string_literal().unwrap_err().to_string(), "whoops");
321 
322     fn bail_format_implicit(x: u32) -> Result<()> {
323         bail!("yikes {x}")
324     }
325     assert_eq!(
326         bail_format_implicit(42).unwrap_err().to_string(),
327         "yikes 42"
328     );
329 
330     fn bail_format_explicit(y: u32) -> Result<()> {
331         bail!("ouch {}", y + 1)
332     }
333     assert_eq!(bail_format_explicit(35).unwrap_err().to_string(), "ouch 36");
334 
335     fn bail_core_error() -> Result<()> {
336         bail!(TestError(13))
337     }
338     assert_eq!(bail_core_error().unwrap_err().to_string(), "TestError(13)");
339 
340     fn bail_display() -> Result<()> {
341         let x = 1337;
342         bail!(x)
343     }
344     assert_eq!(bail_display().unwrap_err().to_string(), "1337");
345 }
346 
347 #[test]
348 fn ensure_macro() {
349     fn ensure_string_literal(c: bool) -> Result<()> {
350         ensure!(c, "whoops");
351         Ok(())
352     }
353     assert!(ensure_string_literal(true).is_ok());
354     assert_eq!(
355         ensure_string_literal(false).unwrap_err().to_string(),
356         "whoops"
357     );
358 
359     fn ensure_format_implicit(c: bool, x: u32) -> Result<()> {
360         ensure!(c, "yikes {x}");
361         Ok(())
362     }
363     assert!(ensure_format_implicit(true, 42).is_ok());
364     assert_eq!(
365         ensure_format_implicit(false, 42).unwrap_err().to_string(),
366         "yikes 42"
367     );
368 
369     fn ensure_format_explicit(c: bool, y: u32) -> Result<()> {
370         ensure!(c, "ouch {}", y + 1);
371         Ok(())
372     }
373     assert!(ensure_format_explicit(true, 35).is_ok());
374     assert_eq!(
375         ensure_format_explicit(false, 35).unwrap_err().to_string(),
376         "ouch 36"
377     );
378 
379     fn ensure_core_error(c: bool) -> Result<()> {
380         ensure!(c, TestError(13));
381         Ok(())
382     }
383     assert!(ensure_core_error(true).is_ok());
384     assert_eq!(
385         ensure_core_error(false).unwrap_err().to_string(),
386         "TestError(13)"
387     );
388 
389     fn ensure_display(c: bool) -> Result<()> {
390         let x = 1337;
391         ensure!(c, x);
392         Ok(())
393     }
394     assert!(ensure_display(true).is_ok());
395     assert_eq!(ensure_display(false).unwrap_err().to_string(), "1337");
396 
397     fn ensure_bool_ref(c: &bool) -> Result<()> {
398         ensure!(c, "whoops");
399         Ok(())
400     }
401     assert!(ensure_bool_ref(&true).is_ok());
402     assert_eq!(ensure_bool_ref(&false).unwrap_err().to_string(), "whoops");
403 
404     fn ensure_no_message(a: u32) -> Result<()> {
405         ensure!(a == 42);
406         Ok(())
407     }
408     assert!(ensure_no_message(42).is_ok());
409     assert_eq!(
410         ensure_no_message(0).unwrap_err().to_string(),
411         "Condition failed: `a == 42`"
412     );
413 }
414 
415 #[test]
416 fn downcast() {
417     // Error::msg(T)
418     let error = Error::msg("uh oh");
419     let error = error.downcast::<TestError>().unwrap_err();
420     let error = error.downcast::<OutOfMemory>().unwrap_err();
421     assert_eq!(error.downcast::<&str>().unwrap(), "uh oh");
422 
423     // Error::new()
424     let error = Error::new(TestError(42));
425     let error = error.downcast::<&str>().unwrap_err();
426     let error = error.downcast::<OutOfMemory>().unwrap_err();
427     assert_eq!(error.downcast::<TestError>().unwrap().0, 42);
428 
429     // Error::from(oom)
430     let error = Error::from(OutOfMemory::new(5));
431     let error = error.downcast::<&str>().unwrap_err();
432     let error = error.downcast::<TestError>().unwrap_err();
433     assert!(error.downcast::<OutOfMemory>().is_ok());
434 
435     // First in context chain.
436     let error = Error::new(TestError(42))
437         .context("yikes")
438         .context(OutOfMemory::new(5));
439     let error = error.downcast::<String>().unwrap_err();
440     assert!(error.downcast::<OutOfMemory>().is_ok());
441 
442     // Middle in context chain.
443     let error = Error::new(TestError(42))
444         .context("yikes")
445         .context(OutOfMemory::new(5));
446     let error = error.downcast::<String>().unwrap_err();
447     assert_eq!(error.downcast::<&str>().unwrap(), "yikes");
448 
449     // Last in context chain.
450     let error = Error::new(TestError(42))
451         .context("yikes")
452         .context(OutOfMemory::new(5));
453     let error = error.downcast::<String>().unwrap_err();
454     assert_eq!(error.downcast::<TestError>().unwrap().0, 42);
455 
456     // Multiple `T`s in the context chain gives the first one.
457     let error = Error::new(TestError(42)).context(TestError(36));
458     assert_eq!(error.downcast::<TestError>().unwrap().0, 36);
459 }
460 
461 #[test]
462 fn downcast_drops_everything() {
463     // Error::new
464     let drops = Arc::new(AtomicU32::new(0));
465     let error = Error::new(CountDrops::new(&drops))
466         .context(CountDrops::new(&drops))
467         .context(CountDrops::new(&drops));
468     assert_eq!(drops.load(SeqCst), 0);
469     let c = error.downcast::<CountDrops>().unwrap();
470     assert_eq!(drops.load(SeqCst), 2);
471     drop(c);
472     assert_eq!(drops.load(SeqCst), 3);
473 
474     // Error::msg
475     let drops = Arc::new(AtomicU32::new(0));
476     let error = Error::msg(CountDrops(drops.clone()))
477         .context(CountDrops(drops.clone()))
478         .context(CountDrops(drops.clone()));
479     assert_eq!(drops.load(SeqCst), 0);
480     let c = error.downcast::<CountDrops>().unwrap();
481     assert_eq!(drops.load(SeqCst), 2);
482     drop(c);
483     assert_eq!(drops.load(SeqCst), 3);
484 }
485 
486 #[test]
487 fn downcast_ref() {
488     // `Error::msg(T)`
489     let e = Error::msg("str");
490     assert_eq!(e.downcast_ref::<&str>().copied().unwrap(), "str");
491     assert!(e.downcast_ref::<TestError>().is_none());
492     assert!(e.downcast_ref::<OutOfMemory>().is_none());
493 
494     // Context chain.
495     let e = e.context(TestError(42));
496     assert_eq!(e.downcast_ref::<&str>().copied().unwrap(), "str");
497     assert_eq!(e.downcast_ref::<TestError>().unwrap().0, 42);
498     assert!(e.downcast_ref::<OutOfMemory>().is_none());
499 
500     // Multiple `T`s in the context chain gives you the first one.
501     let e = e.context("another str");
502     assert_eq!(e.downcast_ref::<&str>().copied().unwrap(), "another str");
503     assert_eq!(e.downcast_ref::<TestError>().unwrap().0, 42);
504     assert!(e.downcast_ref::<OutOfMemory>().is_none());
505 
506     // `Error::from(T)`
507     let e = Error::from(TestError(36));
508     assert_eq!(e.downcast_ref::<TestError>().unwrap().0, 36);
509     assert!(e.downcast_ref::<&str>().is_none());
510     assert!(e.downcast_ref::<OutOfMemory>().is_none());
511 
512     // `Error::from(OutOfMemory)`
513     let e = Error::from(OutOfMemory::new(5));
514     assert!(e.downcast_ref::<OutOfMemory>().is_some());
515     assert!(e.downcast_ref::<TestError>().is_none());
516     assert!(e.downcast_ref::<&str>().is_none());
517 }
518 
519 #[test]
520 fn downcast_mut() {
521     // `Error::msg(T)`
522     let mut e = Error::msg("str");
523     assert!(e.downcast_mut::<TestError>().is_none());
524     assert!(e.downcast_mut::<OutOfMemory>().is_none());
525     *e.downcast_mut::<&str>().unwrap() = "whoops";
526     assert_eq!(*e.downcast_ref::<&str>().unwrap(), "whoops");
527 
528     // Context chain.
529     let mut e = e.context(TestError(42));
530     assert!(e.downcast_mut::<OutOfMemory>().is_none());
531     *e.downcast_mut::<&str>().unwrap() = "uh oh";
532     assert_eq!(*e.downcast_ref::<&str>().unwrap(), "uh oh");
533     e.downcast_mut::<TestError>().unwrap().0 += 1;
534     assert_eq!(e.downcast_ref::<TestError>().unwrap().0, 43);
535 
536     // Multiple `T`s in the context chain gives you the first one.
537     let mut e = e.context("another str");
538     *e.downcast_mut::<&str>().unwrap() = "yikes";
539     assert_eq!(*e.downcast_ref::<&str>().unwrap(), "yikes");
540     assert_eq!(format!("{e:#}"), "yikes: TestError(43): uh oh");
541 
542     // `Error::from(T)`
543     let mut e = Error::from(TestError(36));
544     assert!(e.downcast_mut::<&str>().is_none());
545     assert!(e.downcast_mut::<OutOfMemory>().is_none());
546     e.downcast_mut::<TestError>().unwrap().0 += 1;
547     assert_eq!(e.downcast_ref::<TestError>().unwrap().0, 37);
548 
549     // `Error::from(OutOfMemory)`
550     let mut e = Error::from(OutOfMemory::new(5));
551     assert!(e.downcast_mut::<OutOfMemory>().is_some());
552     assert!(e.downcast_mut::<TestError>().is_none());
553     assert!(e.downcast_mut::<&str>().is_none());
554 }
555 
556 #[test]
557 fn context_on_oom() {
558     let error = Error::new(OutOfMemory::new(5));
559     let error = error.context("yikes");
560     assert!(error.is::<OutOfMemory>());
561     assert!(
562         !error.is::<&str>(),
563         "shouldn't attempt to box up more context when we've already exhausted memory"
564     );
565 }
566 
567 #[test]
568 fn context_on_ok_result() {
569     let result: Result<u32> = Ok(42);
570     let result = result.context("uh oh").context(TestError(1337));
571     assert_eq!(result.unwrap(), 42);
572 }
573 
574 #[test]
575 fn context_on_err_result() {
576     let result: Result<u32> = Err(Error::new(TestError(42))).context("uh oh");
577     let error = result.unwrap_err();
578 
579     assert!(error.is::<TestError>());
580     assert_eq!(error.downcast_ref::<TestError>().unwrap().0, 42);
581 
582     assert!(error.is::<&str>());
583     assert_eq!(error.downcast_ref::<&str>().copied().unwrap(), "uh oh");
584 }
585 
586 #[test]
587 fn context_on_some_option() {
588     let option = Some(42);
589     let result = option.context("uh oh").context(TestError(1337));
590     assert_eq!(result.unwrap(), 42);
591 }
592 
593 #[test]
594 fn context_on_none_option() {
595     let option: Option<u32> = None;
596     let result = option.context(TestError(42)).context("uh oh");
597     let error = result.unwrap_err();
598 
599     assert!(error.is::<TestError>());
600     assert_eq!(error.downcast_ref::<TestError>().unwrap().0, 42);
601 
602     assert!(error.is::<&str>());
603     assert_eq!(error.downcast_ref::<&str>().copied().unwrap(), "uh oh");
604 }
605 
606 #[test]
607 fn with_context_on_ok_result() {
608     let result: Result<u32> = Ok(42);
609     let result = result
610         .with_context(|| "uh oh")
611         .with_context(|| TestError(36));
612     assert_eq!(result.unwrap(), 42);
613 }
614 
615 #[test]
616 fn with_context_on_err_result() {
617     let result: Result<u32> = Err(Error::new(TestError(36)));
618     let result = result.with_context(|| "uh oh");
619     let error = result.unwrap_err();
620 
621     assert!(error.is::<TestError>());
622     assert!(error.is::<&str>());
623     assert_eq!(error.downcast_ref::<&str>().copied().unwrap(), "uh oh");
624 }
625 
626 #[test]
627 fn with_context_on_some_option() {
628     let option = Some(36);
629     let result = option
630         .with_context(|| "uh oh")
631         .with_context(|| TestError(42));
632     assert_eq!(result.unwrap(), 36);
633 }
634 
635 #[test]
636 fn with_context_on_none_option() {
637     let option: Option<u32> = None;
638     let result = option
639         .with_context(|| "uh oh")
640         .with_context(|| TestError(42));
641     let error = result.unwrap_err();
642 
643     assert!(error.is::<&str>());
644     assert_eq!(error.downcast_ref::<&str>().copied().unwrap(), "uh oh");
645 
646     assert!(error.is::<TestError>());
647     assert_eq!(error.downcast_ref::<TestError>().unwrap().0, 42);
648 }
649 
650 #[test]
651 fn fmt_debug() {
652     let error = Error::msg("whoops").context("uh oh").context("yikes");
653     let actual = format!("{error:?}");
654 
655     let expected = "\
656 yikes
657 
658 Caused by:
659     0: uh oh
660     1: whoops
661 ";
662 
663     #[cfg(feature = "backtrace")]
664     {
665         assert!(actual.starts_with(expected));
666         if let BacktraceStatus::Captured = error.backtrace().status() {
667             assert!(actual.contains("Stack backtrace:"));
668         }
669     }
670 
671     #[cfg(not(feature = "backtrace"))]
672     {
673         assert_eq!(actual, expected);
674     }
675 }
676 #[test]
677 fn fmt_debug_with_single_cause() {
678     let error = Error::msg("whoops").context("uh oh");
679     let actual = format!("{error:?}");
680 
681     // NB: the causes are only numbered when there are multiple of them.
682     let expected = "\
683 uh oh
684 
685 Caused by:
686     whoops
687 ";
688 
689     #[cfg(feature = "backtrace")]
690     {
691         assert!(actual.starts_with(expected));
692         if let BacktraceStatus::Captured = error.backtrace().status() {
693             assert!(actual.contains("Stack backtrace:"));
694         }
695     }
696 
697     #[cfg(not(feature = "backtrace"))]
698     {
699         assert_eq!(actual, expected);
700     }
701 }
702 
703 #[test]
704 fn fmt_debug_alternate() {
705     let error = ChainError::new("root cause", None);
706     let error = ChainError::new("whoops", Some(Box::new(error)));
707     let error = Error::new(error)
708         .context(TestError(42))
709         .context("yikes")
710         .context("ouch");
711 
712     let actual = format!("{error:#?}");
713     let actual = actual.trim();
714     println!("actual `{{:#?}}` output:\n{actual}");
715 
716     let expected = r#"
717 Error {
718     inner: DynError {
719         error: ouch,
720         source: DynError {
721             error: yikes,
722             source: DynError {
723                 error: TestError(
724                     42,
725                 ),
726                 source: DynError {
727                     error: ChainError {
728                         message: "whoops",
729                         source: Some(
730                             ChainError {
731                                 message: "root cause",
732                                 source: None,
733                             },
734                         ),
735                     },
736                 },
737             },
738         },
739     },
740 }
741     "#
742     .trim();
743     println!("expected `{{:#?}}` output:\n{expected}");
744 
745     assert_eq!(actual, expected);
746 }
747 
748 #[test]
749 fn fmt_debug_alternate_with_oom() {
750     let error = Error::new(OutOfMemory::new(5));
751 
752     let actual = format!("{error:#?}");
753     let actual = actual.trim();
754     println!("actual `{{:#?}}` output:\n{actual}");
755 
756     let expected = r#"
757 Error {
758     inner: Oom(
759         OutOfMemory {
760             requested_allocation_size: 5,
761         },
762     ),
763 }
764     "#
765     .trim();
766     println!("expected `{{:#?}}` output:\n{expected}");
767 
768     assert_eq!(actual, expected);
769 }
770 
771 #[test]
772 fn fmt_display() {
773     let error = Error::msg("whoops").context("uh oh").context("yikes");
774     assert_eq!(format!("{error}"), "yikes");
775 }
776 
777 #[test]
778 fn fmt_display_alternate() {
779     let error = Error::msg("ouch")
780         .context("whoops")
781         .context("uh oh")
782         .context("yikes");
783     assert_eq!(format!("{error:#}"), "yikes: uh oh: whoops: ouch");
784 }
785 
786 #[test]
787 fn chain() {
788     let error = Error::msg("failure")
789         .context("uh oh")
790         .context(TestError(42));
791 
792     let mut chain = error.chain();
793 
794     let e = chain.next().unwrap();
795     assert_eq!(e.to_string(), "TestError(42)");
796 
797     let e = chain.next().unwrap();
798     assert_eq!(e.to_string(), "uh oh");
799 
800     let e = chain.next().unwrap();
801     assert_eq!(e.to_string(), "failure");
802 
803     assert!(chain.next().is_none());
804 
805     for _ in 0..100 {
806         assert!(chain.next().is_none(), "`Chain` is a fused iterator");
807     }
808 }
809 
810 #[test]
811 fn chain_on_error_with_source() {
812     let error = ChainError::new("yikes", None);
813     let error = ChainError::new("whoops", Some(Box::new(error)));
814     let error = ChainError::new("uh oh", Some(Box::new(error)));
815     let error = Error::new(error).context("ouch").context("oof");
816 
817     let mut chain = error.chain();
818 
819     let e = chain.next().unwrap();
820     assert_eq!(e.to_string(), "oof");
821 
822     let e = chain.next().unwrap();
823     assert_eq!(e.to_string(), "ouch");
824 
825     let e = chain.next().unwrap();
826     assert_eq!(e.to_string(), "uh oh");
827 
828     let e = chain.next().unwrap();
829     assert_eq!(e.to_string(), "whoops");
830 
831     let e = chain.next().unwrap();
832     assert_eq!(e.to_string(), "yikes");
833 
834     assert!(chain.next().is_none());
835 }
836 
837 #[test]
838 fn root_cause() {
839     let error = ChainError::new("yikes", None);
840     let error = ChainError::new("whoops", Some(Box::new(error)));
841     let error = ChainError::new("uh oh", Some(Box::new(error)));
842     let error = Error::new(error).context("ouch").context("oof");
843     let root = error.root_cause();
844     assert_eq!(root.to_string(), "yikes");
845     assert!(root.source().is_none());
846 }
847 
848 #[test]
849 fn chain_with_leaf_sources() {
850     #[derive(Debug)]
851     struct ErrorWithSource(String, Box<dyn core::error::Error + Send + Sync + 'static>);
852 
853     impl fmt::Display for ErrorWithSource {
854         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
855             f.write_str(&self.0)
856         }
857     }
858 
859     impl core::error::Error for ErrorWithSource {
860         fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
861             Some(&*self.1)
862         }
863     }
864 
865     let error = Error::new(ErrorWithSource("leaf".to_string(), Box::new(TestError(42))))
866         .context("oof")
867         .context("wow");
868 
869     let mut chain = error.chain();
870 
871     let e = chain.next().unwrap();
872     assert_eq!(e.to_string(), "wow");
873 
874     let e = chain.next().unwrap();
875     assert_eq!(e.to_string(), "oof");
876 
877     let e = chain.next().unwrap();
878     assert_eq!(e.to_string(), "leaf");
879 
880     let e = chain.next().unwrap();
881     assert_eq!(e.to_string(), "TestError(42)");
882 
883     assert!(chain.next().is_none());
884 }
885 
886 #[test]
887 fn oom_requested_allocation_size() {
888     // Check that a bunch of interesting allocation sizes roundtrip.
889     for shift in 0..30 {
890         let bytes = (1 << shift) - 1;
891         let oom = OutOfMemory::new(bytes);
892         assert_eq!(oom.requested_allocation_size(), bytes);
893 
894         let bytes = 1 << shift;
895         let oom = OutOfMemory::new(bytes);
896         assert_eq!(oom.requested_allocation_size(), bytes);
897 
898         let bytes = (1 << shift) + 1;
899         let oom = OutOfMemory::new(bytes);
900         assert_eq!(oom.requested_allocation_size(), bytes);
901     }
902 
903     // We will round down if the allocation size is too large, but make no
904     // specific guarantees about that behavior.
905     let oom = OutOfMemory::new(usize::MAX);
906     assert!(oom.requested_allocation_size() <= usize::try_from(isize::MAX).unwrap());
907 }
908