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

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

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

            
71
731695
pub fn line_terminator(reader: &mut Reader) -> ParseResult<LineTerminator> {
72
    // let start = p.state.clone();
73
731695
    let space0 = zero_or_more_spaces(reader)?;
74
731695
    let comment = optional(comment, reader)?;
75
731695
    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
731660
        match newline(reader) {
82
151820
            Ok(r) => r,
83
579840
            Err(e) => {
84
579840
                let kind = ParseErrorKind::Expecting {
85
579840
                    value: String::from("line_terminator"),
86
579840
                };
87
579840
                return Err(ParseError::new(e.pos, false, kind));
88
            }
89
        }
90
    };
91

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

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

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

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

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

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

            
191
1156860
pub fn newline(reader: &mut Reader) -> ParseResult<Whitespace> {
192
1156860
    let start = reader.cursor();
193
1156860
    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
1156860
        Err(_) => match literal("\n", reader) {
199
163595
            Ok(_) => Ok(Whitespace {
200
163595
                value: "\n".to_string(),
201
163595
                source_info: SourceInfo::new(start.pos, reader.cursor().pos),
202
163595
            }),
203
            Err(_) => {
204
993265
                let kind = ParseErrorKind::Expecting {
205
993265
                    value: String::from("newline"),
206
993265
                };
207
993265
                Err(ParseError::new(start.pos, false, kind))
208
            }
209
        },
210
    }
211
}
212

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

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

            
268
1090
    Ok(Hex {
269
1090
        space0,
270
1090
        value,
271
1090
        encoded,
272
1090
        space1,
273
1090
    })
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
16060
pub fn null(reader: &mut Reader) -> ParseResult<()> {
341
16060
    try_literal("null", reader)
342
}
343

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

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

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

            
396
3175
pub fn eof(reader: &mut Reader) -> ParseResult<()> {
397
3175
    if reader.is_eof() {
398
3175
        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
30440
pub fn hex_digit_value(c: char) -> Option<u32> {
408
30440
    match c.to_ascii_lowercase() {
409
1700
        '0' => Some(0),
410
2035
        '1' => Some(1),
411
2240
        '2' => Some(2),
412
1475
        '3' => Some(3),
413
1455
        '4' => Some(4),
414
1795
        '5' => Some(5),
415
3800
        '6' => Some(6),
416
1680
        '7' => Some(7),
417
1945
        '8' => Some(8),
418
960
        '9' => Some(9),
419
960
        'a' => Some(10),
420
1260
        'b' => Some(11),
421
2365
        'c' => Some(12),
422
2195
        'd' => Some(13),
423
1250
        'e' => Some(14),
424
2025
        'f' => Some(15),
425
1300
        _ => None,
426
    }
427
}
428

            
429
30440
pub fn hex_digit(reader: &mut Reader) -> ParseResult<u32> {
430
30440
    let start = reader.cursor();
431
30440
    match reader.read() {
432
30440
        Some(c) => match hex_digit_value(c) {
433
29140
            Some(v) => Ok(v),
434
1300
            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::Expression(Expr {
635
                            space0: Whitespace {
636
                                value: String::new(),
637
                                source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 18)),
638
                            },
639
                            variable: Variable {
640
                                name: "name".to_string(),
641
                                source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 22)),
642
                            },
643
                            space1: Whitespace {
644
                                value: String::new(),
645
                                source_info: SourceInfo::new(Pos::new(1, 22), Pos::new(1, 22)),
646
                            },
647
                        }),
648
                        TemplateElement::String {
649
                            value: "!".to_string(),
650
                            encoded: "!".to_string(),
651
                        },
652
                    ],
653
                    source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 25)),
654
                },
655
                line_terminator0: LineTerminator {
656
                    space0: Whitespace {
657
                        value: " ".to_string(),
658
                        source_info: SourceInfo::new(Pos::new(1, 25), Pos::new(1, 26)),
659
                    },
660
                    comment: Some(Comment {
661
                        value: " comment".to_string(),
662
                        source_info: SourceInfo::new(Pos::new(1, 27), Pos::new(1, 35)),
663
                    }),
664
                    newline: Whitespace {
665
                        value: String::new(),
666
                        source_info: SourceInfo::new(Pos::new(1, 35), Pos::new(1, 35)),
667
                    },
668
                },
