1
#![cfg(test)]
2

            
3
use crate::char_stream::CharStream;
4
use crate::source_map::{BytePos, Pos};
5

            
6
1
#[test]
7
1
fn peek_should_return_eof_when_char_stream_is_empty() {
8
1
    let mut char_stream = CharStream::with_text("");
9
1
    assert_eq!(char_stream.peek(), CharStream::EOF_CHAR);
10
1
}
11

            
12
1
#[test]
13
1
fn peek_should_return_first_char_from_stream_when_it_is_not_empty() {
14
1
    let mut char_stream = CharStream::with_text("abc");
15
1
    assert_eq!(char_stream.peek(), 'a');
16
1
}
17

            
18
1
#[test]
19
1
fn multiple_calls_to_peek_should_return_the_same_char() {
20
1
    let mut char_stream = CharStream::with_text("abc");
21
1

            
22
1
    assert_eq!(char_stream.peek(), 'a');
23
1
    assert_eq!(char_stream.peek(), 'a');
24
1
    assert_eq!(char_stream.peek(), 'a');
25
1
}
26

            
27
1
#[test]
28
1
fn lookahead_should_return_eof_when_char_stream_is_empty_no_matter_the_value_of_n() {
29
1
    let mut char_stream = CharStream::with_text("");
30
1

            
31
1
    assert_eq!(char_stream.lookahead(0), CharStream::EOF_CHAR);
32
1
    assert_eq!(char_stream.lookahead(1), CharStream::EOF_CHAR);
33
1
    assert_eq!(char_stream.lookahead(2), CharStream::EOF_CHAR);
34
1
}
35

            
36
1
#[test]
37
1
fn lookahead_should_return_eof_when_n_is_greater_or_equal_to_the_char_stream_length() {
38
1
    let mut char_stream = CharStream::with_text("abc");
39
1

            
40
1
    assert_eq!(char_stream.lookahead(3), CharStream::EOF_CHAR);
41
1
    assert_eq!(char_stream.lookahead(4), CharStream::EOF_CHAR);
42
1
    assert_eq!(char_stream.lookahead(5), CharStream::EOF_CHAR);
43
1
}
44

            
45
1
#[test]
46
1
fn lookahead_should_return_first_char_from_stream_when_n_is_zero() {
47
1
    let mut char_stream = CharStream::with_text("abc");
48
1
    assert_eq!(char_stream.lookahead(0), 'a');
49
1
}
50

            
51
1
#[test]
52
1
fn lookahead_should_return_nth_char_from_stream_when_n_is_nonzero() {
53
1
    let mut char_stream = CharStream::with_text("abcdefg");
54
1

            
55
1
    assert_eq!(char_stream.lookahead(1), 'b');
56
1
    assert_eq!(char_stream.lookahead(4), 'e');
57
1
}
58

            
59
1
#[test]
60
1
fn lookahead_can_look_at_most_8_chars_ahead() {
61
1
    let mut char_stream = CharStream::with_text("the brown fox jumped over the lazy dog");
62
1
    assert_eq!(char_stream.lookahead(8), 'n');
63
1
}
64

            
65
1
#[test]
66
#[should_panic(expected = "cannot look further than 8 chars ahead")]
67
1
fn lookahead_cannot_look_further_than_8_chars_ahead() {
68
1
    let mut char_stream = CharStream::with_text("the brown fox jumped over the lazy dog");
69
1
    char_stream.lookahead(9);
70
1
}
71

            
72
1
#[test]
73
1
fn lookahead_should_not_consume_the_char_stream() {
74
1
    let mut char_stream = CharStream::with_text("abc");
75
1

            
76
1
    char_stream.lookahead(3);
77
1

            
78
1
    assert_eq!(char_stream.peek(), 'a');
79
1
}
80

            
81
1
#[test]
82
1
fn consume_should_return_eof_when_char_stream_is_empty() {
83
1
    let mut char_stream = CharStream::with_text("");
84
1

            
85
1
    assert_eq!(char_stream.consume(), CharStream::EOF_CHAR);
86
1
}
87

            
88
1
#[test]
89
1
fn consume_should_return_the_then_peeked_char() {
90
1
    let mut char_stream = CharStream::with_text("abc");
91
1
    assert_eq!(char_stream.consume(), 'a');
92
1
}
93

            
94
1
#[test]
95
1
fn consume_should_advance_the_peeked_char_to_the_next_char() {
96
1
    let mut char_stream = CharStream::with_text("abc");
97
1

            
98
1
    char_stream.consume();
99
1

            
100
1
    assert_eq!(char_stream.peek(), 'b');
101

            
102
1
    assert_eq!(char_stream.lookahead(0), 'b');
103
1
    assert_eq!(char_stream.lookahead(1), 'c');
104
1
}
105

            
106
1
#[test]
107
1
fn consume_should_return_eof_after_the_char_stream_is_completely_consumed() {
108
1
    let mut char_stream = CharStream::with_text("abc");
109
1

            
110
1
    char_stream.consume();
111
1
    char_stream.consume();
112
1
    char_stream.consume();
113
1

            
114
1
    assert_eq!(char_stream.consume(), CharStream::EOF_CHAR);
115
1
}
116

            
117
1
#[test]
118
1
fn consume_should_return_eof_forever_after_encountering_a_null_char_in_the_middle_of_the_input() {
119
1
    let mut char_stream = CharStream::with_text("abc\0def");
120
1

            
121
1
    char_stream.consume();
122
1
    char_stream.consume();
123
1
    char_stream.consume();
124
1

            
125
1
    assert_eq!(char_stream.consume(), CharStream::EOF_CHAR);
126
1
    assert_eq!(char_stream.consume(), CharStream::EOF_CHAR);
127
1
    assert_eq!(char_stream.consume(), CharStream::EOF_CHAR);
128
1
    assert_eq!(char_stream.consume(), CharStream::EOF_CHAR);
129
1
}
130

            
131
1
#[test]
132
1
fn consume_should_turn_a_line_feed_and_carriage_return_into_line_feed_only() {
133
1
    let mut char_stream = CharStream::with_text("\n\ra");
134
1

            
135
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(0));
136

            
137
1
    assert_eq!(char_stream.peek(), '\n');
