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
    Base64, Comment, File, Hex, KeyValue, LineTerminator, Regex, SourceInfo, Whitespace,
20
};
21
use crate::combinator::{one_or_more, optional, recover, zero_or_more};
22
use crate::parser::string::unquoted_template;
23
use crate::parser::{base64, filename, key_string, ParseError, ParseErrorKind, ParseResult};
24
use crate::reader::Reader;
25

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

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

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

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

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

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

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

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

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

            
170
756135
pub fn newline(reader: &mut Reader) -> ParseResult<Whitespace> {
171
756135
    let start = reader.cursor();
172
756135
    match try_literal("\r\n", reader) {
173
        Ok(_) => Ok(Whitespace {
174
            value: "\r\n".to_string(),
175
            source_info: SourceInfo::new(start.pos, reader.cursor().pos),
176
        }),
177
756135
        Err(_) => match literal("\n", reader) {
178
143330
            Ok(_) => Ok(Whitespace {
179
143330
                value: "\n".to_string(),
180
143330
                source_info: SourceInfo::new(start.pos, reader.cursor().pos),
181
143330
            }),
182
            Err(_) => {
183
612805
                let kind = ParseErrorKind::Expecting {
184
612805
                    value: String::from("newline"),
185
612805
                };
186
612805
                Err(ParseError::new(start.pos, false, kind))
187
            }
188
        },
189
    }
190
}
191

            
192
30220
pub fn key_value(reader: &mut Reader) -> ParseResult<KeyValue> {
193
30220
    let line_terminators = optional_line_terminators(reader)?;
194
30220
    let space0 = zero_or_more_spaces(reader)?;
195
30220
    let key = recover(key_string::parse, reader)?;
196
17985
    let space1 = zero_or_more_spaces(reader)?;
197
21582
    recover(|reader1| literal(":", reader1), reader)?;
198
3940
    let space2 = zero_or_more_spaces(reader)?;
199
3940
    let value = unquoted_template(reader)?;
200
3940
    let line_terminator0 = line_terminator(reader)?;
201
3940
    Ok(KeyValue {
202
3940
        line_terminators,
203
3940
        space0,
204
3940
        key,
205
3940
        space1,
206
3940
        space2,
207
3940
        value,
208
3940
        line_terminator0,
209
3940
    })
210
}
211

            
212
35830
pub fn hex(reader: &mut Reader) -> ParseResult<Hex> {
213
35830
    try_literal("hex", reader)?;
214
1105
    literal(",", reader)?;
215
1105
    let space0 = zero_or_more_spaces(reader)?;
216
1105
    let mut value: Vec<u8> = vec![];
217
1105
    let start = reader.cursor();
218
1105
    let mut current: i32 = -1;
219
    loop {
220
29805
        let s = reader.cursor();
221
29805
        match hex_digit(reader) {
222
28700
            Ok(d) => {
223
28700
                if current != -1 {
224
14350
                    value.push((current * 16 + d as i32) as u8);
225
14350
                    current = -1;
226
14350
                } else {
227
14350
                    current = d as i32;
228
                }
229
            }
230
            Err(_) => {
231
1105
                reader.seek(s);
232
1105
                break;
233
            }
234
1105
        };
235
    }
236
1105
    if current != -1 {
237
        return Err(ParseError::new(
238
            reader.cursor().pos,
239
            false,
240
            ParseErrorKind::OddNumberOfHexDigits,
241
        ));
242
    }
243
1105
    let encoded = reader.read_from(start.index);
244
1105
    let space1 = zero_or_more_spaces(reader)?;
245
1105
    literal(";", reader)?;
246

            
247
1105
    Ok(Hex {
248
1105
        space0,
249
1105
        value,
250
1105
        encoded,
251
1105
        space1,
252
1105
    })
253
}
254

            
255
385
pub fn regex(reader: &mut Reader) -> ParseResult<Regex> {
256
385
    try_literal("/", reader)?;
257
375
    let start = reader.cursor();
258
375
    let mut s = String::new();
259

            
260
    // Hurl escaping /
261
    // in order to avoid terminating the regex
262
    // eg. \a\b/
263
    //
264
    // Other escaped sequences such as \* are part of the regex expression
265
    // They are not part of the syntax of Hurl itself.
266
    loop {
267
5170
        match reader.read() {
268
            None => {
269
                let kind = ParseErrorKind::RegexExpr {
270
                    message: "unexpected end of file".to_string(),
271
                };
272
                return Err(ParseError::new(reader.cursor().pos, false, kind));
273
            }
274
375
            Some('/') => break,
275
            Some('\\') => {
276
345
                if let Some('/') = reader.peek() {
277
20
                    reader.read();
278
20
                    s.push('/');
279
325
                } else {
280
325
                    s.push('\\');
281
                }
282
            }
283
4450
            Some(c) => s.push(c),
284
        }
285
    }
286
375
    match regex::Regex::new(s.as_str()) {
287
370
        Ok(inner) => Ok(Regex { inner }),
288
5
        Err(e) => {
289
5
            let message = match e {
290
5
                regex::Error::Syntax(s) => {
291
5
                    // The regex syntax error from the crate returns a multiline String
292
5
                    // For example
293
5
                    //     regex parse error:
294
5
                    //         x{a}
295
5
                    //           ^
296
5
                    //     error: repetition quantifier expects a valid decimal
297
5
                    //
298
5
                    // To fit nicely in Hurl Error reporting, you need an error message string that does not spread on multiple lines
299
5
                    // You will assume that the error most relevant description is on the last line
300
5
                    let lines = s.split('\n').collect::<Vec<&str>>();
301
5
                    let last_line = lines.last().expect("at least one line");
302
5
                    last_line
303
5
                        .strip_prefix("error: ")
304
5
                        .unwrap_or(last_line)
305
5
                        .to_string()
306
                }
307
                regex::Error::CompiledTooBig(_) => "Size limit exceeded".to_string(),
308
                _ => "unknown".to_string(),
309
            };
310
5
            Err(ParseError::new(
311
5
                start.pos,
312
5
                false,
313
5
                ParseErrorKind::RegexExpr { message },
314
5
            ))
315
        }
316
    }
317
}
318

            
319
16565
pub fn null(reader: &mut Reader) -> ParseResult<()> {
320
16565
    try_literal("null", reader)
321
}
322

            
323
45645
pub fn boolean(reader: &mut Reader) -> ParseResult<bool> {
324
45645
    let start = reader.cursor();
325
45645
    match try_literal("true", reader) {
326
1035
        Ok(_) => Ok(true),
327
44610
        Err(_) => match literal("false", reader) {
328
565
            Ok(_) => Ok(false),
329
            Err(_) => {
330
44045
                let kind = ParseErrorKind::Expecting {
331
44045
                    value: String::from("true|false"),
332
44045
                };
333
44045
                Err(ParseError::new(start.pos, true, kind))
334
            }
335
        },
336
    }
337
}
338

            
339
35710
pub(crate) fn file(reader: &mut Reader) -> ParseResult<File> {
340
35710
    let _start = reader.cursor();
341
35710
    try_literal("file", reader)?;
342
470
    literal(",", reader)?;
343
470
    let space0 = zero_or_more_spaces(reader)?;
344
470
    let f = filename::parse(reader)?;
345
465
    let space1 = zero_or_more_spaces(reader)?;
346
465
    literal(";", reader)?;
347
460
    Ok(File {
348
460
        space0,
349
460
        filename: f,
350
460
        space1,
351
460
    })
352
}
353

            
354
35190
pub(crate) fn base64(reader: &mut Reader) -> ParseResult<Base64> {
355
35190
    // base64 => can have whitespace
356
35190
    // support parser position
357
35190
    try_literal("base64", reader)?;
358
320
    literal(",", reader)?;
359
320
    let space0 = zero_or_more_spaces(reader)?;
360
320
    let save_state = reader.cursor();
361
320
    let value = base64::parse(reader);
362
320
    let count = reader.cursor().index - save_state.index;
363
320
    reader.seek(save_state);
364
320
    let encoded = reader.read_n(count);
365
320
    let space1 = zero_or_more_spaces(reader)?;
366
320
    literal(";", reader)?;
367
315
    Ok(Base64 {
368
315
        space0,
369
315
        value,
370
315
        encoded,
371
315
        space1,
372
315
    })
373
}
374

            
375
3785
pub fn eof(reader: &mut Reader) -> ParseResult<()> {
376
3785
    if reader.is_eof() {
377
3785
        Ok(())
378
    } else {
379
        let kind = ParseErrorKind::Expecting {
380
            value: String::from("eof"),
381
        };
382
        Err(ParseError::new(reader.cursor().pos, false, kind))
383
    }
384
}
385

            
386
30675
pub fn hex_digit_value(c: char) -> Option<u32> {
387
30675
    match c.to_ascii_lowercase() {
388
1715
        '0' => Some(0),
389
2040
        '1' => Some(1),
390
2245
        '2' => Some(2),
391
1495
        '3' => Some(3),
392
1455
        '4' => Some(4),
393
1810
        '5' => Some(5),
394
3860
        '6' => Some(6),
395
1680
        '7' => Some(7),
396
1945
        '8' => Some(8),
397
975
        '9' => Some(9),
398
975
        'a' => Some(10),
399
1270
        'b' => Some(11),
400
2380
        'c' => Some(12),
401
2195
        'd' => Some(13),
402
1285
        'e' => Some(14),
403
2035
        'f' => Some(15),
404
1315
        _ => None,
405
    }
406
}
407

            
408
30675
pub fn hex_digit(reader: &mut Reader) -> ParseResult<u32> {
409
30675
    let start = reader.cursor();
410
30675
    match reader.read() {
411
30675
        Some(c) => match hex_digit_value(c) {
412
29360
            Some(v) => Ok(v),
413
1315
            None => Err(ParseError::new(start.pos, true, ParseErrorKind::HexDigit)),
414
        },
415
        None => Err(ParseError::new(start.pos, true, ParseErrorKind::HexDigit)),
416
    }
417
}
418

            
419
#[cfg(test)]
420
mod tests {
421
    use super::*;
422
    use crate::ast::{Expr, ExprKind, Placeholder, Template, TemplateElement, Variable};
423
    use crate::reader::Pos;
424

            
425
    #[test]
426
    fn test_space() {
427
        let mut reader = Reader::new("x");
428
        let error = space(&mut reader).err().unwrap();
429
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
430
        assert_eq!(reader.cursor().index, 1);
431

            
432
        let mut reader = Reader::new("  ");
433
        assert_eq!(
434
            space(&mut reader),
435
            Ok(Whitespace {
436
                value: " ".to_string(),
437
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 2)),
438
            }),
439
        );
