1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2024 Orange
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *          http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
use crate::ast::*;
19
use crate::combinator::{one_or_more, optional, recover, zero_or_more};
20
use crate::parser::error::*;
21
use crate::parser::string::*;
22
use crate::parser::{base64, filename, key_string, ParseResult};
23
use crate::reader::Reader;
24

            
25
720770
pub fn space(reader: &mut Reader) -> ParseResult<Whitespace> {
26
720770
    let start = reader.cursor();
27
720770
    match reader.read() {
28
5
        None => Err(ParseError::new(start.pos, true, ParseErrorKind::Space)),
29
720765
        Some(c) => {
30
720765
            if c == ' ' || c == '\t' {
31
145400
                Ok(Whitespace {
32
145400
                    value: c.to_string(),
33
145400
                    source_info: SourceInfo::new(start.pos, reader.cursor().pos),
34
145400
                })
35
            } else {
36
575365
                Err(ParseError::new(start.pos, true, ParseErrorKind::Space))
37
            }
38
        }
39
    }
40
}
41

            
42
61210
pub fn one_or_more_spaces(reader: &mut Reader) -> ParseResult<Whitespace> {
43
61210
    let start = reader.cursor();
44
61210
    match one_or_more(space, reader) {
45
61200
        Ok(v) => {
46
73460
            let s = v.iter().map(|x| x.value.clone()).collect();
47
61200
            Ok(Whitespace {
48
61200
                value: s,
49
61200
                source_info: SourceInfo::new(start.pos, reader.cursor().pos),
50
61200
            })
51
        }
52
10
        Err(e) => Err(e),
53
    }
54
}
55

            
56
520560
pub fn zero_or_more_spaces(reader: &mut Reader) -> ParseResult<Whitespace> {
57
520560
    let start = reader.cursor();
58
520560
    match zero_or_more(space, reader) {
59
        //Ok(v) => return Ok(v.join("")),
60
520560
        Ok(v) => {
61
537396
            let s = v.iter().map(|x| x.value.clone()).collect();
62
520560
            Ok(Whitespace {
63
520560
                value: s,
64
520560
                source_info: SourceInfo::new(start.pos, reader.cursor().pos),
65
520560
            })
66
        }
67
        Err(e) => Err(e),
68
    }
69
}
70

            
71
279655
pub fn line_terminator(reader: &mut Reader) -> ParseResult<LineTerminator> {
72
    // let start = p.state.clone();
73
279655
    let space0 = zero_or_more_spaces(reader)?;
74
279655
    let comment = optional(comment, reader)?;
75
279655
    let nl = if reader.is_eof() {
76
35
        Whitespace {
77
35
            value: String::new(),
78
35
            source_info: SourceInfo::new(reader.cursor().pos, reader.cursor().pos),
79
        }
80
    } else {
81
279620
        match newline(reader) {
82
130160
            Ok(r) => r,
83
149460
            Err(e) => {
84
149460
                let kind = ParseErrorKind::Expecting {
85
149460
                    value: String::from("line_terminator"),
86
149460
                };
87
149460
                return Err(ParseError::new(e.pos, false, kind));
88
            }
89
        }
90
    };
91

            
92
130195
    Ok(LineTerminator {
93
130195
        space0,
94
130195
        comment,
95
130195
        newline: nl,
96
130195
    })
97
}
98

            
99
158590
pub fn optional_line_terminators(reader: &mut Reader) -> ParseResult<Vec<LineTerminator>> {
100
242718
    zero_or_more(|p2| recover(line_terminator, p2), reader)
101
}
102

            
103
279655
pub fn comment(reader: &mut Reader) -> ParseResult<Comment> {
104
279655
    try_literal("#", reader)?;
105
11835
    let start = reader.cursor();
106
11835
    let mut value = String::new();
107
    loop {
108
471440
        if reader.is_eof() {
109
            break;
110
        }
111
471440
        let save_state = reader.cursor();
112
471440
        match newline(reader) {
113
            Ok(_) => {
114
11835
                reader.seek(save_state);
115
11835
                break;
116
            }
117
            _ => {
118
459605
                reader.seek(save_state);
119
459605
                if let Some(c) = reader.read() {
120
459605
                    value.push(c);
121
                }
122
            }
123
        }
124
    }
125
11835
    let end = reader.cursor();
126
11835
    Ok(Comment {
127
11835
        value,
128
11835
        source_info: SourceInfo::new(start.pos, end.pos),
129
11835
    })
130
}
131

            
132
/// Does not return a value, non recoverable parser. Use combinator recover to make it recoverable
133
4194870
pub fn literal(s: &str, reader: &mut Reader) -> ParseResult<()> {
134
4194870
    let start = reader.cursor();
135
4439365
    for c in s.chars() {
136
4439365
        match reader.read() {
137
            None => {
138
46155
                let kind = ParseErrorKind::Expecting {
139
46155
                    value: s.to_string(),
140
46155
                };
141
46155
                return Err(ParseError::new(start.pos, false, kind));
142
            }
143
4393210
            Some(x) => {
144
4393210
                if x != c {
145
3827450
                    let kind = ParseErrorKind::Expecting {
146
3827450
                        value: s.to_string(),
147
3827450
                    };
148
3827450
                    return Err(ParseError::new(start.pos, false, kind));
149
                } else {
150
565760
                    continue;
151
                }
152
            }
153
        }
154
    }
155
321265
    Ok(())
156
}
157

            
158
/// Recoverable version which reset the cursor, meant to be combined with following action.
159
3261625
pub fn try_literal(s: &str, reader: &mut Reader) -> ParseResult<()> {
160
3261625
    let save_state = reader.cursor();
161
3261625
    match literal(s, reader) {
162
117645
        Ok(_) => Ok(()),
163
3143980
        Err(e) => {
164
3143980
            reader.seek(save_state);
165
3143980
            Err(ParseError::new(e.pos, true, e.kind))
166
        }
167
    }
168
}
169

            
170
/// Returns the literal string
171
38395
pub fn try_literals(s1: &str, s2: &str, reader: &mut Reader) -> ParseResult<String> {
172
38395
    let start = reader.cursor();
173
38395
    match literal(s1, reader) {
174
5
        Ok(_) => Ok(s1.to_string()),
175
        Err(_) => {
176
38390
            reader.seek(start);
177
38390
            match literal(s2, reader) {
178
14340
                Ok(_) => Ok(s2.to_string()),
179
                Err(_) => {
180
24050
                    reader.seek(start);
181
24050
                    let kind = ParseErrorKind::Expecting {
182
24050
                        value: format!("<{s1}> or <{s2}>"),
183
24050
                    };
184
24050
                    Err(ParseError::new(start.pos, true, kind))
185
                }
186
            }
187
        }
188
    }
189
}
190

            
191
751885
pub fn newline(reader: &mut Reader) -> ParseResult<Whitespace> {
192
751885
    let start = reader.cursor();
193
751885
    match try_literal("\r\n", reader) {
194
        Ok(_) => Ok(Whitespace {
195
            value: "\r\n".to_string(),
196
            source_info: SourceInfo::new(start.pos, reader.cursor().pos),
197
        }),
198
751885
        Err(_) => match literal("\n", reader) {
199
142820
            Ok(_) => Ok(Whitespace {
200
142820
                value: "\n".to_string(),
201
142820
                source_info: SourceInfo::new(start.pos, reader.cursor().pos),
202
142820
            }),
203
            Err(_) => {
204
609065
                let kind = ParseErrorKind::Expecting {
205
609065
                    value: String::from("newline"),
206
609065
                };
207
609065
                Err(ParseError::new(start.pos, false, kind))
208
            }
209
        },
210
    }
211
}
212

            
213
30115
pub fn key_value(reader: &mut Reader) -> ParseResult<KeyValue> {
214
30115
    let line_terminators = optional_line_terminators(reader)?;
215
30115
    let space0 = zero_or_more_spaces(reader)?;
216
30115
    let key = recover(key_string::parse, reader)?;
217
17925
    let space1 = zero_or_more_spaces(reader)?;
218
21510
    recover(|reader1| literal(":", reader1), reader)?;
219
3895
    let space2 = zero_or_more_spaces(reader)?;
220
3895
    let value = unquoted_template(reader)?;
221
3895
    let line_terminator0 = line_terminator(reader)?;
222
3895
    Ok(KeyValue {
223
3895
        line_terminators,
224
3895
        space0,
225
3895
        key,
226
3895
        space1,
227
3895
        space2,
228
3895
        value,
229
3895
        line_terminator0,
230
3895
    })
231
}
232

            
233
35710
pub fn hex(reader: &mut Reader) -> ParseResult<Hex> {
234
35710
    try_literal("hex", reader)?;
235
1105
    literal(",", reader)?;
236
1105
    let space0 = zero_or_more_spaces(reader)?;
237
1105
    let mut value: Vec<u8> = vec![];
238
1105
    let start = reader.cursor();
239
1105
    let mut current: i32 = -1;
240
    loop {
241
29805
        let s = reader.cursor();
242
29805
        match hex_digit(reader) {
243
28700
            Ok(d) => {
244
28700
                if current != -1 {
245
14350
                    value.push((current * 16 + d as i32) as u8);
246
14350
                    current = -1;
247
14350
                } else {
248
14350
                    current = d as i32;
249
                }
250
            }
251
            Err(_) => {
252
1105
                reader.seek(s);
253
1105
                break;
254
            }
255
1105
        };
256
    }
257
1105
    if current != -1 {
258
        return Err(ParseError::new(
259
            reader.cursor().pos,
260
            false,
261
            ParseErrorKind::OddNumberOfHexDigits,
262
        ));
263
    }
264
1105
    let encoded = reader.read_from(start.index);
265
1105
    let space1 = zero_or_more_spaces(reader)?;
266
1105
    literal(";", reader)?;
267

            
268
1105
    Ok(Hex {
269
1105
        space0,
270
1105
        value,
271
1105
        encoded,
272
1105
        space1,
273
1105
    })
274
}
275

            
276
375
pub fn regex(reader: &mut Reader) -> ParseResult<Regex> {
277
375
    try_literal("/", reader)?;
278
365
    let start = reader.cursor();
279
365
    let mut s = String::new();
280

            
281
    // Hurl escaping /
282
    // in order to avoid terminating the regex
283
    // eg. \a\b/
284
    //
285
    // Other escaped sequences such as \* are part of the regex expression
286
    // They are not part of the syntax of Hurl itself.
287
    loop {
288
4870
        match reader.read() {
289
            None => {
290
                let kind = ParseErrorKind::RegexExpr {
291
                    message: "unexpected end of file".to_string(),
292
                };
293
                return Err(ParseError::new(reader.cursor().pos, false, kind));
294
            }
295
365
            Some('/') => break,
296
            Some('\\') => {
297
325
                if let Some('/') = reader.peek() {
298
20
                    reader.read();
299
20
                    s.push('/');
300
305
                } else {
301
305
                    s.push('\\');
302
                }
303
            }
304
4180
            Some(c) => s.push(c),
305
        }
306
    }
307
365
    match regex::Regex::new(s.as_str()) {
308
360
        Ok(inner) => Ok(Regex { inner }),
309
5
        Err(e) => {
310
5
            let message = match e {
311
5
                regex::Error::Syntax(s) => {
312
5
                    // The regex syntax error from the crate returns a multiline String
313
5
                    // For example
314
5
                    //     regex parse error:
315
5
                    //         x{a}
316
5
                    //           ^
317
5
                    //     error: repetition quantifier expects a valid decimal
318
5
                    //
319
5
                    // To fit nicely in Hurl Error reporting, you need an error message string that does not spread on multiple lines
320
5
                    // You will assume that the error most relevant description is on the last line
321
5
                    let lines = s.split('\n').collect::<Vec<&str>>();
322
5
                    let last_line = lines.last().expect("at least one line");
323
5
                    last_line
324
5
                        .strip_prefix("error: ")
325
5
                        .unwrap_or(last_line)
326
5
                        .to_string()
327
                }
328
                regex::Error::CompiledTooBig(_) => "Size limit exceeded".to_string(),
329
                _ => "unknown".to_string(),
330
            };
331
5
            Err(ParseError::new(
332
5
                start.pos,
333
5
                false,
334
5
                ParseErrorKind::RegexExpr { message },
335
5
            ))
336
        }
337
    }
338
}
339

            
340
16470
pub fn null(reader: &mut Reader) -> ParseResult<()> {
341
16470
    try_literal("null", reader)
342
}
343

            
344
45460
pub fn boolean(reader: &mut Reader) -> ParseResult<bool> {
345
45460
    let start = reader.cursor();
346
45460
    match try_literal("true", reader) {
347
1045
        Ok(_) => Ok(true),
348
44415
        Err(_) => match literal("false", reader) {
349
565
            Ok(_) => Ok(false),
350
            Err(_) => {
351
43850
                let kind = ParseErrorKind::Expecting {
352
43850
                    value: String::from("true|false"),
353
43850
                };
354
43850
                Err(ParseError::new(start.pos, true, kind))
355
            }
356
        },
357
    }
358
}
359

            
360
35590
pub(crate) fn file(reader: &mut Reader) -> ParseResult<File> {
361
35590
    let _start = reader.cursor();
362
35590
    try_literal("file", reader)?;
363
475
    literal(",", reader)?;
364
475
    let space0 = zero_or_more_spaces(reader)?;
365
475
    let f = filename::parse(reader)?;
366
470
    let space1 = zero_or_more_spaces(reader)?;
367
470
    literal(";", reader)?;
368
465
    Ok(File {
369
465
        space0,
370
465
        filename: f,
371
465
        space1,
372
465
    })
373
}
374

            
375
35070
pub(crate) fn base64(reader: &mut Reader) -> ParseResult<Base64> {
376
35070
    // base64 => can have whitespace
377
35070
    // support parser position
378
35070
    try_literal("base64", reader)?;
379
320
    literal(",", reader)?;
380
320
    let space0 = zero_or_more_spaces(reader)?;
381
320
    let save_state = reader.cursor();
382
320
    let value = base64::parse(reader);
383
320
    let count = reader.cursor().index - save_state.index;
384
320
    reader.seek(save_state);
385
320
    let encoded = reader.read_n(count);
386
320
    let space1 = zero_or_more_spaces(reader)?;
387
320
    literal(";", reader)?;
388
315
    Ok(Base64 {
389
315
        space0,
390
315
        value,
391
315
        encoded,
392
315
        space1,
393
315
    })
394
}
395

            
396
3755
pub fn eof(reader: &mut Reader) -> ParseResult<()> {
397
3755
    if reader.is_eof() {
398
3755
        Ok(())
399
    } else {
400
        let kind = ParseErrorKind::Expecting {
401
            value: String::from("eof"),
402
        };
403
        Err(ParseError::new(reader.cursor().pos, false, kind))
404
    }
405
}
406

            
407
30675
pub fn hex_digit_value(c: char) -> Option<u32> {
408
30675
    match c.to_ascii_lowercase() {
409
1715
        '0' => Some(0),
410
2040
        '1' => Some(1),
411
2245
        '2' => Some(2),
412
1495
        '3' => Some(3),
413
1455
        '4' => Some(4),
414
1810
        '5' => Some(5),
415
3860
        '6' => Some(6),
416
1680
        '7' => Some(7),
417
1945
        '8' => Some(8),
418
975
        '9' => Some(9),
419
975
        'a' => Some(10),
420
1270
        'b' => Some(11),
421
2380
        'c' => Some(12),
422
2195
        'd' => Some(13),
423
1285
        'e' => Some(14),
424
2035
        'f' => Some(15),
425
1315
        _ => None,
426
    }
427
}
428

            
429
30675
pub fn hex_digit(reader: &mut Reader) -> ParseResult<u32> {
430
30675
    let start = reader.cursor();
431
30675
    match reader.read() {
432
30675
        Some(c) => match hex_digit_value(c) {
433
29360
            Some(v) => Ok(v),
434
1315
            None => Err(ParseError::new(start.pos, true, ParseErrorKind::HexDigit)),
435
        },
436
        None => Err(ParseError::new(start.pos, true, ParseErrorKind::HexDigit)),
437
    }
438
}
439

            
440
#[cfg(test)]
441
mod tests {
442
    use super::*;
443
    use crate::reader::Pos;
444

            
445
    #[test]
446
    fn test_space() {
447
        let mut reader = Reader::new("x");
448
        let error = space(&mut reader).err().unwrap();
449
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
450
        assert_eq!(reader.cursor().index, 1);
451

            
452
        let mut reader = Reader::new("  ");
453
        assert_eq!(
454
            space(&mut reader),
455
            Ok(Whitespace {
456
                value: " ".to_string(),
457
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 2)),
458
            }),
459
        );
