1 #![allow(
2 // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
3 clippy::nonstandard_macro_braces,
4 )]
5
6 mod drop;
7
8 use crate::drop::{DetectDrop, Flag};
9 use anyhow::{Context, Error, Result};
10 use std::fmt::{self, Display};
11 use thiserror::Error;
12
13 // https://github.com/dtolnay/anyhow/issues/18
14 #[test]
test_inference() -> Result<()>15 fn test_inference() -> Result<()> {
16 let x = "1";
17 let y: u32 = x.parse().context("...")?;
18 assert_eq!(y, 1);
19 Ok(())
20 }
21
22 macro_rules! context_type {
23 ($name:ident) => {
24 #[derive(Debug)]
25 struct $name {
26 message: &'static str,
27 #[allow(dead_code)]
28 drop: DetectDrop,
29 }
30
31 impl Display for $name {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 f.write_str(self.message)
34 }
35 }
36 };
37 }
38
39 context_type!(HighLevel);
40 context_type!(MidLevel);
41
42 #[derive(Error, Debug)]
43 #[error("{message}")]
44 struct LowLevel {
45 message: &'static str,
46 drop: DetectDrop,
47 }
48
49 struct Dropped {
50 low: Flag,
51 mid: Flag,
52 high: Flag,
53 }
54
55 impl Dropped {
none(&self) -> bool56 fn none(&self) -> bool {
57 !self.low.get() && !self.mid.get() && !self.high.get()
58 }
59
all(&self) -> bool60 fn all(&self) -> bool {
61 self.low.get() && self.mid.get() && self.high.get()
62 }
63 }
64
make_chain() -> (Error, Dropped)65 fn make_chain() -> (Error, Dropped) {
66 let dropped = Dropped {
67 low: Flag::new(),
68 mid: Flag::new(),
69 high: Flag::new(),
70 };
71
72 let low = LowLevel {
73 message: "no such file or directory",
74 drop: DetectDrop::new(&dropped.low),
75 };
76
77 // impl Context for Result<T, E>
78 let mid = Err::<(), LowLevel>(low)
79 .context(MidLevel {
80 message: "failed to load config",
81 drop: DetectDrop::new(&dropped.mid),
82 })
83 .unwrap_err();
84
85 // impl Context for Result<T, Error>
86 let high = Err::<(), Error>(mid)
87 .context(HighLevel {
88 message: "failed to start server",
89 drop: DetectDrop::new(&dropped.high),
90 })
91 .unwrap_err();
92
93 (high, dropped)
94 }
95
96 #[test]
test_downcast_ref()97 fn test_downcast_ref() {
98 let (err, dropped) = make_chain();
99
100 assert!(!err.is::<String>());
101 assert!(err.downcast_ref::<String>().is_none());
102
103 assert!(err.is::<HighLevel>());
104 let high = err.downcast_ref::<HighLevel>().unwrap();
105 assert_eq!(high.to_string(), "failed to start server");
106
107 assert!(err.is::<MidLevel>());
108 let mid = err.downcast_ref::<MidLevel>().unwrap();
109 assert_eq!(mid.to_string(), "failed to load config");
110
111 assert!(err.is::<LowLevel>());
112 let low = err.downcast_ref::<LowLevel>().unwrap();
113 assert_eq!(low.to_string(), "no such file or directory");
114
115 assert!(dropped.none());
116 drop(err);
117 assert!(dropped.all());
118 }
119
120 #[test]
test_downcast_high()121 fn test_downcast_high() {
122 let (err, dropped) = make_chain();
123
124 let err = err.downcast::<HighLevel>().unwrap();
125 assert!(!dropped.high.get());
126 assert!(dropped.low.get() && dropped.mid.get());
127
128 drop(err);
129 assert!(dropped.all());
130 }
131
132 #[test]
test_downcast_mid()133 fn test_downcast_mid() {
134 let (err, dropped) = make_chain();
135
136 let err = err.downcast::<MidLevel>().unwrap();
137 assert!(!dropped.mid.get());
138 assert!(dropped.low.get() && dropped.high.get());
139
140 drop(err);
141 assert!(dropped.all());
142 }
143
144 #[test]
test_downcast_low()145 fn test_downcast_low() {
146 let (err, dropped) = make_chain();
147
148 let err = err.downcast::<LowLevel>().unwrap();
149 assert!(!dropped.low.get());
150 assert!(dropped.mid.get() && dropped.high.get());
151
152 drop(err);
153 assert!(dropped.all());
154 }
155
156 #[test]
test_unsuccessful_downcast()157 fn test_unsuccessful_downcast() {
158 let (err, dropped) = make_chain();
159
160 let err = err.downcast::<String>().unwrap_err();
161 assert!(dropped.none());
162
163 drop(err);
164 assert!(dropped.all());
165 }
166
167 #[test]
test_root_cause()168 fn test_root_cause() {
169 let (err, _) = make_chain();
170
171 assert_eq!(err.root_cause().to_string(), "no such file or directory");
172 }
173