440
        assert_eq!(reader.cursor().index, 1);
441
    }
442

            
443
    #[test]
444
    fn test_one_or_more_spaces() {
445
        let mut reader = Reader::new("  ");
446
        assert_eq!(
447
            one_or_more_spaces(&mut reader),
448
            Ok(Whitespace {
449
                value: "  ".to_string(),
450
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 3)),
451
            })
452
        );
453

            
454
        let mut reader = Reader::new("abc");
455
        let error = one_or_more_spaces(&mut reader).err().unwrap();
456
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
457
    }
458

            
459
    #[test]
460
    fn test_zero_or_more_spaces() {
461
        let mut reader = Reader::new("  ");
462
        assert_eq!(
463
            zero_or_more_spaces(&mut reader),
464
            Ok(Whitespace {
465
                value: "  ".to_string(),
466
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 3)),
467
            })
468
        );
469
        assert_eq!(reader.cursor().index, 2);
470

            
471
        let mut reader = Reader::new("xxx");
472
        assert_eq!(
473
            zero_or_more_spaces(&mut reader),
474
            Ok(Whitespace {
475
                value: String::new(),
476
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
477
            })
478
        );
479
        assert_eq!(reader.cursor().index, 0);
480

            
481
        let mut reader = Reader::new(" xxx");
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, 2)),
487
            })