460
        assert_eq!(reader.cursor().index, 1);
461
    }
462

            
463
    #[test]
464
    fn test_one_or_more_spaces() {
465
        let mut reader = Reader::new("  ");
466
        assert_eq!(
467
            one_or_more_spaces(&mut reader),
468
            Ok(Whitespace {
469
                value: "  ".to_string(),
470
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 3)),
471
            })
472
        );
473

            
474
        let mut reader = Reader::new("abc");
475
        let error = one_or_more_spaces(&mut reader).err().unwrap();
476
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
477
    }
478

            
479
    #[test]
480
    fn test_zero_or_more_spaces() {
481
        let mut reader = Reader::new("  ");
482
        assert_eq!(
483
            zero_or_more_spaces(&mut reader),
484
            Ok(Whitespace {
485
                value: "  ".to_string(),
486
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 3)),
487
            })
488
        );
489
        assert_eq!(reader.cursor().index, 2);
490

            
491
        let mut reader = Reader::new("xxx");
492
        assert_eq!(
493
            zero_or_more_spaces(&mut reader),
494
            Ok(Whitespace {
495
                value: String::new(),
496
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
497
            })
498
        );
499
        assert_eq!(reader.cursor().index, 0);
500

            
501
        let mut reader = Reader::new(" xxx");
