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