488
        );
489
        assert_eq!(reader.cursor().index, 1);
490
    }
491

            
492
    #[test]
493
    fn test_comment() {
494
        //    let mut parser = Parser::init("# comment");
495
        //    assert_eq!(
496
        //        comment(&mut reader),
497
        //        Ok(Comment {
498
        //            value: " comment".to_string()
499
        //        })
500
        //    );
501
        //    assert_eq!(reader.state.cursor, 9);
502

            
503
        let mut reader = Reader::new("#\n");
504
        assert_eq!(
505
            comment(&mut reader),
506
            Ok(Comment {
507
                value: String::new(),
508
                source_info: SourceInfo::new(Pos::new(1, 2), Pos::new(1, 2)),
509
            })
510
        );
511

            
512
        let mut reader = Reader::new("# comment\n");
513
        assert_eq!(
514
            comment(&mut reader),
515
            Ok(Comment {
516
                value: " comment".to_string(),
517
                source_info: SourceInfo::new(Pos::new(1, 2), Pos::new(1, 10)),
518
            })
519
        );
520
        assert_eq!(reader.cursor().index, 9);
521

            
522
        let mut reader = Reader::new("xxx");
523
        let error = comment(&mut reader).err().unwrap();
524
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
525
        assert!(error.recoverable);
526
    }