502
        assert_eq!(
503
            zero_or_more_spaces(&mut reader),
504
            Ok(Whitespace {
505
                value: " ".to_string(),
506
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 2)),
507
            })
508
        );
509
        assert_eq!(reader.cursor().index, 1);
510
    }
511

            
512
    #[test]
513
    fn test_comment() {
514
        //    let mut parser = Parser::init("# comment");
515
        //    assert_eq!(
516
        //        comment(&mut reader),
517
        //        Ok(Comment {
518
        //            value: " comment".to_string()
519
        //        })
520
        //    );
521
        //    assert_eq!(reader.state.cursor, 9);
522

            
523
        let mut reader = Reader::new("#\n");
524
        assert_eq!(
525
            comment(&mut reader),
526
            Ok(Comment {
527
                value: String::new(),
528
                source_info: SourceInfo::new(Pos::new(1, 2), Pos::new(1, 2)),
529
            })
530
        );
531

            
532
        let mut reader = Reader::new("# comment\n");
533
        assert_eq!(
534
            comment(&mut reader),
535
            Ok(Comment {
536
                value: " comment".to_string(),
537
                source_info: SourceInfo::new(Pos::new(1, 2), Pos::new(1, 10)),
538
            })
539
        );
540
        assert_eq!(reader.cursor().index, 9);
541

            
542
        let mut reader = Reader::new("xxx");
543
        let error = comment(&mut reader).err().unwrap();
544
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
545
        assert!(error.recoverable);
546
    }