669
            }
670
        );
671
    }
672

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

            
734
    #[test]
735
    fn test_key_value_recover() {
736
        let mut reader = Reader::new("{{key");
737
        let error = key_value(&mut reader).err().unwrap();
738
        assert_eq!(error.pos, Pos { line: 1, column: 6 });
739
        assert!(error.recoverable);
740
        assert_eq!(reader.cursor().index, 5); // does not reset cursor
741

            
742
        let mut reader = Reader::new("GET http://google.fr");
743
        let error = key_value(&mut reader).err().unwrap();
744
        assert_eq!(error.pos, Pos { line: 1, column: 5 });
745
        assert!(error.recoverable);
746
        assert_eq!(reader.cursor().index, 5); // does not reset cursor
747
    }
748

            
749
    #[test]
750
    fn test_boolean() {
751
        let mut reader = Reader::new("true");
752
        assert!(boolean(&mut reader).unwrap());
753

            
754
        let mut reader = Reader::new("xxx");
755
        let error = boolean(&mut reader).err().unwrap();
756
        assert_eq!(
757
            error.kind,
758
            ParseErrorKind::Expecting {
759
                value: String::from("true|false")
760
            }
761
        );
762
        assert!(error.recoverable);
763

            
764
        let mut reader = Reader::new("trux");
765
        let error = boolean(&mut reader).err().unwrap();
766
        assert_eq!(
767
            error.kind,
768
            ParseErrorKind::Expecting {
769
                value: String::from("true|false")
770
            }
771
        );
772
        assert!(error.recoverable);
773
    }
774

            
775
    #[test]
776
    fn test_hex_digit() {
777
        let mut reader = Reader::new("0");
778
        assert_eq!(hex_digit(&mut reader).unwrap(), 0);
779

            
780
        let mut reader = Reader::new("x");
781
        let error = hex_digit(&mut reader).err().unwrap();
782
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
783
        assert_eq!(error.kind, ParseErrorKind::HexDigit);
784
        assert!(error.recoverable);
785
    }
786

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

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

            
824
    #[test]
825
    fn test_hex_error() {
826
        let mut reader = Reader::new("hex,012;");
827
        let error = hex(&mut reader).err().unwrap();
828
        assert_eq!(error.pos, Pos { line: 1, column: 8 });
829
        assert_eq!(error.kind, ParseErrorKind::OddNumberOfHexDigits);
830
    }
831

            
832
    #[test]
833
    fn test_regex() {
834
        let mut reader = Reader::new(r#"/a{3}/"#);
835
        assert_eq!(
836
            regex(&mut reader).unwrap(),
837
            Regex {
838
                inner: regex::Regex::new(r#"a{3}"#).unwrap()
839
            }
840
        );
841

            
842
        let mut reader = Reader::new(r"/a\/b/");
843
        assert_eq!(
844
            regex(&mut reader).unwrap(),
845
            Regex {
846
                inner: regex::Regex::new(r#"a/b"#).unwrap()
847
            }
848
        );
849

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

            
858
        let mut reader = Reader::new(r"/\d{4}-\d{2}-\d{2}/");
859
        assert_eq!(
860
            regex(&mut reader).unwrap(),
861
            Regex {
862
                inner: regex::Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap()
863
            }
864
        );
865
    }
866

            
867
    #[test]
868
    fn test_regex_error() {
869
        let mut reader = Reader::new("xxx");
870
        let error = regex(&mut reader).err().unwrap();
871
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
872
        assert!(error.recoverable);
873

            
874
        let mut reader = Reader::new("/xxx");
875
        let error = regex(&mut reader).err().unwrap();
876
        assert_eq!(error.pos, Pos { line: 1, column: 5 });
877
        assert!(!error.recoverable);
878
        assert_eq!(
879
            error.kind,
880
            ParseErrorKind::RegexExpr {
881
                message: "unexpected end of file".to_string()
882
            }
883
        );
884

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

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

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

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

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

            
992
    #[test]
993
    fn test_file_error() {
994
        let mut reader = Reader::new("fil; filename1;");
995
        let error = file(&mut reader).err().unwrap();
996
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
997
        assert!(error.recoverable);
998

            
999
        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);
    }
}