527

            
528
    #[test]
529
    fn test_literal() {
530
        let mut reader = Reader::new("hello");
531
        assert_eq!(literal("hello", &mut reader), Ok(()));
532
        assert_eq!(reader.cursor().index, 5);
533

            
534
        let mut reader = Reader::new("");
535
        let error = literal("hello", &mut reader).err().unwrap();
536
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
537
        assert_eq!(
538
            error.kind,
539
            ParseErrorKind::Expecting {
540
                value: String::from("hello")
541
            }
542
        );
543
        assert_eq!(reader.cursor().index, 0);
544

            
545
        let mut reader = Reader::new("hi");
546
        let error = literal("hello", &mut reader).err().unwrap();
547
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
548
        assert_eq!(
549
            error.kind,
550
            ParseErrorKind::Expecting {
551
                value: String::from("hello")
552
            }
553
        );
554
        assert_eq!(reader.cursor().index, 2);
555

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

            
568
    #[test]
569
    fn test_new_line() {
570
        let mut reader = Reader::new("\n");
571
        assert_eq!(
572
            newline(&mut reader).unwrap(),
573
            Whitespace {
574
                value: String::from("\n"),
575
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(2, 1)),
576
            }
577
        );
578
    }
579

            
580
    #[test]
581
    fn test_key_value() {
582
        let mut reader = Reader::new("message: hello {{name}}! # comment");
583
        assert_eq!(
584
            key_value(&mut reader).unwrap(),
585
            KeyValue {
586
                line_terminators: vec![],
587
                space0: Whitespace {
588
                    value: String::new(),
589
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
590
                },
591
                key: Template {
592
                    delimiter: None,
593
                    elements: vec![TemplateElement::String {
594
                        value: "message".to_string(),
595
                        encoded: "message".to_string(),
596
                    }],
597
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 8)),
598
                },
599
                space1: Whitespace {
600
                    value: String::new(),
601
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
602
                },
603
                space2: Whitespace {
604
                    value: " ".to_string(),
605
                    source_info: SourceInfo::new(Pos::new(1, 9), Pos::new(1, 10)),
606
                },
607
                value: Template {
608
                    delimiter: None,
609
                    elements: vec![
610
                        TemplateElement::String {
611
                            value: "hello ".to_string(),
612
                            encoded: "hello ".to_string(),
613
                        },
614
                        TemplateElement::Placeholder(Placeholder {
615
                            space0: Whitespace {
616
                                value: String::new(),
617
                                source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 18)),
618
                            },
619
                            expr: Expr {
620
                                kind: ExprKind::Variable(Variable {
621
                                    name: "name".to_string(),
622
                                    source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 22)),
623
                                }),
624
                                source_info: SourceInfo::new(Pos::new(1, 18), Pos::new(1, 22)),
625
                            },
626
                            space1: Whitespace {
627
                                value: String::new(),
628
                                source_info: SourceInfo::new(Pos::new(1, 22), Pos::new(1, 22)),
629
                            },
630
                        }),
631
                        TemplateElement::String {
632
                            value: "!".to_string(),
633
                            encoded: "!".to_string(),
634
                        },
635
                    ],
636
                    source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 25)),
637
                },
638
                line_terminator0: LineTerminator {
639
                    space0: Whitespace {
640
                        value: " ".to_string(),
641
                        source_info: SourceInfo::new(Pos::new(1, 25), Pos::new(1, 26)),
642
                    },
643
                    comment: Some(Comment {
644
                        value: " comment".to_string(),
645
                        source_info: SourceInfo::new(Pos::new(1, 27), Pos::new(1, 35)),
646
                    }),
647
                    newline: Whitespace {
648
                        value: String::new(),
649
                        source_info: SourceInfo::new(Pos::new(1, 35), Pos::new(1, 35)),
650
                    },
651
                },
652
            }
653
        );
654
    }
655

            
656
    #[test]
657
    fn test_key_value_template() {
658
        let mut reader = Reader::new("{{key}}: value");
659
        assert_eq!(
660
            key_value(&mut reader).unwrap(),
661
            KeyValue {
662
                line_terminators: vec![],
663
                space0: Whitespace {
664
                    value: String::new(),
665
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
666
                },
667
                key: Template {
668
                    delimiter: None,
669
                    elements: vec![TemplateElement::Placeholder(Placeholder {
670
                        space0: Whitespace {
671
                            value: String::new(),
672
                            source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 3)),
673
                        },
674
                        expr: Expr {
675
                            kind: ExprKind::Variable(Variable {
676
                                name: "key".to_string(),
677
                                source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 6)),
678
                            }),
679
                            source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 6))
680
                        },
681
                        space1: Whitespace {
682
                            value: String::new(),
683
                            source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
684
                        },
685
                    })],