547

            
548
    #[test]
549
    fn test_literal() {
550
        let mut reader = Reader::new("hello");
551
        assert_eq!(literal("hello", &mut reader), Ok(()));
552
        assert_eq!(reader.cursor().index, 5);
553

            
554
        let mut reader = Reader::new("");
555
        let error = literal("hello", &mut reader).err().unwrap();
556
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
557
        assert_eq!(
558
            error.kind,
559
            ParseErrorKind::Expecting {
560
                value: String::from("hello")
561
            }
562
        );
563
        assert_eq!(reader.cursor().index, 0);
564

            
565
        let mut reader = Reader::new("hi");
566
        let error = literal("hello", &mut reader).err().unwrap();
567
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
568
        assert_eq!(
569
            error.kind,
570
            ParseErrorKind::Expecting {
571
                value: String::from("hello")
572
            }
573
        );
574
        assert_eq!(reader.cursor().index, 2);
575

            
576
        let mut reader = Reader::new("he");
577
        let error = literal("hello", &mut reader).err().unwrap();
578
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
579
        assert_eq!(
580
            error.kind,
581
            ParseErrorKind::Expecting {
582
                value: String::from("hello")
583
            }
584
        );
585
        assert_eq!(reader.cursor().index, 2);
586
    }
587

            
588
    #[test]
