Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/core/tests/tests.rs
3071 views
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
909