1 use configparser::ini::{Ini, WriteOptions};
2 use std::error::Error;
3
4 #[test]
5 #[allow(clippy::approx_constant)]
non_cs() -> Result<(), Box<dyn Error>>6 fn non_cs() -> Result<(), Box<dyn Error>> {
7 let mut config = Ini::new();
8 let map = config.load("tests/test.ini")?;
9 config.set_comment_symbols(&[';', '#', '!']);
10 let inpstring = config.read(
11 "defaultvalues=defaultvalues
12 [topsecret]
13 KFC = the secret herb is orega-
14 colon:value after colon
15 Empty string =
16 None string
17 Password=[in-brackets]
18 [ spacing ]
19 indented=indented
20 not indented = not indented ;testcomment
21 !modified comment
22 [values]#another comment
23 Bool = True
24 Boolcoerce = 0
25 Int = -31415
26 Uint = 31415
27 Float = 3.1415"
28 .to_owned(),
29 )?;
30 assert_eq!(map, inpstring);
31 config.set("DEFAULT", "defaultvalues", Some("notdefault".to_owned()));
32 assert_eq!(
33 config.get("DEFAULT", "defaultvalues").unwrap(),
34 "notdefault"
35 );
36 config.setstr("DEFAULT", "defaultvalues", Some("defaultvalues"));
37 assert_eq!(
38 config.get("DEFAULT", "defaultvalues").unwrap(),
39 "defaultvalues"
40 );
41 config.setstr("DEFAULT", "defaultvalues", None);
42 config.write("output.ini")?;
43 let map2 = config.clone().load("output.ini")?;
44 assert_eq!(map2, *config.get_map_ref());
45 let map3 = config.clone().read(config.writes())?;
46 assert_eq!(map2, map3);
47 assert_eq!(config.sections().len(), 4);
48 assert_eq!(config.get("DEFAULT", "defaultvalues"), None);
49 assert_eq!(
50 config.get("topsecret", "KFC").unwrap(),
51 "the secret herb is orega-"
52 );
53 assert_eq!(config.get("topsecret", "Empty string").unwrap(), "");
54 assert_eq!(config.get("topsecret", "None string"), None);
55 assert_eq!(config.get("spacing", "indented").unwrap(), "indented");
56 assert_eq!(
57 config.get("spacing", "not indented").unwrap(),
58 "not indented"
59 );
60 assert_eq!(
61 config.get("topsecret", "colon").unwrap(),
62 "value after colon"
63 );
64 assert!(config.getbool("values", "Bool")?.unwrap());
65 assert!(!config.getboolcoerce("values", "Boolcoerce")?.unwrap());
66 assert_eq!(config.getint("values", "Int")?.unwrap(), -31415);
67 assert_eq!(config.getuint("values", "Uint")?.unwrap(), 31415);
68 assert_eq!(config.getfloat("values", "Float")?.unwrap(), 3.1415);
69 assert_eq!(config.getfloat("topsecret", "None string"), Ok(None));
70 assert_eq!(
71 map["default"]["defaultvalues"].clone().unwrap(),
72 "defaultvalues"
73 );
74 assert_eq!(
75 map["topsecret"]["kfc"].clone().unwrap(),
76 "the secret herb is orega-"
77 );
78 assert_eq!(map["topsecret"]["empty string"].clone().unwrap(), "");
79 assert_eq!(map["topsecret"]["none string"], None);
80 assert_eq!(map["spacing"]["indented"].clone().unwrap(), "indented");
81 assert_eq!(
82 map["spacing"]["not indented"].clone().unwrap(),
83 "not indented"
84 );
85 let mut config2 = config.clone();
86 let val = config2.remove_key("default", "defaultvalues");
87 assert_eq!(val, Some(None));
88 assert_eq!(config2.get("default", "defaultvalues"), None);
89 config2.remove_section("default");
90 assert_eq!(config2.get("default", "nope"), None);
91 let mut_map = config.get_mut_map();
92 mut_map.get_mut("topsecret").unwrap().insert(
93 String::from("none string"),
94 Some(String::from("None string")),
95 );
96 assert_eq!(
97 mut_map["topsecret"]["none string"].clone().unwrap(),
98 "None string"
99 );
100 mut_map.clear();
101 config2.clear();
102 assert_eq!(config.get_map_ref(), config2.get_map_ref());
103
104 config.load("tests/test.ini")?;
105 config.read_and_append("defaultvalues=somenewvalue".to_owned())?;
106 assert_eq!(
107 config.get("default", "defaultvalues").unwrap(),
108 "somenewvalue"
109 );
110 assert_eq!(
111 config.get("topsecret", "KFC").unwrap(),
112 "the secret herb is orega-"
113 );
114
115 let mut config3 = config.clone();
116 let mut_map = config3.get_mut_map();
117 mut_map.clear();
118 config3.load("tests/test.ini")?;
119 config3.load_and_append("tests/test_more.ini")?;
120 assert_eq!(
121 config3.get("default", "defaultvalues").unwrap(),
122 "overwritten"
123 );
124 assert_eq!(config3.get("topsecret", "KFC").unwrap(), "redacted");
125 // spacing -> indented exists in tests/test.ini, but not tests/test_more.ini
126 assert_eq!(config3.get("spacing", "indented").unwrap(), "indented");
127 assert!(!config3.getbool("values", "Bool")?.unwrap());
128
129 Ok(())
130 }
131
132 #[test]
133 #[allow(clippy::approx_constant)]
cs() -> Result<(), Box<dyn Error>>134 fn cs() -> Result<(), Box<dyn Error>> {
135 let mut config = Ini::new_cs();
136 let map = config.load("tests/test.ini")?;
137 config.set_comment_symbols(&[';', '#', '!']);
138 let inpstring = config.read(
139 "defaultvalues=defaultvalues
140 [topsecret]
141 KFC = the secret herb is orega-
142 colon:value after colon
143 Empty string =
144 None string
145 Password=[in-brackets]
146 [ spacing ]
147 indented=indented
148 not indented = not indented ;testcomment
149 !modified comment
150 [values]#another comment
151 Bool = True
152 Boolcoerce = 0
153 Int = -31415
154 Uint = 31415
155 Float = 3.1415"
156 .to_owned(),
157 )?;
158 assert_eq!(map, inpstring);
159 config.set("default", "defaultvalues", Some("notdefault".to_owned()));
160 assert_eq!(
161 config.get("default", "defaultvalues").unwrap(),
162 "notdefault"
163 );
164 config.setstr("default", "defaultvalues", Some("defaultvalues"));
165 assert_eq!(
166 config.get("default", "defaultvalues").unwrap(),
167 "defaultvalues"
168 );
169 config.setstr("default", "defaultvalues", None);
170 config.write("output2.ini")?;
171 let map2 = config.clone().load("output2.ini")?;
172 assert_eq!(map2, *config.get_map_ref());
173 let map3 = config.clone().read(config.writes())?;
174 assert_eq!(map2, map3);
175 assert_eq!(config.sections().len(), 4);
176 assert_eq!(config.get("default", "defaultvalues"), None);
177 assert_eq!(
178 config.get("topsecret", "KFC").unwrap(),
179 "the secret herb is orega-"
180 );
181 assert_eq!(config.get("topsecret", "Empty string").unwrap(), "");
182 assert_eq!(config.get("topsecret", "None string"), None);
183 assert_eq!(config.get("spacing", "indented").unwrap(), "indented");
184 assert_eq!(
185 config.get("spacing", "not indented").unwrap(),
186 "not indented"
187 );
188 assert_eq!(
189 config.get("topsecret", "colon").unwrap(),
190 "value after colon"
191 );
192 assert!(config.getbool("values", "Bool")?.unwrap());
193 assert!(!config.getboolcoerce("values", "Boolcoerce")?.unwrap());
194 assert_eq!(config.getint("values", "Int")?.unwrap(), -31415);
195 assert_eq!(config.getuint("values", "Uint")?.unwrap(), 31415);
196 assert_eq!(config.getfloat("values", "Float")?.unwrap(), 3.1415);
197 assert_eq!(config.getfloat("topsecret", "None string"), Ok(None));
198 assert_eq!(
199 map["default"]["defaultvalues"].clone().unwrap(),
200 "defaultvalues"
201 );
202 assert_eq!(
203 map["topsecret"]["KFC"].clone().unwrap(),
204 "the secret herb is orega-"
205 );
206 assert_eq!(map["topsecret"]["Empty string"].clone().unwrap(), "");
207 assert_eq!(map["topsecret"]["None string"], None);
208 assert_eq!(map["spacing"]["indented"].clone().unwrap(), "indented");
209 assert_eq!(
210 map["spacing"]["not indented"].clone().unwrap(),
211 "not indented"
212 );
213 let mut config2 = config.clone();
214 let val = config2.remove_key("default", "defaultvalues");
215 assert_eq!(val, Some(None));
216 assert_eq!(config2.get("default", "defaultvalues"), None);
217 config2.remove_section("default");
218 assert_eq!(config2.get("default", "nope"), None);
219 let mut_map = config.get_mut_map();
220 mut_map.get_mut("topsecret").unwrap().insert(
221 String::from("none string"),
222 Some(String::from("None string")),
223 );
224 assert_eq!(
225 mut_map["topsecret"]["none string"].clone().unwrap(),
226 "None string"
227 );
228 mut_map.clear();
229 config2.clear();
230 assert_eq!(config.get_map_ref(), config2.get_map_ref());
231 Ok(())
232 }
233
234 #[test]
235 #[cfg(feature = "indexmap")]
sort_on_write() -> Result<(), Box<dyn Error>>236 fn sort_on_write() -> Result<(), Box<dyn Error>> {
237 let mut config = Ini::new_cs();
238 config.load("tests/test.ini")?;
239
240 assert_eq!(
241 config.writes(),
242 "defaultvalues=defaultvalues
243 [topsecret]
244 KFC=the secret herb is orega-
245 colon=value after colon
246 Empty string=
247 None string
248 Password=[in-brackets]
249 [spacing]
250 indented=indented
251 not indented=not indented
252 [values]
253 Bool=True
254 Boolcoerce=0
255 Int=-31415
256 Uint=31415
257 Float=3.1415
258 "
259 );
260
261 Ok(())
262 }
263
264 #[test]
265 #[cfg(feature = "indexmap")]
pretty_writes_result_is_formatted_correctly() -> Result<(), Box<dyn Error>>266 fn pretty_writes_result_is_formatted_correctly() -> Result<(), Box<dyn Error>> {
267 use configparser::ini::IniDefault;
268
269 const OUT_FILE_CONTENTS: &str = "defaultvalues=defaultvalues
270 [topsecret]
271 KFC=the secret herb is orega-
272 Empty string=
273 None string
274 Password=[in-brackets]
275 [Section]
276 Key1: Value1
277 Key2: this is a haiku
278 spread across separate lines
279 a single value
280 Key3: another value
281 ";
282
283 let mut ini_defaults = IniDefault::default();
284 ini_defaults.case_sensitive = true;
285 ini_defaults.multiline = true;
286 let mut config = Ini::new_from_defaults(ini_defaults);
287 config.read(OUT_FILE_CONTENTS.to_owned())?;
288
289 let mut write_options = WriteOptions::default();
290 write_options.space_around_delimiters = true;
291 write_options.multiline_line_indentation = 2;
292 write_options.blank_lines_between_sections = 1;
293 assert_eq!(
294 config.pretty_writes(&write_options),
295 "defaultvalues = defaultvalues
296
297 [topsecret]
298 KFC = the secret herb is orega-
299 Empty string =
300 None string
301 Password = [in-brackets]
302
303 [Section]
304 Key1 = Value1
305 Key2 = this is a haiku
306 spread across separate lines
307 a single value
308 Key3 = another value
309 "
310 );
311
312 Ok(())
313 }
314
315 #[test]
316 #[cfg(feature = "indexmap")]
317 #[cfg(feature = "async-std")]
318 #[cfg(feature = "tokio")]
pretty_write_result_is_formatted_correctly() -> Result<(), Box<dyn Error>>319 fn pretty_write_result_is_formatted_correctly() -> Result<(), Box<dyn Error>> {
320 use configparser::ini::IniDefault;
321
322 const OUT_FILE_CONTENTS: &str = "defaultvalues=defaultvalues
323 [topsecret]
324 KFC=the secret herb is orega-
325 Empty string=
326 None string
327 Password=[in-brackets]
328 [Section]
329 Key1: Value1
330 Key2: this is a haiku
331 spread across separate lines
332 a single value
333 Key3: another value
334 ";
335
336 let mut ini_defaults = IniDefault::default();
337 ini_defaults.case_sensitive = true;
338 ini_defaults.multiline = true;
339 let mut config = Ini::new_from_defaults(ini_defaults);
340 config.read(OUT_FILE_CONTENTS.to_owned())?;
341
342 let mut write_options = WriteOptions::default();
343 write_options.space_around_delimiters = true;
344 write_options.multiline_line_indentation = 2;
345 write_options.blank_lines_between_sections = 1;
346 config.pretty_write("pretty_output.ini", &write_options)?;
347
348 let file_contents = std::fs::read_to_string("pretty_output.ini")?;
349 assert_eq!(
350 file_contents,
351 "defaultvalues = defaultvalues
352
353 [topsecret]
354 KFC = the secret herb is orega-
355 Empty string =
356 None string
357 Password = [in-brackets]
358
359 [Section]
360 Key1 = Value1
361 Key2 = this is a haiku
362 spread across separate lines
363 a single value
364 Key3 = another value
365 "
366 );
367
368 Ok(())
369 }
370
371 #[tokio::test]
372 #[cfg(feature = "indexmap")]
373 #[cfg(feature = "async-std")]
374 #[cfg(feature = "tokio")]
async_pretty_print_result_is_formatted_correctly() -> Result<(), Box<dyn Error>>375 async fn async_pretty_print_result_is_formatted_correctly() -> Result<(), Box<dyn Error>> {
376 use configparser::ini::IniDefault;
377
378 const OUT_FILE_CONTENTS: &str = "defaultvalues=defaultvalues
379 [topsecret]
380 KFC=the secret herb is orega-
381 Empty string=
382 None string
383 Password=[in-brackets]
384 [Section]
385 Key1: Value1
386 Key2: this is a haiku
387 spread across separate lines
388 a single value
389 Key3: another value
390 ";
391
392 let mut ini_defaults = IniDefault::default();
393 ini_defaults.case_sensitive = true;
394 ini_defaults.multiline = true;
395 let mut config = Ini::new_from_defaults(ini_defaults);
396 config.read(OUT_FILE_CONTENTS.to_owned())?;
397
398 let mut write_options = WriteOptions::default();
399 write_options.space_around_delimiters = true;
400 write_options.multiline_line_indentation = 2;
401 write_options.blank_lines_between_sections = 1;
402 config
403 .pretty_write_async("pretty_output_async.ini", &write_options)
404 .await
405 .map_err(|e| e.to_string())?;
406
407 let file_contents = std::fs::read_to_string("pretty_output_async.ini")?;
408 assert_eq!(
409 file_contents,
410 "defaultvalues = defaultvalues
411
412 [topsecret]
413 KFC = the secret herb is orega-
414 Empty string =
415 None string
416 Password = [in-brackets]
417
418 [Section]
419 Key1 = Value1
420 Key2 = this is a haiku
421 spread across separate lines
422 a single value
423 Key3 = another value
424 "
425 );
426
427 Ok(())
428 }
429
430 #[tokio::test]
431 #[cfg(feature = "async-std")]
432 #[cfg(feature = "tokio")]
async_load_write() -> Result<(), Box<dyn Error>>433 async fn async_load_write() -> Result<(), Box<dyn Error>> {
434 const OUT_FILE_CONTENTS: &str = "defaultvalues=defaultvalues
435 [topsecret]
436 KFC = the secret herb is orega-
437 colon:value after colon
438 Empty string =
439 None string
440 Password=[in-brackets]
441 [ spacing ]
442 indented=indented
443 not indented = not indented ;testcomment
444 !modified comment
445 [values]#another comment
446 Bool = True
447 Boolcoerce = 0
448 Int = -31415
449 Uint = 31415
450 Float = 3.1415";
451
452 let mut config = Ini::new();
453 config.read(OUT_FILE_CONTENTS.to_owned())?;
454 config.write("output_sync.ini")?;
455
456 let mut config_async = Ini::new();
457 config_async.read(OUT_FILE_CONTENTS.to_owned())?;
458 config_async
459 .write_async("output_async.ini")
460 .await
461 .map_err(|e| e.to_string())?;
462
463 let mut sync_content = Ini::new();
464 sync_content.load("output_sync.ini")?;
465
466 let mut async_content = Ini::new();
467 async_content.load_async("output_async.ini").await?;
468
469 assert_eq!(sync_content, async_content);
470
471 Ok(())
472 }
473
474 #[tokio::test]
475 #[cfg(feature = "async-std")]
476 #[cfg(feature = "tokio")]
async_load_and_append() -> Result<(), Box<dyn Error>>477 async fn async_load_and_append() -> Result<(), Box<dyn Error>> {
478 let mut sync_content = Ini::new();
479 sync_content.load("tests/test.ini")?;
480 sync_content.load_and_append("tests/test_more.ini")?;
481
482 let mut async_content = Ini::new();
483 async_content.load_async("tests/test.ini").await?;
484 async_content
485 .load_and_append_async("tests/test_more.ini")
486 .await?;
487
488 assert_eq!(sync_content, async_content);
489
490 Ok(())
491 }
492
493 #[test]
494 #[cfg(feature = "indexmap")]
multiline_off() -> Result<(), Box<dyn Error>>495 fn multiline_off() -> Result<(), Box<dyn Error>> {
496 let mut config = Ini::new_cs();
497 config.load("tests/test_multiline.ini")?;
498
499 let map = config.get_map_ref();
500
501 let section = map.get("Section").unwrap();
502
503 assert_eq!(config.get("Section", "Key1").unwrap(), "Value1");
504 assert_eq!(config.get("Section", "Key2").unwrap(), "Value Two");
505 assert_eq!(config.get("Section", "Key3").unwrap(), "this is a haiku");
506 assert!(section.contains_key("spread across separate lines"));
507 assert!(section.contains_key("a single value"));
508
509 assert_eq!(config.get("Section", "Key4").unwrap(), "Four");
510
511 assert_eq!(
512 config.writes(),
513 "[Section]
514 Key1=Value1
515 Key2=Value Two
516 Key3=this is a haiku
517 spread across separate lines
518 a single value
519 Key4=Four
520 "
521 );
522
523 Ok(())
524 }
525
526 #[test]
527 #[cfg(feature = "indexmap")]
multiline_on() -> Result<(), Box<dyn Error>>528 fn multiline_on() -> Result<(), Box<dyn Error>> {
529 let mut config = Ini::new_cs();
530 config.set_multiline(true);
531 config.load("tests/test_multiline.ini")?;
532
533 assert_eq!(config.get("Section", "Key1").unwrap(), "Value1");
534 assert_eq!(config.get("Section", "Key2").unwrap(), "Value Two");
535 assert_eq!(
536 config.get("Section", "Key3").unwrap(),
537 "this is a haiku\nspread across separate lines\na single value"
538 );
539 assert_eq!(config.get("Section", "Key4").unwrap(), "Four");
540
541 assert_eq!(
542 config.writes(),
543 "[Section]
544 Key1=Value1
545 Key2=Value Two
546 Key3=this is a haiku
547 spread across separate lines
548 a single value
549 Key4=Four
550 "
551 );
552
553 Ok(())
554 }
555