589
    fn test_new_line() {
590
        let mut reader = Reader::new("\n");
591
        assert_eq!(
592
            newline(&mut reader).unwrap(),
593
            Whitespace {
594
                value: String::from("\n"),
595
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(2, 1)),
596
            }
597
        );
598
    }
599

            
600
    #[test]
601
    fn test_key_value() {
602
        let mut reader = Reader::new("message: hello {{name}}! # comment");
603
        assert_eq!(
604
            key_value(&mut reader).unwrap(),
605
            KeyValue {
606
                line_terminators: vec![],
607
                space0: Whitespace {
608
                    value: String::new(),
609
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
610
                },
611
                key: Template {
612
                    delimiter: None,
613
                    elements: vec![TemplateElement::String {
614
                        value: "message".to_string(),
615
                        encoded: "message".to_string(),
616
                    }],
617
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 8)),
618
                },
619
                space1: Whitespace {
620
                    value: String::new(),
621
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
622
                },
623
                space2: Whitespace {
624
                    value: " ".to_string(),
625
                    source_info: SourceInfo::new(Pos::new(1, 9), Pos::new(1, 10)),
626
                },
627
                value: Template {
628
                    delimiter: None,
629
                    elements: vec![
630
                        TemplateElement::String {
631
                            value: "hello ".to_string(),
632
                            encoded: "hello ".to_string(),
633
                        },
634
                        TemplateElement::Placeholder(Placeholder {
635
                            space0: Whitespace {
636
                                value: String::new(),
637
                                source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 18)),
638
                            },
639
                            expr: Expr {
640
                                kind: ExprKind::Variable(Variable {
641
                                    name: "name".to_string(),
642
                                    source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 22)),
643
                                }),
644
                                source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 22)),
