xref: /wasmtime-44.0.1/crates/core/tests/tests.rs (revision 5afb6030)
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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result24     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 {
new(drops: &Arc<AtomicU32>) -> Self35     fn new(drops: &Arc<AtomicU32>) -> Self {
36         CountDrops(drops.clone())
37     }
38 }
39 
40 impl Drop for CountDrops {
drop(&mut self)41     fn drop(&mut self) {
42         self.0.fetch_add(1, SeqCst);
43     }
44 }
45 
46 impl fmt::Display for CountDrops {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result47     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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result61     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 {
source(&self) -> Option<&(dyn core::error::Error + 'static)>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 {
new( message: impl Into<String>, source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>, ) -> Self74     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]
new()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]
new_drops()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]
from_error_with_large_align()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]
msg()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]
msg_drops()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]
from_error()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]
into_boxed_dyn_error()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]
is()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]
is_for_root_cause_with_initial_error_source()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")]
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]
format_err_macro_string_literal()249 fn format_err_macro_string_literal() {
250     let error = format_err!("literal");
251     assert_eq!(error.to_string(), "literal");
252 }
253 
254 #[test]
format_err_macro_format_implicit_args()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]
format_err_macro_format_explicit_args()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]
format_err_macro_core_error()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]
format_err_macro_core_error_chain()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]
format_err_macro_msg()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")]
format_err_is_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]
bail_macro()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]
ensure_macro()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]
downcast()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]
downcast_drops_everything()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]
downcast_ref()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]
downcast_mut()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]
context_on_oom()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]
context_on_ok_result()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]
context_on_err_result()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]
context_on_some_option()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]
context_on_none_option()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]
with_context_on_ok_result()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]
with_context_on_err_result()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]
with_context_on_some_option()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]
with_context_on_none_option()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]
fmt_debug()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]
fmt_debug_with_single_cause()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]
fmt_debug_alternate()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: Error {
721             inner: DynError {
722                 error: yikes,
723                 source: Error {
724                     inner: DynError {
725                         error: TestError(
726                             42,
727                         ),
728                         source: Error {
729                             inner: DynError {
730                                 error: ChainError {
731                                     message: "whoops",
732                                     source: Some(
733                                         ChainError {
734                                             message: "root cause",
735                                             source: None,
736                                         },
737                                     ),
738                                 },
739                             },
740                         },
741                     },
742                 },
743             },
744         },
745     },
746 }
747     "#
748     .trim();
749     println!("expected `{{:#?}}` output:\n{expected}");
750 
751     assert_eq!(actual, expected);
752 }
753 
754 #[test]
fmt_debug_alternate_with_oom()755 fn fmt_debug_alternate_with_oom() {
756     let error = Error::new(OutOfMemory::new(5));
757 
758     let actual = format!("{error:#?}");
759     let actual = actual.trim();
760     println!("actual `{{:#?}}` output:\n{actual}");
761 
762     let expected = r#"
763 Error {
764     inner: Oom(
765         OutOfMemory {
766             requested_allocation_size: 5,
767         },
768     ),
769 }
770     "#
771     .trim();
772     println!("expected `{{:#?}}` output:\n{expected}");
773 
774     assert_eq!(actual, expected);
775 }
776 
777 #[test]
fmt_display()778 fn fmt_display() {
779     let error = Error::msg("whoops").context("uh oh").context("yikes");
780     assert_eq!(format!("{error}"), "yikes");
781 }
782 
783 #[test]
fmt_display_alternate()784 fn fmt_display_alternate() {
785     let error = Error::msg("ouch")
786         .context("whoops")
787         .context("uh oh")
788         .context("yikes");
789     assert_eq!(format!("{error:#}"), "yikes: uh oh: whoops: ouch");
790 }
791 
792 #[test]
chain()793 fn chain() {
794     let error = Error::msg("failure")
795         .context("uh oh")
796         .context(TestError(42));
797 
798     let mut chain = error.chain();
799 
800     let e = chain.next().unwrap();
801     assert_eq!(e.to_string(), "TestError(42)");
802 
803     let e = chain.next().unwrap();
804     assert_eq!(e.to_string(), "uh oh");
805 
806     let e = chain.next().unwrap();
807     assert_eq!(e.to_string(), "failure");
808 
809     assert!(chain.next().is_none());
810 
811     for _ in 0..100 {
812         assert!(chain.next().is_none(), "`Chain` is a fused iterator");
813     }
814 }
815 
816 #[test]
chain_on_error_with_source()817 fn chain_on_error_with_source() {
818     let error = ChainError::new("yikes", None);
819     let error = ChainError::new("whoops", Some(Box::new(error)));
820     let error = ChainError::new("uh oh", Some(Box::new(error)));
821     let error = Error::new(error).context("ouch").context("oof");
822 
823     let mut chain = error.chain();
824 
825     let e = chain.next().unwrap();
826     assert_eq!(e.to_string(), "oof");
827 
828     let e = chain.next().unwrap();
829     assert_eq!(e.to_string(), "ouch");
830 
831     let e = chain.next().unwrap();
832     assert_eq!(e.to_string(), "uh oh");
833 
834     let e = chain.next().unwrap();
835     assert_eq!(e.to_string(), "whoops");
836 
837     let e = chain.next().unwrap();
838     assert_eq!(e.to_string(), "yikes");
839 
840     assert!(chain.next().is_none());
841 }
842 
843 #[test]
root_cause()844 fn root_cause() {
845     let error = ChainError::new("yikes", None);
846     let error = ChainError::new("whoops", Some(Box::new(error)));
847     let error = ChainError::new("uh oh", Some(Box::new(error)));
848     let error = Error::new(error).context("ouch").context("oof");
849     let root = error.root_cause();
850     assert_eq!(root.to_string(), "yikes");
851     assert!(root.source().is_none());
852 }
853 
854 #[test]
chain_with_leaf_sources()855 fn chain_with_leaf_sources() {
856     #[derive(Debug)]
857     struct ErrorWithSource(String, Box<dyn core::error::Error + Send + Sync + 'static>);
858 
859     impl fmt::Display for ErrorWithSource {
860         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
861             f.write_str(&self.0)
862         }
863     }
864 
865     impl core::error::Error for ErrorWithSource {
866         fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
867             Some(&*self.1)
868         }
869     }
870 
871     let error = Error::new(ErrorWithSource("leaf".to_string(), Box::new(TestError(42))))
872         .context("oof")
873         .context("wow");
874 
875     let mut chain = error.chain();
876 
877     let e = chain.next().unwrap();
878     assert_eq!(e.to_string(), "wow");
879 
880     let e = chain.next().unwrap();
881     assert_eq!(e.to_string(), "oof");
882 
883     let e = chain.next().unwrap();
884     assert_eq!(e.to_string(), "leaf");
885 
886     let e = chain.next().unwrap();
887     assert_eq!(e.to_string(), "TestError(42)");
888 
889     assert!(chain.next().is_none());
890 }
891 
892 #[test]
oom_requested_allocation_size()893 fn oom_requested_allocation_size() {
894     // Check that a bunch of interesting allocation sizes roundtrip.
895     for shift in 0..30 {
896         let bytes = (1 << shift) - 1;
897         let oom = OutOfMemory::new(bytes);
898         assert_eq!(oom.requested_allocation_size(), bytes);
899 
900         let bytes = 1 << shift;
901         let oom = OutOfMemory::new(bytes);
902         assert_eq!(oom.requested_allocation_size(), bytes);
903 
904         let bytes = (1 << shift) + 1;
905         let oom = OutOfMemory::new(bytes);
906         assert_eq!(oom.requested_allocation_size(), bytes);
907     }
908 
909     // We will round down if the allocation size is too large, but make no
910     // specific guarantees about that behavior.
911     let oom = OutOfMemory::new(usize::MAX);
912     assert!(oom.requested_allocation_size() <= usize::try_from(isize::MAX).unwrap());
913 }
914 
915 #[test]
916 #[cfg(feature = "anyhow")]
anyhow_preserves_downcast() -> Result<()>917 fn anyhow_preserves_downcast() -> Result<()> {
918     {
919         let e: Error = TestError(1).into();
920         assert!(e.downcast_ref::<TestError>().is_some());
921         let e: anyhow::Error = e.into();
922         assert!(e.downcast_ref::<TestError>().is_some());
923     }
924     {
925         let e = Error::from(TestError(1)).context("hi");
926         assert!(e.downcast_ref::<TestError>().is_some());
927         assert!(e.downcast_ref::<&str>().is_some());
928         let e: anyhow::Error = e.into();
929         assert!(e.downcast_ref::<TestError>().is_some());
930         assert!(e.downcast_ref::<&str>().is_some());
931     }
932     Ok(())
933 }
934 
935 #[test]
936 #[cfg(feature = "anyhow")]
anyhow_source_downcast() -> Result<()>937 fn anyhow_source_downcast() -> Result<()> {
938     let e: anyhow::Error = TestError(1).into();
939     assert!(e.downcast_ref::<TestError>().is_some());
940 
941     let e: Error = Error::from_anyhow(e);
942     assert!(e.downcast_ref::<TestError>().is_some());
943 
944     let e: anyhow::Error = e.into();
945     assert!(e.downcast_ref::<TestError>().is_some());
946     Ok(())
947 }
948 
949 #[cfg(feature = "anyhow")]
assert_chain<T, U>(actual: impl IntoIterator<Item = T>, expected: impl IntoIterator<Item = U>) where T: PartialEq<U>, T: fmt::Debug, U: fmt::Debug,950 fn assert_chain<T, U>(actual: impl IntoIterator<Item = T>, expected: impl IntoIterator<Item = U>)
951 where
952     T: PartialEq<U>,
953     T: fmt::Debug,
954     U: fmt::Debug,
955 {
956     let mut actual = actual.into_iter();
957     let mut expected = expected.into_iter();
958     loop {
959         match (actual.next(), expected.next()) {
960             (None, None) => return,
961             (None, Some(x)) => {
962                 panic!("expected {x:?} next in chain, but actual chain is exhausted")
963             }
964             (Some(x), None) => panic!("expected chain to be exhausted, but found {x:?}"),
965             (Some(x), Some(y)) => assert_eq!(x, y),
966         }
967     }
968 }
969 
970 #[test]
971 #[cfg(feature = "anyhow")]
anyhow_wasmtime_anyhow_sandwich_chain() -> Result<()>972 fn anyhow_wasmtime_anyhow_sandwich_chain() -> Result<()> {
973     let e: anyhow::Error = TestError(1).into();
974     let e = e.context(TestError(2));
975 
976     assert_chain(
977         e.chain().map(|e| e.to_string()),
978         ["TestError(2)", "TestError(1)"],
979     );
980 
981     let e: Error = Error::from_anyhow(e);
982     let e = e.context(TestError(3));
983 
984     assert_chain(
985         e.chain().map(|e| e.to_string()),
986         ["TestError(3)", "TestError(2)", "TestError(1)"],
987     );
988 
989     let e: anyhow::Error = e.into();
990     let e = e.context(TestError(4));
991 
992     assert_chain(
993         e.chain().map(|e| e.to_string()),
994         [
995             "TestError(4)",
996             "TestError(3)",
997             "TestError(2)",
998             "TestError(1)",
999         ],
1000     );
1001 
1002     Ok(())
1003 }
1004 
1005 #[test]
1006 #[cfg(feature = "anyhow")]
wasmtime_anyhow_wasmtime_sandwich_chain() -> Result<()>1007 fn wasmtime_anyhow_wasmtime_sandwich_chain() -> Result<()> {
1008     let e: Error = TestError(1).into();
1009     let e = e.context(TestError(2));
1010 
1011     assert_chain(
1012         e.chain().map(|e| e.to_string()),
1013         ["TestError(2)", "TestError(1)"],
1014     );
1015 
1016     let e: anyhow::Error = e.into();
1017     let e = e.context(TestError(3));
1018 
1019     assert_chain(
1020         e.chain().map(|e| e.to_string()),
1021         ["TestError(3)", "TestError(2)", "TestError(1)"],
1022     );
1023 
1024     let e: Error = Error::from_anyhow(e);
1025     let e = e.context(TestError(4));
1026 
1027     assert_chain(
1028         e.chain().map(|e| e.to_string()),
1029         [
1030             "TestError(4)",
1031             "TestError(3)",
1032             "TestError(2)",
1033             "TestError(1)",
1034         ],
1035     );
1036 
1037     Ok(())
1038 }
1039