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