xref: /third_party/rust/crates/nom/tests/ini.rs (revision 6855e09e)
1use nom::{
2  bytes::complete::take_while,
3  character::complete::{
4    alphanumeric1 as alphanumeric, char, multispace0 as multispace, space0 as space,
5  },
6  combinator::{map, map_res, opt},
7  multi::many0,
8  sequence::{delimited, pair, separated_pair, terminated, tuple},
9  IResult,
10};
11
12use std::collections::HashMap;
13use std::str;
14
15fn category(i: &[u8]) -> IResult<&[u8], &str> {
16  map_res(
17    delimited(char('['), take_while(|c| c != b']'), char(']')),
18    str::from_utf8,
19  )(i)
20}
21
22fn key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)> {
23  let (i, key) = map_res(alphanumeric, str::from_utf8)(i)?;
24  let (i, _) = tuple((opt(space), char('='), opt(space)))(i)?;
25  let (i, val) = map_res(take_while(|c| c != b'\n' && c != b';'), str::from_utf8)(i)?;
26  let (i, _) = opt(pair(char(';'), take_while(|c| c != b'\n')))(i)?;
27  Ok((i, (key, val)))
28}
29
30fn keys_and_values(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>> {
31  map(many0(terminated(key_value, opt(multispace))), |vec| {
32    vec.into_iter().collect()
33  })(i)
34}
35
36fn category_and_keys(i: &[u8]) -> IResult<&[u8], (&str, HashMap<&str, &str>)> {
37  let (i, category) = terminated(category, opt(multispace))(i)?;
38  let (i, keys) = keys_and_values(i)?;
39  Ok((i, (category, keys)))
40}
41
42fn categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>> {
43  map(
44    many0(separated_pair(
45      category,
46      opt(multispace),
47      map(
48        many0(terminated(key_value, opt(multispace))),
49        |vec: Vec<_>| vec.into_iter().collect(),
50      ),
51    )),
52    |vec: Vec<_>| vec.into_iter().collect(),
53  )(i)
54}
55
56#[test]
57fn parse_category_test() {
58  let ini_file = &b"[category]
59
60parameter=value
61key = value2"[..];
62
63  let ini_without_category = &b"\n\nparameter=value
64key = value2"[..];
65
66  let res = category(ini_file);
67  println!("{:?}", res);
68  match res {
69    Ok((i, o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
70    _ => println!("error"),
71  }
72
73  assert_eq!(res, Ok((ini_without_category, "category")));
74}
75
76#[test]
77fn parse_key_value_test() {
78  let ini_file = &b"parameter=value
79key = value2"[..];
80
81  let ini_without_key_value = &b"\nkey = value2"[..];
82
83  let res = key_value(ini_file);
84  println!("{:?}", res);
85  match res {
86    Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
87    _ => println!("error"),
88  }
89
90  assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
91}
92
93#[test]
94fn parse_key_value_with_space_test() {
95  let ini_file = &b"parameter = value
96key = value2"[..];
97
98  let ini_without_key_value = &b"\nkey = value2"[..];
99
100  let res = key_value(ini_file);
101  println!("{:?}", res);
102  match res {
103    Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
104    _ => println!("error"),
105  }
106
107  assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
108}
109
110#[test]
111fn parse_key_value_with_comment_test() {
112  let ini_file = &b"parameter=value;abc
113key = value2"[..];
114
115  let ini_without_key_value = &b"\nkey = value2"[..];
116
117  let res = key_value(ini_file);
118  println!("{:?}", res);
119  match res {
120    Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
121    _ => println!("error"),
122  }
123
124  assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value"))));
125}
126
127#[test]
128fn parse_multiple_keys_and_values_test() {
129  let ini_file = &b"parameter=value;abc
130
131key = value2
132
133[category]"[..];
134
135  let ini_without_key_value = &b"[category]"[..];
136
137  let res = keys_and_values(ini_file);
138  println!("{:?}", res);
139  match res {
140    Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
141    _ => println!("error"),
142  }
143
144  let mut expected: HashMap<&str, &str> = HashMap::new();
145  expected.insert("parameter", "value");
146  expected.insert("key", "value2");
147  assert_eq!(res, Ok((ini_without_key_value, expected)));
148}
149
150#[test]
151fn parse_category_then_multiple_keys_and_values_test() {
152  //FIXME: there can be an empty line or a comment line after a category
153  let ini_file = &b"[abcd]
154parameter=value;abc
155
156key = value2
157
158[category]"[..];
159
160  let ini_after_parser = &b"[category]"[..];
161
162  let res = category_and_keys(ini_file);
163  println!("{:?}", res);
164  match res {
165    Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
166    _ => println!("error"),
167  }
168
169  let mut expected_h: HashMap<&str, &str> = HashMap::new();
170  expected_h.insert("parameter", "value");
171  expected_h.insert("key", "value2");
172  assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h))));
173}
174
175#[test]
176fn parse_multiple_categories_test() {
177  let ini_file = &b"[abcd]
178
179parameter=value;abc
180
181key = value2
182
183[category]
184parameter3=value3
185key4 = value4
186"[..];
187
188  let ini_after_parser = &b""[..];
189
190  let res = categories(ini_file);
191  //println!("{:?}", res);
192  match res {
193    Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
194    _ => println!("error"),
195  }
196
197  let mut expected_1: HashMap<&str, &str> = HashMap::new();
198  expected_1.insert("parameter", "value");
199  expected_1.insert("key", "value2");
200  let mut expected_2: HashMap<&str, &str> = HashMap::new();
201  expected_2.insert("parameter3", "value3");
202  expected_2.insert("key4", "value4");
203  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
204  expected_h.insert("abcd", expected_1);
205  expected_h.insert("category", expected_2);
206  assert_eq!(res, Ok((ini_after_parser, expected_h)));
207}
208