138
1
    assert_eq!(char_stream.consume(), '\n');
139
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(2));
140

            
141
1
    assert_eq!(char_stream.peek(), 'a');
142
1
    assert_eq!(char_stream.consume(), 'a');
143
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(3));
144
1
}
145

            
146
1
#[test]
147
1
fn consume_should_turn_a_carriage_return_and_line_feed_into_line_feed_only() {
148
1
    let mut char_stream = CharStream::with_text("\r\na");
149
1

            
150
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(0));
151

            
152
1
    assert_eq!(char_stream.peek(), '\n');
153
1
    assert_eq!(char_stream.consume(), '\n');
154
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(2));
155

            
156
1
    assert_eq!(char_stream.peek(), 'a');
157
1
    assert_eq!(char_stream.consume(), 'a');
158
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(3));
159
1
}
160

            
161
1
#[test]
162
1
fn consume_should_not_deduplicate_line_feeds() {
163
1
    let mut char_stream = CharStream::with_text("\n\na");
164
1

            
165
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(0));
166

            
167
1
    assert_eq!(char_stream.peek(), '\n');
168
1
    assert_eq!(char_stream.consume(), '\n');
169
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(1));
170

            
171
1
    assert_eq!(char_stream.peek(), '\n');
172
1
    assert_eq!(char_stream.consume(), '\n');
173
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(2));
174

            
175
1
    assert_eq!(char_stream.peek(), 'a');
176
1
    assert_eq!(char_stream.consume(), 'a');
177
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(3));
178
1
}
179

            
180
1
#[test]
181
1
fn consume_should_not_deduplicate_carriage_returns() {
182
1
    let mut char_stream = CharStream::with_text("\r\ra");
183
1

            
184
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(0));
185

            
186
1
    assert_eq!(char_stream.peek(), '\r');
187
1
    assert_eq!(char_stream.consume(), '\r');
188
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(1));
189

            
190
1
    assert_eq!(char_stream.peek(), '\r');
191
1
    assert_eq!(char_stream.consume(), '\r');
192
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(2));
193

            
194
1
    assert_eq!(char_stream.peek(), 'a');
195
1
    assert_eq!(char_stream.consume(), 'a');
196
1
    assert_eq!(char_stream.peek_byte_pos(), BytePos::from_usize(3));