645
                            },
646
                            space1: Whitespace {
647
                                value: String::new(),
648
                                source_info: SourceInfo::new(Pos::new(1, 22), Pos::new(1, 22)),
649
                            },
650
                        }),
651
                        TemplateElement::String {
652
                            value: "!".to_string(),
653
                            encoded: "!".to_string(),
654
                        },
655
                    ],
656
                    source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 25)),
657
                },
658
                line_terminator0: LineTerminator {
659
                    space0: Whitespace {
660
                        value: " ".to_string(),
661
                        source_info: SourceInfo::new(Pos::new(1, 25), Pos::new(1, 26)),
662
                    },
663
                    comment: Some(Comment {
664
                        value: " comment".to_string(),
665
                        source_info: SourceInfo::new(Pos::new(1, 27), Pos::new(1, 35)),
666
                    }),
667
                    newline: Whitespace {
668
                        value: String::new(),
669
                        source_info: SourceInfo::new(Pos::new(1, 35), Pos::new(1, 35)),
670
                    },
671
                },
672
            }
673
        );
674
    }
675

            
676
    #[test]
677
    fn test_key_value_template() {
678
        let mut reader = Reader::new("{{key}}: value");
679
        assert_eq!(
680
            key_value(&mut reader).unwrap(),
681
            KeyValue {
682
                line_terminators: vec![],
683
                space0: Whitespace {
684
                    value: String::new(),
685
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
686
                },
687
                key: Template {
688
                    delimiter: None,
689
                    elements: vec![TemplateElement::Placeholder(Placeholder {
690
                        space0: Whitespace {
691
                            value: String::new(),
692
                            source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 3)),
693
                        },
694
                        expr: Expr {
695
                            kind: ExprKind::Variable(Variable {
696
                                name: "key".to_string(),
697
                                source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 6)),
698
                            }),
699
                            source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 6))
700
                        },
701
                        space1: Whitespace {
702
                            value: String::new(),
703
                            source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
704
                        },
705
                    })],
706
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 8)),
707
                },
708
                space1: Whitespace {
709
                    value: String::new(),
710
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
711
                },
712
                space2: Whitespace {
713
                    value: " ".to_string(),
714
                    source_info: SourceInfo::new(Pos::new(1, 9), Pos::new(1, 10)),
715
                },
716
                value: Template {
717
                    delimiter: None,
718
                    elements: vec![TemplateElement::String {
719
                        value: "value".to_string(),
720
                        encoded: "value".to_string(),
721
                    }],
722
                    source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 15)),
723
                },
724
                line_terminator0: LineTerminator {
725
                    space0: Whitespace {
726
                        value: String::new(),
727
                        source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
728
                    },
729
                    comment: None,
730
                    newline: Whitespace {
731
                        value: String::new(),
732
                        source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
733
                    },
734
                },
735
            }
736
        );
737
        assert_eq!(reader.cursor().index, 14);
738
    }
739

            
740
    #[test]
741
    fn test_key_value_recover() {
742
        let mut reader = Reader::new("{{key");
743
        let error = key_value(&mut reader).err().unwrap();
744
        assert_eq!(error.pos, Pos { line: 1, column: 6 });
745
        assert!(error.recoverable);
746
        assert_eq!(reader.cursor().index, 5); // does not reset cursor
747

            
748
        let mut reader = Reader::new("GET http://google.fr");
749
        let error = key_value(&mut reader).err().unwrap();
750
        assert_eq!(error.pos, Pos { line: 1, column: 5 });
751
        assert!(error.recoverable);
752
        assert_eq!(reader.cursor().index, 5); // does not reset cursor
753
    }
754

            
755
    #[test]
756
    fn test_boolean() {
757
        let mut reader = Reader::new("true");
758
        assert!(boolean(&mut reader).unwrap());
759

            
760
        let mut reader = Reader::new("xxx");
761
        let error = boolean(&mut reader).err().unwrap();
762
        assert_eq!(
763
            error.kind,
764
            ParseErrorKind::Expecting {
765
                value: String::from("true|false")
766
            }
767
        );
768
        assert!(error.recoverable);
769

            
770
        let mut reader = Reader::new("trux");
771
        let error = boolean(&mut reader).err().unwrap();
772
        assert_eq!(
773
            error.kind,
774
            ParseErrorKind::Expecting {
775
                value: String::from("true|false")
776
            }
777
        );
778
        assert!(error.recoverable);
779
    }