686
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 8)),
687
                },
688
                space1: Whitespace {
689
                    value: String::new(),
690
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
691
                },
692
                space2: Whitespace {
693
                    value: " ".to_string(),
694
                    source_info: SourceInfo::new(Pos::new(1, 9), Pos::new(1, 10)),
695
                },
696
                value: Template {
697
                    delimiter: None,
698
                    elements: vec![TemplateElement::String {
699
                        value: "value".to_string(),
700
                        encoded: "value".to_string(),
701
                    }],
702
                    source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 15)),
703
                },
704
                line_terminator0: LineTerminator {
705
                    space0: Whitespace {
706
                        value: String::new(),
707
                        source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
708
                    },
709
                    comment: None,
710
                    newline: Whitespace {
711
                        value: String::new(),
712
                        source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
713
                    },
714
                },
715
            }
716
        );
717
        assert_eq!(reader.cursor().index, 14);
718
    }
719

            
720
    #[test]
721
    fn test_key_value_recover() {
722
        let mut reader = Reader::new("{{key");
723
        let error = key_value(&mut reader).err().unwrap();
724
        assert_eq!(error.pos, Pos { line: 1, column: 6 });
725
        assert!(error.recoverable);
726
        assert_eq!(reader.cursor().index, 5); // does not reset cursor
727

            
728
        let mut reader = Reader::new("GET ®http://google.fr");
729
        let error = key_value(&mut reader).err().unwrap();
730
        assert_eq!(error.pos, Pos { line: 1, column: 5 });
731
        assert!(error.recoverable);
732
        assert_eq!(reader.cursor().index, 5); // does not reset cursor
733
    }
734

            
735
    #[test]