197
1
}
198

            
199
1
#[test]
200
1
fn try_consume_should_not_consume_char_stream_if_ch_is_not_equal_to_peek() {
201
1
    let mut char_stream = CharStream::with_text("abc");
202
1

            
203
1
    char_stream.try_consume('b');
204
1

            
205
1
    assert_eq!(char_stream.peek(), 'a');
206
1
}
207

            
208
1
#[test]
209
1
fn try_consume_should_return_false_if_ch_is_not_equal_to_peek() {
210
1
    let mut char_stream = CharStream::with_text("abc");
211
1

            
212
1
    assert!(!char_stream.try_consume('b'));
213
1
}
214

            
215
1
#[test]
216
1
fn try_consume_should_consume_char_stream_if_ch_is_equal_to_peek() {
217
1
    let mut char_stream = CharStream::with_text("abc");
218
1

            
219
1
    char_stream.try_consume('a');
220
1

            
221
1
    assert_eq!(char_stream.peek(), 'b');
222
1
}
223

            
224
1
#[test]
225
1
fn try_consume_should_return_true_if_ch_is_equal_to_peek() {
226
1
    let mut char_stream = CharStream::with_text("abc");
227
1

            
228
1
    assert!(char_stream.try_consume('a'));
229
1
}
230

            
231
1
#[test]
232
#[should_panic(expected = "cannot consume an EOF char")]
233
1
fn try_consume_should_panic_if_ch_is_eof() {
234
1
    let mut char_stream = CharStream::with_text("abc");
235
1
    char_stream.try_consume(CharStream::EOF_CHAR);
236
1
}
237

            
238
1
#[test]
239
1
fn peek_and_lookahead_should_return_eof_after_the_char_stream_is_completely_consumed() {
240
1
    let mut char_stream = CharStream::with_text("abc");
241
1

            
242
1
    char_stream.consume();
243
1
    char_stream.consume();
244
1
    char_stream.consume();
245
1

            
246
1
    assert_eq!(char_stream.peek(), CharStream::EOF_CHAR);
247

            
248
1
    assert_eq!(char_stream.lookahead(0), CharStream::EOF_CHAR);
249
1
    assert_eq!(char_stream.lookahead(1), CharStream::EOF_CHAR);
250
1
}
251

            
252
1
#[test]
253
1
fn peek_byte_pos_should_return_zero_for_the_first_peeked_char_whether_char_stream_is_empty_or_not()
254
1
{
255
1
    assert_eq!(
256
1
        CharStream::with_text("").peek_byte_pos(),
257
1
        BytePos::from_usize(0)
258
1
    );
259

            
260
1
    assert_eq!(
261
1
        CharStream::with_text("abc").peek_byte_pos(),
262
1
        BytePos::from_usize(0)
263
1
    );
264
1
}
265

            
266
1
#[test]
267
1
fn peek_byte_pos_should_not_advance_after_peeking_a_char() {
268
1
    let mut char_stream = CharStream::with_text("abc");
269
1

            
270
1
    let before_byte_pos = char_stream.peek_byte_pos();
271
1
    let _ = char_stream.peek();
272
1
    let after_byte_pos = char_stream.peek_byte_pos();
273
1

            
274
1
    assert_eq!(before_byte_pos, after_byte_pos);
275
1
}
276

            
277
1
#[test]
278
1
fn peek_byte_pos_should_not_advance_after_lookahead() {
279
1
    let mut char_stream = CharStream::with_text("abc");
280
1

            
281
1
    let before_byte_pos = char_stream.peek_byte_pos();
282
1
    let _ = char_stream.lookahead(2);
283
1
    let after_byte_pos = char_stream.peek_byte_pos();
284
1

            
285
1
    assert_eq!(before_byte_pos, after_byte_pos);
286
1
}
287

            
288
1
#[test]
289
1
fn peek_byte_pos_should_not_advance_after_consuming_an_eof_char() {
290
1
    let input_text = "abc";
291
1
    let mut char_stream = CharStream::with_text(input_text);
292
1

            
293
1
    let first_byte_pos = char_stream.peek_byte_pos();
294
1

            
295
3
    for _ in 0..input_text.len() {
296
3
        char_stream.consume();
297
3
    }
298

            
299
1
    let last_byte_pos = char_stream.peek_byte_pos();
300
1

            
301
1
    assert_ne!(first_byte_pos, last_byte_pos);
302

            
303
1
    let eof_char = char_stream.consume();
304
1

            
305
1
    assert_eq!(eof_char, CharStream::EOF_CHAR);
306
1
    assert_eq!(char_stream.peek_byte_pos(), last_byte_pos);
307
1
}
308

            
309
1
#[test]
310
1
fn peek_byte_pos_should_advance_by_one_after_consuming_an_ascii_char() {
311
1
    let mut char_stream = CharStream::with_text("abc");
312
1

            
313
1
    let first_byte_pos = char_stream.peek_byte_pos();
314
1

            
315
1
    let _ = char_stream.consume();
316
1
    let second_byte_pos = char_stream.peek_byte_pos();
317
1

            
318
1
    assert_eq!(second_byte_pos, first_byte_pos + BytePos::from_usize(1));
319

            
320
1
    let _ = char_stream.consume();
321
1
    let third_byte_pos = char_stream.peek_byte_pos();
322
1

            
323
1
    assert_eq!(third_byte_pos, first_byte_pos + BytePos::from_usize(2));
324
1
}
325

            
326
1
#[test]
327
1
fn peek_byte_pos_should_advance_by_the_char_utf8_byte_length_after_consuming_a_utf8_char() {
328
1
    let text_input_with_varying_char_lengths = "\u{80}\u{800}\u{10000}";
329
1
    let mut char_stream = CharStream::with_text(text_input_with_varying_char_lengths);
330
1

            
331
1
    let expected_peek_byte_poses = [
332
1
        BytePos::from_usize(2), // 2-byte length
333
1
        BytePos::from_usize(5), // 3-byte length
334
1
        BytePos::from_usize(9), // 4-byte length
335
1
    ];
336

            
337
4
    for expected_peek_byte_pos in expected_peek_byte_poses {
338
3
        char_stream.consume();
339
3
        assert_eq!(char_stream.peek_byte_pos(), expected_peek_byte_pos);
340
    }
341
1
}