780

            
781
    #[test]
782
    fn test_hex_digit() {
783
        let mut reader = Reader::new("0");
784
        assert_eq!(hex_digit(&mut reader).unwrap(), 0);
785

            
786
        let mut reader = Reader::new("x");
787
        let error = hex_digit(&mut reader).err().unwrap();
788
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
789
        assert_eq!(error.kind, ParseErrorKind::HexDigit);
790
        assert!(error.recoverable);
791
    }
792

            
793
    #[test]
794
    fn test_hex() {
795
        let mut reader = Reader::new("hex, ff;");
796
        assert_eq!(
797
            hex(&mut reader).unwrap(),
798
            Hex {
799
                space0: Whitespace {
800
                    value: " ".to_string(),
801
                    source_info: SourceInfo::new(Pos::new(1, 5), Pos::new(1, 6)),
802
                },
803
                value: vec![255],
804
                encoded: "ff".to_string(),
805
                space1: Whitespace {
806
                    value: String::new(),
807
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
808
                },
809
            }
810
        );
811

            
812
        let mut reader = Reader::new("hex,010203 ;");
813
        assert_eq!(
814
            hex(&mut reader).unwrap(),
815
            Hex {
816
                space0: Whitespace {
817
                    value: String::new(),
818
                    source_info: SourceInfo::new(Pos::new(1, 5), Pos::new(1, 5)),
819
                },
820
                value: vec![1, 2, 3],
821
                encoded: "010203".to_string(),
822
                space1: Whitespace {
823
                    value: " ".to_string(),
824
                    source_info: SourceInfo::new(Pos::new(1, 11), Pos::new(1, 12)),
825
                },
826
            }
827
        );
828
    }
829

            
830
    #[test]
831
    fn test_hex_error() {
832
        let mut reader = Reader::new("hex,012;");
833
        let error = hex(&mut reader).err().unwrap();
834
        assert_eq!(error.pos, Pos { line: 1, column: 8 });
835
        assert_eq!(error.kind, ParseErrorKind::OddNumberOfHexDigits);
836
    }
837

            
838
    #[test]
839
    fn test_regex() {
840
        let mut reader = Reader::new(r#"/a{3}/"#);
841
        assert_eq!(
842
            regex(&mut reader).unwrap(),
843
            Regex {
844
                inner: regex::Regex::new(r#"a{3}"#).unwrap()
845
            }
846
        );
847

            
848
        let mut reader = Reader::new(r"/a\/b/");
849
        assert_eq!(
850
            regex(&mut reader).unwrap(),
851
            Regex {
852
                inner: regex::Regex::new(r#"a/b"#).unwrap()
853
            }
854
        );
855

            
856
        let mut reader = Reader::new(r"/a\.b/");
857
        assert_eq!(
858
            regex(&mut reader).unwrap(),
859
            Regex {
860
                inner: regex::Regex::new(r"a\.b").unwrap()
861
            }
862
        );
863

            
864
        let mut reader = Reader::new(r"/\d{4}-\d{2}-\d{2}/");
865
        assert_eq!(
866
            regex(&mut reader).unwrap(),
867
            Regex {
868
                inner: regex::Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap()
869
            }
870
        );
871
    }
872

            
873
    #[test]
874
    fn test_regex_error() {
875
        let mut reader = Reader::new("xxx");
876
        let error = regex(&mut reader).err().unwrap();
877
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
878
        assert!(error.recoverable);
879

            
880
        let mut reader = Reader::new("/xxx");
881
        let error = regex(&mut reader).err().unwrap();
882
        assert_eq!(error.pos, Pos { line: 1, column: 5 });
883
        assert!(!error.recoverable);
884
        assert_eq!(
885
            error.kind,
886
            ParseErrorKind::RegexExpr {
887
                message: "unexpected end of file".to_string()
888
            }
889
        );
890

            
891
        let mut reader = Reader::new("/x{a}/");
892
        let error = regex(&mut reader).err().unwrap();
893
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
894
        assert!(!error.recoverable);
895
        assert_eq!(
896
            error.kind,
897
            ParseErrorKind::RegexExpr {
898
                message: "repetition quantifier expects a valid decimal".to_string()
899
            }
900
        );
901
    }
902

            
903
    #[test]
904
    fn test_file() {
905
        let mut reader = Reader::new("file,data.xml;");
906
        assert_eq!(
907
            file(&mut reader).unwrap(),
908
            File {
909
                space0: Whitespace {
910
                    value: String::new(),
911
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
912
                },
913
                filename: Template {
914
                    delimiter: None,
915
                    elements: vec![TemplateElement::String {
916
                        value: String::from("data.xml"),
917
                        encoded: String::from("data.xml"),
918
                    }],
919
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 14)),
920
                },
921
                space1: Whitespace {
922
                    value: String::new(),
923
                    source_info: SourceInfo::new(Pos::new(1, 14), Pos::new(1, 14)),
924
                },
925
            }
926
        );
927

            
928
        let mut reader = Reader::new("file, filename1;");
929
        assert_eq!(
930
            file(&mut reader).unwrap(),
931
            File {
932
                space0: Whitespace {
933
                    value: String::from(" "),
934
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
935
                },
936
                filename: Template {
937
                    delimiter: None,
938
                    elements: vec![TemplateElement::String {
939
                        value: String::from("filename1"),
940
                        encoded: String::from("filename1"),
941
                    }],
942
                    source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 16)),
943
                },
944
                space1: Whitespace {
945
                    value: String::new(),
946
                    source_info: SourceInfo::new(Pos::new(1, 16), Pos::new(1, 16)),
947
                },
948
            }
949
        );
