1 mod lib {
2     #[cfg(feature = "std")]
3     pub mod std {
4         pub use std::string::ToString;
5         pub use std::vec::Vec;
6     }
7     #[cfg(all(not(feature = "std"), feature = "alloc"))]
8     pub mod std {
9         pub use alloc::string::ToString;
10         pub use alloc::vec::Vec;
11     }
12 }
13 
14 #[cfg(feature = "alloc")]
15 use lib::std::*;
16 
17 use super::{LocatedSpan, LocatedSpanEx};
18 #[cfg(feature = "alloc")]
19 use nom::ParseTo;
20 use nom::{
21     error::ErrorKind, Compare, CompareResult, FindSubstring, FindToken, InputIter, InputTake,
22     InputTakeAtPosition, Offset, Slice,
23 };
24 
25 type StrSpan<'a> = LocatedSpan<&'a str>;
26 type BytesSpan<'a> = LocatedSpan<&'a [u8]>;
27 type StrSpanEx<'a, 'b> = LocatedSpanEx<&'a str, &'b str>;
28 type BytesSpanEx<'a, 'b> = LocatedSpanEx<&'a [u8], &'b str>;
29 
30 #[test]
new_sould_be_the_same_as_new_extra()31 fn new_sould_be_the_same_as_new_extra() {
32     let byteinput = &b"foobar"[..];
33     assert_eq!(
34         BytesSpan::new(byteinput),
35         LocatedSpanEx::new_extra(byteinput, ())
36     );
37     let strinput = "foobar";
38     assert_eq!(
39         StrSpan::new(strinput),
40         LocatedSpanEx::new_extra(strinput, ())
41     );
42 }
43 
44 #[test]
it_should_call_new_for_u8_successfully()45 fn it_should_call_new_for_u8_successfully() {
46     let input = &b"foobar"[..];
47     let output = BytesSpan {
48         offset: 0,
49         line: 1,
50         fragment: input,
51         extra: (),
52     };
53 
54     assert_eq!(BytesSpan::new(input), output);
55 }
56 
57 #[test]
it_should_call_new_for_str_successfully()58 fn it_should_call_new_for_str_successfully() {
59     let input = &"foobar"[..];
60     let output = StrSpan {
61         offset: 0,
62         line: 1,
63         fragment: input,
64         extra: (),
65     };
66 
67     assert_eq!(StrSpan::new(input), output);
68 }
69 
70 #[test]
it_should_slice_for_str()71 fn it_should_slice_for_str() {
72     let str_slice = StrSpanEx::new_extra("foobar", "extra");
73     assert_eq!(
74         str_slice.slice(1..),
75         StrSpanEx {
76             offset: 1,
77             line: 1,
78             fragment: "oobar",
79             extra: "extra",
80         }
81     );
82     assert_eq!(
83         str_slice.slice(1..3),
84         StrSpanEx {
85             offset: 1,
86             line: 1,
87             fragment: "oo",
88             extra: "extra",
89         }
90     );
91     assert_eq!(
92         str_slice.slice(..3),
93         StrSpanEx {
94             offset: 0,
95             line: 1,
96             fragment: "foo",
97             extra: "extra",
98         }
99     );
100     assert_eq!(str_slice.slice(..), str_slice);
101 }
102 
103 #[test]
it_should_slice_for_u8()104 fn it_should_slice_for_u8() {
105     let bytes_slice = BytesSpanEx::new_extra(b"foobar", "extra");
106     assert_eq!(
107         bytes_slice.slice(1..),
108         BytesSpanEx {
109             offset: 1,
110             line: 1,
111             fragment: b"oobar",
112             extra: "extra",
113         }
114     );
115     assert_eq!(
116         bytes_slice.slice(1..3),
117         BytesSpanEx {
118             offset: 1,
119             line: 1,
120             fragment: b"oo",
121             extra: "extra",
122         }
123     );
124     assert_eq!(
125         bytes_slice.slice(..3),
126         BytesSpanEx {
127             offset: 0,
128             line: 1,
129             fragment: b"foo",
130             extra: "extra",
131         }
132     );
133     assert_eq!(bytes_slice.slice(..), bytes_slice);
134 }
135 
136 #[test]
it_should_calculate_columns()137 fn it_should_calculate_columns() {
138     let input = StrSpan::new(
139         "foo
140         bar",
141     );
142 
143     let bar_idx = input.find_substring("bar").unwrap();
144     assert_eq!(input.slice(bar_idx..).get_column(), 9);
145 }
146 
147 #[test]
it_should_calculate_columns_accurately_with_non_ascii_chars()148 fn it_should_calculate_columns_accurately_with_non_ascii_chars() {
149     let s = StrSpan::new("メカジキ");
150     assert_eq!(s.slice(6..).get_utf8_column(), 3);
151 }
152 
153 #[test]
154 #[should_panic(expected = "offset is too big")]
it_should_panic_when_getting_column_if_offset_is_too_big()155 fn it_should_panic_when_getting_column_if_offset_is_too_big() {
156     let s = StrSpanEx {
157         offset: usize::max_value(),
158         fragment: "",
159         line: 1,
160         extra: "",
161     };
162     s.get_column();
163 }
164 
165 #[cfg(feature = "alloc")]
166 #[test]
it_should_iterate_indices()167 fn it_should_iterate_indices() {
168     let str_slice = StrSpan::new("foobar");
169     assert_eq!(
170         str_slice.iter_indices().collect::<Vec<(usize, char)>>(),
171         vec![(0, 'f'), (1, 'o'), (2, 'o'), (3, 'b'), (4, 'a'), (5, 'r')]
172     );
173     assert_eq!(
174         StrSpan::new("")
175             .iter_indices()
176             .collect::<Vec<(usize, char)>>(),
177         vec![]
178     );
179 }
180 
181 #[cfg(feature = "alloc")]
182 #[test]
it_should_iterate_elements()183 fn it_should_iterate_elements() {
184     let str_slice = StrSpan::new("foobar");
185     assert_eq!(
186         str_slice.iter_elements().collect::<Vec<char>>(),
187         vec!['f', 'o', 'o', 'b', 'a', 'r']
188     );
189     assert_eq!(
190         StrSpan::new("").iter_elements().collect::<Vec<char>>(),
191         vec![]
192     );
193 }
194 
195 #[test]
it_should_position_char()196 fn it_should_position_char() {
197     let str_slice = StrSpan::new("foobar");
198     assert_eq!(str_slice.position(|x| x == 'a'), Some(4));
199     assert_eq!(str_slice.position(|x| x == 'c'), None);
200 }
201 
202 #[test]
it_should_compare_elements()203 fn it_should_compare_elements() {
204     assert_eq!(StrSpan::new("foobar").compare("foo"), CompareResult::Ok);
205     assert_eq!(StrSpan::new("foobar").compare("bar"), CompareResult::Error);
206     assert_eq!(StrSpan::new("foobar").compare("foobar"), CompareResult::Ok);
207     assert_eq!(
208         StrSpan::new("foobar").compare_no_case("fooBar"),
209         CompareResult::Ok
210     );
211     assert_eq!(
212         StrSpan::new("foobar").compare("foobarbaz"),
213         CompareResult::Incomplete
214     );
215 
216     // FIXME: WTF! The line below doesn't compile unless we stop comparing
217     // LocatedSpan<&[u8]> with &str
218     //
219     // assert_eq!(BytesSpan::new(b"foobar").compare(b"foo"), CompareResult::Ok);
220     assert_eq!(BytesSpan::new(b"foobar").compare("foo"), CompareResult::Ok);
221 }
222 
223 #[test]
224 #[allow(unused_parens)]
it_should_find_token()225 fn it_should_find_token() {
226     assert!(StrSpan::new("foobar").find_token('a'));
227     assert!(StrSpan::new("foobar").find_token(b'a'));
228     assert!(StrSpan::new("foobar").find_token(&(b'a')));
229     assert!(!StrSpan::new("foobar").find_token('c'));
230     assert!(!StrSpan::new("foobar").find_token(b'c'));
231     assert!(!StrSpan::new("foobar").find_token((&b'c')));
232 
233     assert!(BytesSpan::new(b"foobar").find_token(b'a'));
234     assert!(BytesSpan::new(b"foobar").find_token(&(b'a')));
235     assert!(!BytesSpan::new(b"foobar").find_token(b'c'));
236     assert!(!BytesSpan::new(b"foobar").find_token((&b'c')));
237 }
238 
239 #[test]
it_should_find_substring()240 fn it_should_find_substring() {
241     assert_eq!(StrSpan::new("foobar").find_substring("bar"), Some(3));
242     assert_eq!(StrSpan::new("foobar").find_substring("baz"), None);
243     assert_eq!(BytesSpan::new(b"foobar").find_substring("bar"), Some(3));
244     assert_eq!(BytesSpan::new(b"foobar").find_substring("baz"), None);
245 }
246 
247 #[cfg(feature = "alloc")]
248 #[test]
it_should_parse_to_string()249 fn it_should_parse_to_string() {
250     assert_eq!(
251         StrSpan::new("foobar").parse_to(),
252         Some("foobar".to_string())
253     );
254     assert_eq!(
255         BytesSpan::new(b"foobar").parse_to(),
256         Some("foobar".to_string())
257     );
258 }
259 
260 // https://github.com/Geal/nom/blob/eee82832fafdfdd0505546d224caa466f7d39a15/src/util.rs#L710-L720
261 #[test]
it_should_calculate_offset_for_u8()262 fn it_should_calculate_offset_for_u8() {
263     let s = b"abcd123";
264     let a = &s[..];
265     let b = &a[2..];
266     let c = &a[..4];
267     let d = &a[3..5];
268     assert_eq!(a.offset(b), 2);
269     assert_eq!(a.offset(c), 0);
270     assert_eq!(a.offset(d), 3);
271 }
272 
273 // https://github.com/Geal/nom/blob/eee82832fafdfdd0505546d224caa466f7d39a15/src/util.rs#L722-L732
274 #[test]
it_should_calculate_offset_for_str()275 fn it_should_calculate_offset_for_str() {
276     let s = StrSpan::new("abcřèÂßÇd123");
277     let a = s.slice(..);
278     let b = a.slice(7..);
279     let c = a.slice(..5);
280     let d = a.slice(5..9);
281     assert_eq!(a.offset(&b), 7);
282     assert_eq!(a.offset(&c), 0);
283     assert_eq!(a.offset(&d), 5);
284 }
285 
286 #[test]
it_should_take_chars()287 fn it_should_take_chars() {
288     let s = StrSpanEx::new_extra("abcdefghij", "extra");
289     assert_eq!(
290         s.take(5),
291         StrSpanEx {
292             offset: 0,
293             line: 1,
294             fragment: "abcde",
295             extra: "extra",
296         }
297     );
298 }
299 
300 #[test]
it_should_take_split_chars()301 fn it_should_take_split_chars() {
302     let s = StrSpanEx::new_extra("abcdefghij", "extra");
303     assert_eq!(
304         s.take_split(5),
305         (
306             StrSpanEx {
307                 offset: 5,
308                 line: 1,
309                 fragment: "fghij",
310                 extra: "extra",
311             },
312             StrSpanEx {
313                 offset: 0,
314                 line: 1,
315                 fragment: "abcde",
316                 extra: "extra",
317             }
318         )
319     );
320 }
321 
322 type TestError<'a, 'b> = (LocatedSpanEx<&'a str, &'b str>, nom::error::ErrorKind);
323 
324 #[test]
it_should_split_at_position()325 fn it_should_split_at_position() {
326     let s = StrSpanEx::new_extra("abcdefghij", "extra");
327     assert_eq!(
328         s.split_at_position::<_, TestError>(|c| { c == 'f' }),
329         Ok((
330             StrSpanEx {
331                 offset: 5,
332                 line: 1,
333                 fragment: "fghij",
334                 extra: "extra",
335             },
336             StrSpanEx {
337                 offset: 0,
338                 line: 1,
339                 fragment: "abcde",
340                 extra: "extra",
341             }
342         ))
343     );
344 }
345 
346 // TODO also test split_at_position with an error
347 
348 #[test]
it_should_split_at_position1()349 fn it_should_split_at_position1() {
350     let s = StrSpanEx::new_extra("abcdefghij", "extra");
351     assert_eq!(
352         s.split_at_position1::<_, TestError>(|c| { c == 'f' }, ErrorKind::Alpha),
353         s.split_at_position::<_, TestError>(|c| { c == 'f' }),
354     );
355 }
356 
357 #[test]
it_should_capture_position()358 fn it_should_capture_position() {
359     use super::position;
360     use nom::bytes::complete::{tag, take_until};
361     use nom::IResult;
362 
363     fn parser<'a>(s: StrSpan<'a>) -> IResult<StrSpan<'a>, (StrSpan<'a>, &'a str)> {
364         let (s, _) = take_until("def")(s)?;
365         let (s, p) = position(s)?;
366         let (s, t) = tag("def")(s)?;
367         Ok((s, (p, t.fragment)))
368     }
369 
370     let s = StrSpan::new("abc\ndefghij");
371     let (_, (s, t)) = parser(s).unwrap();
372     assert_eq!(s.offset, 4);
373     assert_eq!(s.line, 2);
374     assert_eq!(t, "def");
375 }
376