1 #![cfg(feature = "toml")]
2 
3 use serde_derive::Deserialize;
4 
5 use std::collections::HashSet;
6 
7 use config::{Config, File, FileFormat, Map, Value};
8 use float_cmp::ApproxEqUlps;
9 
10 #[derive(Debug, Deserialize)]
11 struct Place {
12     name: String,
13     longitude: f64,
14     latitude: f64,
15     favorite: bool,
16     telephone: Option<String>,
17     reviews: u64,
18     rating: Option<f32>,
19 }
20 
21 #[derive(Debug, Deserialize)]
22 struct Settings {
23     debug: f64,
24     production: Option<String>,
25     place: Place,
26 }
27 
make() -> Config28 fn make() -> Config {
29     Config::builder()
30         .add_source(File::new("tests/Settings", FileFormat::Toml))
31         .build()
32         .unwrap()
33 }
34 
35 #[test]
test_not_found()36 fn test_not_found() {
37     let c = make();
38     let res = c.get::<bool>("not_found");
39 
40     assert!(res.is_err());
41     assert_eq!(
42         res.unwrap_err().to_string(),
43         "configuration property \"not_found\" not found".to_string()
44     );
45 }
46 
47 #[test]
test_scalar()48 fn test_scalar() {
49     let c = make();
50 
51     assert_eq!(c.get("debug").ok(), Some(true));
52     assert_eq!(c.get("production").ok(), Some(false));
53 }
54 
55 #[test]
test_scalar_type_loose()56 fn test_scalar_type_loose() {
57     let c = make();
58 
59     assert_eq!(c.get("debug").ok(), Some(true));
60     assert_eq!(c.get("debug").ok(), Some("true".to_string()));
61     assert_eq!(c.get("debug").ok(), Some(1));
62     assert_eq!(c.get("debug").ok(), Some(1.0));
63 
64     assert_eq!(c.get("debug_s").ok(), Some(true));
65     assert_eq!(c.get("debug_s").ok(), Some("true".to_string()));
66     assert_eq!(c.get("debug_s").ok(), Some(1));
67     assert_eq!(c.get("debug_s").ok(), Some(1.0));
68 
69     assert_eq!(c.get("production").ok(), Some(false));
70     assert_eq!(c.get("production").ok(), Some("false".to_string()));
71     assert_eq!(c.get("production").ok(), Some(0));
72     assert_eq!(c.get("production").ok(), Some(0.0));
73 
74     assert_eq!(c.get("production_s").ok(), Some(false));
75     assert_eq!(c.get("production_s").ok(), Some("false".to_string()));
76     assert_eq!(c.get("production_s").ok(), Some(0));
77     assert_eq!(c.get("production_s").ok(), Some(0.0));
78 }
79 
80 #[test]
test_get_scalar_path()81 fn test_get_scalar_path() {
82     let c = make();
83 
84     assert_eq!(c.get("place.favorite").ok(), Some(false));
85     assert_eq!(
86         c.get("place.creator.name").ok(),
87         Some("John Smith".to_string())
88     );
89 }
90 
91 #[test]
test_get_scalar_path_subscript()92 fn test_get_scalar_path_subscript() {
93     let c = make();
94 
95     assert_eq!(c.get("arr[2]").ok(), Some(3));
96     assert_eq!(c.get("items[0].name").ok(), Some("1".to_string()));
97     assert_eq!(c.get("items[1].name").ok(), Some("2".to_string()));
98     assert_eq!(c.get("items[-1].name").ok(), Some("2".to_string()));
99     assert_eq!(c.get("items[-2].name").ok(), Some("1".to_string()));
100 }
101 
102 #[test]
test_map()103 fn test_map() {
104     let c = make();
105     let m: Map<String, Value> = c.get("place").unwrap();
106 
107     assert_eq!(m.len(), 8);
108     assert_eq!(
109         m["name"].clone().into_string().unwrap(),
110         "Torre di Pisa".to_string()
111     );
112     assert_eq!(m["reviews"].clone().into_int().unwrap(), 3866);
113 }
114 
115 #[test]
test_map_str()116 fn test_map_str() {
117     let c = make();
118     let m: Map<String, String> = c.get("place.creator").unwrap();
119 
120     if cfg!(feature = "preserve_order") {
121         assert_eq!(
122             m.into_iter().collect::<Vec<(String, String)>>(),
123             vec![
124                 ("name".to_string(), "John Smith".to_string()),
125                 ("username".to_string(), "jsmith".to_string()),
126                 ("email".to_string(), "jsmith@localhost".to_string()),
127             ]
128         );
129     } else {
130         assert_eq!(m.len(), 3);
131         assert_eq!(m["name"], "John Smith".to_string());
132     }
133 }
134 
135 #[test]
test_map_struct()136 fn test_map_struct() {
137     #[derive(Debug, Deserialize)]
138     struct Settings {
139         place: Map<String, Value>,
140     }
141 
142     let c = make();
143     let s: Settings = c.try_deserialize().unwrap();
144 
145     assert_eq!(s.place.len(), 8);
146     assert_eq!(
147         s.place["name"].clone().into_string().unwrap(),
148         "Torre di Pisa".to_string()
149     );
150     assert_eq!(s.place["reviews"].clone().into_int().unwrap(), 3866);
151 }
152 
153 #[test]
test_file_struct()154 fn test_file_struct() {
155     let c = make();
156 
157     // Deserialize the entire file as single struct
158     let s: Settings = c.try_deserialize().unwrap();
159 
160     assert!(s.debug.approx_eq_ulps(&1.0, 2));
161     assert_eq!(s.production, Some("false".to_string()));
162     assert_eq!(s.place.name, "Torre di Pisa");
163     assert!(s.place.longitude.approx_eq_ulps(&43.722_498_5, 2));
164     assert!(s.place.latitude.approx_eq_ulps(&10.397_052_2, 2));
165     assert!(!s.place.favorite);
166     assert_eq!(s.place.reviews, 3866);
167     assert_eq!(s.place.rating, Some(4.5));
168     assert_eq!(s.place.telephone, None);
169 }
170 
171 #[test]
test_scalar_struct()172 fn test_scalar_struct() {
173     let c = make();
174 
175     // Deserialize a scalar struct that has lots of different
176     // data types
177     let p: Place = c.get("place").unwrap();
178 
179     assert_eq!(p.name, "Torre di Pisa");
180     assert!(p.longitude.approx_eq_ulps(&43.722_498_5, 2));
181     assert!(p.latitude.approx_eq_ulps(&10.397_052_2, 2));
182     assert!(!p.favorite);
183     assert_eq!(p.reviews, 3866);
184     assert_eq!(p.rating, Some(4.5));
185     assert_eq!(p.telephone, None);
186 }
187 
188 #[test]
test_array_scalar()189 fn test_array_scalar() {
190     let c = make();
191     let arr: Vec<i64> = c.get("arr").unwrap();
192 
193     assert_eq!(arr.len(), 10);
194     assert_eq!(arr[3], 4);
195 }
196 
197 #[test]
test_struct_array()198 fn test_struct_array() {
199     #[derive(Debug, Deserialize)]
200     struct Settings {
201         #[serde(rename = "arr")]
202         elements: Vec<String>,
203     }
204 
205     let c = make();
206     let s: Settings = c.try_deserialize().unwrap();
207 
208     assert_eq!(s.elements.len(), 10);
209     assert_eq!(s.elements[3], "4".to_string());
210 }
211 
212 #[test]
test_enum()213 fn test_enum() {
214     #[derive(Debug, Deserialize, PartialEq)]
215     #[serde(rename_all = "lowercase")]
216     enum Diode {
217         Off,
218         Brightness(i32),
219         Blinking(i32, i32),
220         Pattern { name: String, inifinite: bool },
221     }
222     #[derive(Debug, Deserialize)]
223     struct Settings {
224         diodes: Map<String, Diode>,
225     }
226 
227     let c = make();
228     let s: Settings = c.try_deserialize().unwrap();
229 
230     assert_eq!(s.diodes["green"], Diode::Off);
231     assert_eq!(s.diodes["red"], Diode::Brightness(100));
232     assert_eq!(s.diodes["blue"], Diode::Blinking(300, 700));
233     assert_eq!(
234         s.diodes["white"],
235         Diode::Pattern {
236             name: "christmas".into(),
237             inifinite: true,
238         }
239     );
240 }
241 
242 #[test]
test_enum_key()243 fn test_enum_key() {
244     #[derive(Debug, Deserialize, PartialEq, Eq, Hash)]
245     #[serde(rename_all = "lowercase")]
246     enum Quark {
247         Up,
248         Down,
249         Strange,
250         Charm,
251         Bottom,
252         Top,
253     }
254 
255     #[derive(Debug, Deserialize)]
256     struct Settings {
257         proton: Map<Quark, usize>,
258         // Just to make sure that set keys work too.
259         quarks: HashSet<Quark>,
260     }
261 
262     let c = make();
263     let s: Settings = c.try_deserialize().unwrap();
264 
265     assert_eq!(s.proton[&Quark::Up], 2);
266     assert_eq!(s.quarks.len(), 6);
267 }
268 
269 #[test]
test_int_key()270 fn test_int_key() {
271     #[derive(Debug, Deserialize, PartialEq)]
272     struct Settings {
273         divisors: Map<u32, u32>,
274     }
275 
276     let c = make();
277     let s: Settings = c.try_deserialize().unwrap();
278     assert_eq!(s.divisors[&4], 3);
279     assert_eq!(s.divisors.len(), 4);
280 }
281