Skip to content

Commit

Permalink
Don't panic (on general_section for empty ini)
Browse files Browse the repository at this point in the history
When creating a new ini or loading it from an input which contains no
actual entries but empty lines for the general section, calling
general_section and general_section_mut panics. This is not documented
nor do I expect this behavior: Isn't an empty file equivalent to an
empty general section? And from this perspective, calls to
general_section or general_section_mut should not panic.
  • Loading branch information
sirhcel authored and zonyitoo committed Mar 26, 2022
1 parent a734be3 commit 1cbfb75
Showing 1 changed file with 68 additions and 2 deletions.
70 changes: 68 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ impl<'a> From<Entry<'a, SectionKey, Properties>> for SectionEntry<'a> {
}

/// Ini struct
#[derive(Clone, Default)]
#[derive(Clone)]
pub struct Ini {
sections: ListOrderedMultimap<SectionKey, Properties>,
}
Expand Down Expand Up @@ -660,6 +660,20 @@ impl Ini {
}
}

impl Default for Ini {
/// Creates an ini instance with an empty general section. This allows [Ini::general_section]
/// and [Ini::with_general_section] to be called without panicking.
fn default() -> Self {
let mut result = Ini {
sections: Default::default(),
};

result.sections.insert(None::<String>, Default::default());

result
}
}

impl<S: Into<String>> Index<Option<S>> for Ini {
type Output = Properties;

Expand Down Expand Up @@ -1344,8 +1358,39 @@ mod test {
assert!(!props.contains_key("k1"));
}

#[test]
fn load_from_str_with_empty_general_section() {
let input = "[sec1]\nkey1=val1\n";
let opt = Ini::load_from_str(input);
assert!(opt.is_ok());

let mut output = opt.unwrap();
assert_eq!(output.len(), 2);

assert!(output.general_section().is_empty());
assert!(output.general_section_mut().is_empty());

let props1 = output.section(None::<String>).unwrap();
assert!(props1.is_empty());
let props2 = output.section(Some("sec1")).unwrap();
assert_eq!(props2.len(), 1);
assert_eq!(props2.get("key1"), Some("val1"));
}

#[test]
fn load_from_str_with_empty_input() {
let input = "";
let opt = Ini::load_from_str(input);
assert!(opt.is_ok());

let mut output = opt.unwrap();
assert!(output.general_section().is_empty());
assert!(output.general_section_mut().is_empty());
assert_eq!(output.len(), 1);
}

#[test]
fn load_from_str_with_empty_lines() {
let input = "\n\n\n";
let opt = Ini::load_from_str(input);
assert!(opt.is_ok());
Expand All @@ -1364,7 +1409,8 @@ mod test {
assert!(opt.is_ok());

let output = opt.unwrap();
assert_eq!(output.len(), 2);
// there is always a general section
assert_eq!(output.len(), 3);
assert!(output.section(Some("sec1")).is_some());

let sec1 = output.section(Some("sec1")).unwrap();
Expand Down Expand Up @@ -1856,6 +1902,22 @@ a3 = n3
assert_eq!(keys1, vec!["x2", "xb", "a3"]);
}

#[test]
fn write_new() {
use std::str;

let ini = Ini::new();

let opt = WriteOption {
line_separator: LineSeparator::CR,
..Default::default()
};
let mut buf = Vec::new();
ini.write_to_opt(&mut buf, opt).unwrap();

assert_eq!("", str::from_utf8(&buf).unwrap());
}

#[test]
fn write_line_separator() {
use std::str;
Expand Down Expand Up @@ -1929,6 +1991,10 @@ bar = f
assert_eq!(3, ini.section_all(Some("Peer")).count());

let mut iter = ini.iter();
// there is always an empty general section
let (k0, p0) = iter.next().unwrap();
assert_eq!(None, k0);
assert!(p0.is_empty());
let (k1, p1) = iter.next().unwrap();
assert_eq!(Some("Peer"), k1);
assert_eq!(Some("a"), p1.get("foo"));
Expand Down

0 comments on commit 1cbfb75

Please sign in to comment.