736
    fn test_boolean() {
737
        let mut reader = Reader::new("true");
738
        assert!(boolean(&mut reader).unwrap());
739

            
740
        let mut reader = Reader::new("xxx");
741
        let error = boolean(&mut reader).err().unwrap();
742
        assert_eq!(
743
            error.kind,
744
            ParseErrorKind::Expecting {
745
                value: String::from("true|false")
746
            }
747
        );
748
        assert!(error.recoverable);
749

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

            
761
    #[test]
762
    fn test_hex_digit() {
763
        let mut reader = Reader::new("0");
764
        assert_eq!(hex_digit(&mut reader).unwrap(), 0);
765

            
766
        let mut reader = Reader::new("x");
767
        let error = hex_digit(&mut reader).err().unwrap();
768
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
769
        assert_eq!(error.kind, ParseErrorKind::HexDigit);
770
        assert!(error.recoverable);
771
    }
772

            
773
    #[test]
774
    fn test_hex() {
775
        let mut reader = Reader::new("hex, ff;");
776
        assert_eq!(
777
            hex(&mut reader).unwrap(),
778
            Hex {
779
                space0: Whitespace {
780
                    value: " ".to_string(),
781
                    source_info: SourceInfo::new(Pos::new(1, 5), Pos::new(1, 6)),
782
                },
783
                value: vec![255],
784
                encoded: "ff".to_string(),
785
                space1: Whitespace {
786
                    value: String::new(),
787
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
788
                },
789
            }
790
        );
791

            
792
        let mut reader = Reader::new("hex,010203 ;");
793
        assert_eq!(
794
            hex(&mut reader).unwrap(),
795
            Hex {
796
                space0: Whitespace {
797
                    value: String::new(),
798
                    source_info: SourceInfo::new(Pos::new(1, 5), Pos::new(1, 5)),
799
                },
800
                value: vec![1, 2, 3],
801
                encoded: "010203".to_string(),
802
                space1: Whitespace {
803
                    value: " ".to_string(),
804
                    source_info: SourceInfo::new(Pos::new(1, 11), Pos::new(1, 12)),
805
                },
806
            }
807
        );
808
    }
809

            
810
    #[test]
811
    fn test_hex_error() {
812
        let mut reader = Reader::new("hex,012;");
813
        let error = hex(&mut reader).err().unwrap();
814
        assert_eq!(error.pos, Pos { line: 1, column: 8 });
815
        assert_eq!(error.kind, ParseErrorKind::OddNumberOfHexDigits);
816
    }
817

            
818
    #[test]
819
    fn test_regex() {
820
        let mut reader = Reader::new(r#"/a{3}/"#);
821
        assert_eq!(
822
            regex(&mut reader).unwrap(),
823
            Regex {
824
                inner: regex::Regex::new(r#"a{3}"#).unwrap()
825
            }
826
        );
827

            
828
        let mut reader = Reader::new(r"/a\/b/");
829
        assert_eq!(
830
            regex(&mut reader).unwrap(),
831
            Regex {
832
                inner: regex::Regex::new(r#"a/b"#).unwrap()
833
            }
834
        );
835

            
836
        let mut reader = Reader::new(r"/a\.b/");
837
        assert_eq!(
838
            regex(&mut reader).unwrap(),
839
            Regex {
840
                inner: regex::Regex::new(r"a\.b").unwrap()
841
            }
842
        );
843

            
844
        let mut reader = Reader::new(r"/\d{4}-\d{2}-\d{2}/");
845
        assert_eq!(
846
            regex(&mut reader).unwrap(),
847
            Regex {
848
                inner: regex::Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap()
849
            }
850
        );
851
    }
852

            
853
    #[test]
854
    fn test_regex_error() {
855
        let mut reader = Reader::new("xxx");
856
        let error = regex(&mut reader).err().unwrap();
857
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
858
        assert!(error.recoverable);
859

            
860
        let mut reader = Reader::new("/xxx");
861
        let error = regex(&mut reader).err().unwrap();
862
        assert_eq!(error.pos, Pos { line: 1, column: 5 });
863
        assert!(!error.recoverable);
864
        assert_eq!(
865
            error.kind,
866
            ParseErrorKind::RegexExpr {
867
                message: "unexpected end of file".to_string()
868
            }
869
        );
870

            
871
        let mut reader = Reader::new("/x{a}/");
872
        let error = regex(&mut reader).err().unwrap();
873
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
874
        assert!(!error.recoverable);
875
        assert_eq!(
876
            error.kind,
877
            ParseErrorKind::RegexExpr {
878
                message: "repetition quantifier expects a valid decimal".to_string()
879
            }
880
        );
881
    }
882

            
883
    #[test]
884
    fn test_file() {
885
        let mut reader = Reader::new("file,data.xml;");
886
        assert_eq!(
887
            file(&mut reader).unwrap(),
888
            File {
889
                space0: Whitespace {
890
                    value: String::new(),
891
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
892
                },
893
                filename: Template {
894
                    delimiter: None,
895
                    elements: vec![TemplateElement::String {
896
                        value: String::from("data.xml"),
897
                        encoded: String::from("data.xml"),
898
                    }],
899
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 14)),
900
                },
901
                space1: Whitespace {
902
                    value: String::new(),
903
                    source_info: SourceInfo::new(Pos::new(1, 14), Pos::new(1, 14)),
904
                },
905
            }
906
        );
907

            
908
        let mut reader = Reader::new("file, filename1;");
909
        assert_eq!(
910
            file(&mut reader).unwrap(),
911
            File {
912
                space0: Whitespace {
913
                    value: String::from(" "),
914
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 7)),
915
                },
916
                filename: Template {
917
                    delimiter: None,
918
                    elements: vec![TemplateElement::String {
919
                        value: String::from("filename1"),
920
                        encoded: String::from("filename1"),
921
                    }],
922
                    source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 16)),
923
                },
924
                space1: Whitespace {
925
                    value: String::new(),
926
                    source_info: SourceInfo::new(Pos::new(1, 16), Pos::new(1, 16)),
927
                },
928
            }
929
        );
930

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

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

            
978
    #[test]
979
    fn test_file_error() {
980
        let mut reader = Reader::new("fil; filename1;");
981
        let error = file(&mut reader).err().unwrap();
982
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
983
        assert!(error.recoverable);
984

            
985
        let mut reader = Reader::new("file, filename1");
986
        let error = file(&mut reader).err().unwrap();
987
        assert_eq!(
988
            error.pos,
989
            Pos {
990
                line: 1,
991
                column: 16,
992
            }
993
        );
994
        assert!(!error.recoverable);
995
        assert_eq!(
996
            error.kind,
997
            ParseErrorKind::Expecting {
998
                value: String::from(";")
999
            }
        );
        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);
    }
}