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