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