950

            
951
        let mut reader = Reader::new("file, tmp/filename1;");
952
        assert_eq!(
953
            file(&mut reader).unwrap(),
954
            File {
955
                space0: Whitespace {
956
                    value: String::from(" "),
957
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
958
                },
959
                filename: Template {
960
                    delimiter: None,
961
                    elements: vec![TemplateElement::String {
962
                        value: String::from("tmp/filename1"),
963
                        encoded: String::from("tmp/filename1"),
964
                    }],
965
                    source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 20)),
966
                },
967
                space1: Whitespace {
968
                    value: String::new(),
969
                    source_info: SourceInfo::new(Pos::new(1, 20), Pos::new(1, 20)),
970
                },
971
            }
972
        );
973

            
974
        let mut reader = Reader::new(r"file, tmp/filename\ with\ spaces.txt;");
975
        assert_eq!(
976
            file(&mut reader).unwrap(),
977
            File {
978
                space0: Whitespace {
979
                    value: String::from(" "),
980
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
981
                },
982
                filename: Template {
983
                    elements: vec![TemplateElement::String {
984
                        value: String::from("tmp/filename with spaces.txt"),
985
                        encoded: String::from("tmp/filename\\ with\\ spaces.txt"),
986
                    }],
987
                    delimiter: None,
988
                    source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 37)),
989
                },
990
                space1: Whitespace {
991
                    value: String::new(),
992
                    source_info: SourceInfo::new(Pos::new(1, 37), Pos::new(1, 37)),
993
                },
994
            }
995
        );
996
    }
997

            
998
    #[test]
999
    fn test_file_error() {
        let mut reader = Reader::new("fil; filename1;");
        let error = file(&mut reader).err().unwrap();
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
        assert!(error.recoverable);
        let mut reader = Reader::new("file, filename1");
        let error = file(&mut reader).err().unwrap();
        assert_eq!(
            error.pos,
            Pos {
                line: 1,
                column: 16,
            }
        );
        assert!(!error.recoverable);
        assert_eq!(
            error.kind,
            ParseErrorKind::Expecting {
                value: String::from(";")
            }
        );
        let mut reader = Reader::new(r"file, tmp/filename\ with\ unescaped .txt;");
        let error = file(&mut reader).err().unwrap();
        assert_eq!(
            error.pos,
            Pos {
                line: 1,
                column: 37,
            }
        );
        assert!(!error.recoverable);
        assert_eq!(
            error.kind,
            ParseErrorKind::Expecting {
                value: String::from(";")
            }
        );
    }
    #[test]
    fn test_base64() {
        let mut reader = Reader::new("base64,  T WE=;xxx");
        assert_eq!(
            base64(&mut reader).unwrap(),
            Base64 {
                space0: Whitespace {
                    value: String::from("  "),
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 10)),
                },
                value: vec![77, 97],
                encoded: String::from("T WE="),
                space1: Whitespace {
                    value: String::new(),
                    source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
                },
            }
        );
        assert_eq!(reader.cursor().index, 15);
    }
}