1 #![cfg(feature = "std")]
2 
3 use combine::{
4     attempt, choice, many, many1,
5     parser::{
6         char::{char, digit, spaces, string},
7         combinator::recognize,
8     },
9     sep_by, skip_many1,
10     stream::{
11         buffered,
12         easy::{self, Error, Errors},
13         position, IteratorStream,
14     },
15     Parser, Positioned,
16 };
17 
18 #[test]
shared_stream_buffer()19 fn shared_stream_buffer() {
20     // Iterator that can't be cloned
21     let text = "10,222,3,44".chars().map(|c| {
22         if c.is_digit(10) {
23             (c as u8 + 1) as char
24         } else {
25             c
26         }
27     });
28     let buffer = buffered::Stream::new(position::Stream::new(IteratorStream::new(text)), 1);
29     let int: &mut dyn Parser<_, Output = _, PartialState = _> =
30         &mut many(digit()).map(|s: String| s.parse::<i64>().unwrap());
31     let result = sep_by(int, char(',')).parse(buffer).map(|t| t.0);
32     assert_eq!(result, Ok(vec![21, 333, 4, 55]));
33 }
34 
35 #[test]
shared_stream_backtrack()36 fn shared_stream_backtrack() {
37     let text = "apple,apple,ananas,orangeblah";
38     let mut iter = text.chars();
39     // Iterator that can't be cloned
40     let stream = buffered::Stream::new(position::Stream::new(IteratorStream::new(&mut iter)), 2);
41 
42     let value: &mut dyn Parser<_, Output = _, PartialState = _> = &mut choice([
43         attempt(string("apple")),
44         attempt(string("orange")),
45         attempt(string("ananas")),
46     ]);
47     let mut parser = sep_by(value, char(','));
48     let result = parser.parse(stream).map(|t| t.0);
49     assert_eq!(result, Ok(vec!["apple", "apple", "ananas", "orange"]));
50 }
51 
52 #[test]
shared_stream_insufficent_backtrack()53 fn shared_stream_insufficent_backtrack() {
54     let text = "apple,apple,ananas,orangeblah";
55     let mut iter = text.chars();
56     // Iterator that can't be cloned
57     let stream = buffered::Stream::new(
58         easy::Stream(position::Stream::new(IteratorStream::new(&mut iter))),
59         1,
60     );
61 
62     let value: &mut dyn Parser<_, Output = _, PartialState = _> = &mut choice([
63         attempt(string("apple")),
64         attempt(string("orange")),
65         attempt(string("ananas")),
66     ]);
67     let mut parser = sep_by(value, char(','));
68     let result: Result<Vec<&str>, _> = parser.parse(stream).map(|t| t.0);
69     assert!(result.is_err());
70     assert!(
71         result
72             .as_ref()
73             .unwrap_err()
74             .errors
75             .iter()
76             .any(|err| *err == Error::Message("Backtracked to far".into())),
77         "{}",
78         result.unwrap_err()
79     );
80 }
81 
82 /// Test which checks that a stream which has ended does not repeat the last token in some cases in
83 /// which case this test would loop forever
84 #[test]
always_output_end_of_input_after_end_of_input()85 fn always_output_end_of_input_after_end_of_input() {
86     let text = "10".chars();
87     let buffer = buffered::Stream::new(position::Stream::new(IteratorStream::new(text)), 1);
88     let int = many1(digit()).map(|s: String| s.parse::<i64>().unwrap());
89     let result = many(spaces().with(int)).parse(buffer).map(|t| t.0);
90     assert_eq!(result, Ok(vec![10]));
91 }
92 
93 #[test]
position()94 fn position() {
95     let text = "10abc".chars();
96     let stream = buffered::Stream::new(position::Stream::new(IteratorStream::new(text)), 3);
97     assert_eq!(stream.position(), 0);
98     let result = many1::<Vec<_>, _, _>(digit()).parse(stream);
99     assert!(result.is_ok());
100     assert_eq!(result.unwrap().1.position(), 2);
101 }
102 
103 #[test]
buffered_stream_recognize_issue_256()104 fn buffered_stream_recognize_issue_256() {
105     let mut parser = recognize::<String, _, _>(skip_many1(digit()));
106     let input = "12 ";
107     assert_eq!(
108         parser
109             .parse(buffered::Stream::new(easy::Stream(input), 1))
110             .map_err(|err| err.map_position(|pos| pos.translate_position(input))),
111         Err(Errors {
112             position: 2,
113             errors: vec![easy::Error::Message("Backtracked to far".into())]
114         })
115     );
116 }
117