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::{optional, recover, zero_or_more};
20
use crate::parser::error::*;
21
use crate::parser::filter::filters;
22
use crate::parser::predicate::predicate;
23
use crate::parser::primitives::*;
24
use crate::parser::query::query;
25
use crate::parser::string::*;
26
use crate::parser::{filename, key_string, option, ParseResult};
27
use crate::reader::{Pos, Reader};
28

            
29
13280
pub fn request_sections(reader: &mut Reader) -> ParseResult<Vec<Section>> {
30
13280
    let sections = zero_or_more(request_section, reader)?;
31
13230
    Ok(sections)
32
}
33

            
34
12180
pub fn response_sections(reader: &mut Reader) -> ParseResult<Vec<Section>> {
35
12180
    let sections = zero_or_more(response_section, reader)?;
36
12125
    Ok(sections)
37
}
38

            
39
15485
fn request_section(reader: &mut Reader) -> ParseResult<Section> {
40
15485
    let line_terminators = optional_line_terminators(reader)?;
41
15485
    let space0 = zero_or_more_spaces(reader)?;
42
15485
    let start = reader.cursor();
43
15485
    let name = section_name(reader)?;
44
2360
    let source_info = SourceInfo::new(start.pos, reader.cursor().pos);
45

            
46
2360
    let line_terminator0 = line_terminator(reader)?;
47
2360
    let value = match name.as_str() {
48
2360
        "Query" => section_value_query_params(reader, true)?,
49
2265
        "QueryStringParams" => section_value_query_params(reader, false)?,
50
2040
        "BasicAuth" => section_value_basic_auth(reader)?,
51
1965
        "Form" => section_value_form_params(reader, true)?,
52
1930
        "FormParams" => section_value_form_params(reader, false)?,
53
1855
        "Multipart" => section_value_multipart_form_data(reader, true)?,
54
1820
        "MultipartFormData" => section_value_multipart_form_data(reader, false)?,
55
1710
        "Cookies" => section_value_cookies(reader)?,
56
1640
        "Options" => section_value_options(reader)?,
57
        _ => {
58
10
            let kind = ParseErrorKind::RequestSectionName { name: name.clone() };
59
10
            let pos = Pos::new(start.pos.line, start.pos.column + 1);
60
10
            return Err(ParseError::new(pos, false, kind));
61
        }
62
    };
63

            
64
2310
    Ok(Section {
65
2310
        line_terminators,
66
2310
        space0,
67
2310
        line_terminator0,
68
2310
        value,
69
2310
        source_info,
70
2310
    })
71
}
72

            
73
18950
fn response_section(reader: &mut Reader) -> ParseResult<Section> {
74
18950
    let line_terminators = optional_line_terminators(reader)?;
75
18950
    let space0 = zero_or_more_spaces(reader)?;
76
18950
    let start = reader.cursor();
77
18950
    let name = section_name(reader)?;
78
8200
    let end = reader.cursor();
79
8200
    let source_info = SourceInfo::new(start.pos, end.pos);
80

            
81
8200
    let line_terminator0 = line_terminator(reader)?;
82
8200
    let value = match name.as_str() {
83
8200
        "Captures" => section_value_captures(reader)?,
84
7795
        "Asserts" => section_value_asserts(reader)?,
85
        _ => {
86
            let kind = ParseErrorKind::ResponseSectionName { name: name.clone() };
87
            let pos = Pos::new(start.pos.line, start.pos.column + 1);
88
            return Err(ParseError::new(pos, false, kind));
89
        }
90
    };
91

            
92
8145
    Ok(Section {
93
8145
        line_terminators,
94
8145
        space0,
95
8145
        line_terminator0,
96
8145
        value,
97
8145
        source_info,
98
8145
    })
99
}
100

            
101
34435
fn section_name(reader: &mut Reader) -> ParseResult<String> {
102
34435
    let pos = reader.cursor().pos;
103
34435
    try_literal("[", reader)?;
104
90556
    let name = reader.read_while(|c| c.is_alphanumeric());
105
10605
    if name.is_empty() {
106
        // Could be the empty json array for the body
107
40
        let kind = ParseErrorKind::Expecting {
108
40
            value: "a valid section name".to_string(),
109
40
        };
110
40
        return Err(ParseError::new(pos, true, kind));
111
    }
112
10565
    try_literal("]", reader)?;
113
10560
    Ok(name)
114
}
115

            
116
320
fn section_value_query_params(reader: &mut Reader, short: bool) -> ParseResult<SectionValue> {
117
320
    let items = zero_or_more(key_value, reader)?;
118
320
    Ok(SectionValue::QueryParams(items, short))
119
}
120

            
121
75
fn section_value_basic_auth(reader: &mut Reader) -> ParseResult<SectionValue> {
122
75
    let v = optional(key_value, reader)?;
123
75
    Ok(SectionValue::BasicAuth(v))
124
}
125

            
126
110
fn section_value_form_params(reader: &mut Reader, short: bool) -> ParseResult<SectionValue> {
127
110
    let items = zero_or_more(key_value, reader)?;
128
110
    Ok(SectionValue::FormParams(items, short))
129
}
130

            
131
145
fn section_value_multipart_form_data(
132
145
    reader: &mut Reader,
133
145
    short: bool,
134
145
) -> ParseResult<SectionValue> {
135
145
    let items = zero_or_more(multipart_param, reader)?;
136
140
    Ok(SectionValue::MultipartFormData(items, short))
137
}
138

            
139
70
fn section_value_cookies(reader: &mut Reader) -> ParseResult<SectionValue> {
140
70
    let items = zero_or_more(cookie, reader)?;
141
70
    Ok(SectionValue::Cookies(items))
142
}
143

            
144
405
fn section_value_captures(reader: &mut Reader) -> ParseResult<SectionValue> {
145
405
    let items = zero_or_more(capture, reader)?;
146
405
    Ok(SectionValue::Captures(items))
147
}
148

            
149
7795
fn section_value_asserts(reader: &mut Reader) -> ParseResult<SectionValue> {
150
7795
    let asserts = zero_or_more(assert, reader)?;
151
7740
    Ok(SectionValue::Asserts(asserts))
152
}
153

            
154
1630
fn section_value_options(reader: &mut Reader) -> ParseResult<SectionValue> {
155
1630
    let options = zero_or_more(option::parse, reader)?;
156
1595
    Ok(SectionValue::Options(options))
157
}
158

            
159
140
fn cookie(reader: &mut Reader) -> ParseResult<Cookie> {
160
    // let start = reader.state.clone();
161
140
    let line_terminators = optional_line_terminators(reader)?;
162
140
    let space0 = zero_or_more_spaces(reader)?;
163
140
    let name = recover(key_string::parse, reader)?;
164
95
    let space1 = zero_or_more_spaces(reader)?;
165
114
    recover(|p1| literal(":", p1), reader)?;
166
70
    let space2 = zero_or_more_spaces(reader)?;
167
70
    let value = unquoted_template(reader)?;
168
70
    let line_terminator0 = line_terminator(reader)?;
169
70
    Ok(Cookie {
170
70
        line_terminators,
171
70
        space0,
172
70
        name,
173
70
        space1,
174
70
        space2,
175
70
        value,
176
70
        line_terminator0,
177
70
    })
178
}
179

            
180
465
fn multipart_param(reader: &mut Reader) -> ParseResult<MultipartParam> {
181
465
    let save = reader.cursor();
182
465
    match file_param(reader) {
183
200
        Ok(f) => Ok(MultipartParam::FileParam(f)),
184
265
        Err(e) => {
185
265
            if e.recoverable {
186
260
                reader.seek(save);
187
260
                let param = key_value(reader)?;
188
120
                Ok(MultipartParam::Param(param))
189
            } else {
190
5
                Err(e)
191
            }
192
        }
193
    }
194
}
195

            
196
465
fn file_param(reader: &mut Reader) -> ParseResult<FileParam> {
197
465
    let line_terminators = optional_line_terminators(reader)?;
198
465
    let space0 = zero_or_more_spaces(reader)?;
199
465
    let key = recover(key_string::parse, reader)?;
200
405
    let space1 = zero_or_more_spaces(reader)?;
201
486
    recover(|reader1| literal(":", reader1), reader)?;
202
325
    let space2 = zero_or_more_spaces(reader)?;
203
325
    let value = file_value(reader)?;
204
200
    let line_terminator0 = line_terminator(reader)?;
205
200
    Ok(FileParam {
206
200
        line_terminators,
207
200
        space0,
208
200
        key,
209
200
        space1,
210
200
        space2,
211
200
        value,
212
200
        line_terminator0,
213
200
    })
214
}
215

            
216
325
fn file_value(reader: &mut Reader) -> ParseResult<FileValue> {
217
325
    try_literal("file,", reader)?;
218
205
    let space0 = zero_or_more_spaces(reader)?;
219
205
    let f = filename::parse(reader)?;
220
205
    let space1 = zero_or_more_spaces(reader)?;
221
205
    literal(";", reader)?;
222
205
    let save = reader.cursor();
223
205
    let (space2, content_type) = match line_terminator(reader) {
224
        Ok(_) => {
225
135
            reader.seek(save);
226
135
            let space2 = Whitespace {
227
135
                value: String::new(),
228
135
                source_info: SourceInfo {
229
135
                    start: save.pos,
230
135
                    end: save.pos,
231
135
                },
232
135
            };
233
135
            (space2, None)
234
        }
235
        Err(_) => {
236
70
            reader.seek(save);
237
70
            let space2 = zero_or_more_spaces(reader)?;
238
70
            let content_type = file_content_type(reader)?;
239
65
            (space2, Some(content_type))
240
        }
241
    };
242

            
243
200
    Ok(FileValue {
244
200
        space0,
245
200
        filename: f,
246
200
        space1,
247
200
        space2,
248
200
        content_type,
249
200
    })
250
}
251

            
252
70
fn file_content_type(reader: &mut Reader) -> ParseResult<String> {
253
70
    let start = reader.cursor();
254
70
    let mut buf = String::new();
255
70
    let mut spaces = String::new();
256
70
    let mut save = reader.cursor();
257
755
    while let Some(c) = reader.read() {
258
755
        if c.is_alphanumeric() || c == '/' || c == ';' || c == '=' || c == '-' {
259
685
            buf.push_str(spaces.as_str());
260
685
            spaces = String::new();
261
685
            buf.push(c);
262
685
            save = reader.cursor();
263
685
        } else if c == ' ' {
264
            spaces.push(' ');
265
        } else {
266
70
            break;
267
        }
268
    }
269

            
270
70
    reader.seek(save);
271
70
    if buf.is_empty() {
272
5
        return Err(ParseError::new(
273
5
            start.pos,
274
5
            false,
275
5
            ParseErrorKind::FileContentType,
276
5
        ));
277
    }
278
65
    Ok(buf)
279
}
280

            
281
2230
fn capture(reader: &mut Reader) -> ParseResult<Capture> {
282
2230
    let line_terminators = optional_line_terminators(reader)?;
283
2230
    let space0 = zero_or_more_spaces(reader)?;
284
2230
    let name = recover(key_string::parse, reader)?;
285
1940
    let space1 = zero_or_more_spaces(reader)?;
286
2328
    recover(|p1| literal(":", p1), reader)?;
287
1825
    let space2 = zero_or_more_spaces(reader)?;
288
1825
    let q = query(reader)?;
289
1825
    let filters = filters(reader)?;
290
1825
    let line_terminator0 = line_terminator(reader)?;
291
1825
    Ok(Capture {
292
1825
        line_terminators,
293
1825
        space0,
294
1825
        name,
295
1825
        space1,
296
1825
        space2,
297
1825
        query: q,
298
1825
        filters,
299
1825
        line_terminator0,
300
1825
    })
301
}
302

            
303
24655
fn assert(reader: &mut Reader) -> ParseResult<Assert> {
304
24655
    let line_terminators = optional_line_terminators(reader)?;
305
24655
    let space0 = zero_or_more_spaces(reader)?;
306
24655
    let query0 = query(reader)?;
307
17480
    let filters = filters(reader)?;
308
17480
    let space1 = one_or_more_spaces(reader)?;
309
17480
    let predicate0 = predicate(reader)?;
310

            
311
17450
    let line_terminator0 = line_terminator(reader)?;
312
17450
    Ok(Assert {
313
17450
        line_terminators,
314
17450
        space0,
315
17450
        query: query0,
316
17450
        filters,
317
17450
        space1,
318
17450
        predicate: predicate0,
319
17450
        line_terminator0,
320
17450
    })
321
}
322

            
323
#[cfg(test)]
324
mod tests {
325
    use super::*;
326

            
327
    #[test]
328
    fn test_section_name() {
329
        let mut reader = Reader::new("[SectionA]");
330
        assert_eq!(section_name(&mut reader).unwrap(), String::from("SectionA"));
331

            
332
        let mut reader = Reader::new("[]");
333
        assert!(section_name(&mut reader).err().unwrap().recoverable);
334
    }
335

            
336
    #[test]
337
    fn test_asserts_section() {
338
        let mut reader = Reader::new("[Asserts]\nheader \"Location\" == \"https://google.fr\"\n");
339

            
340
        assert_eq!(
341
            response_section(&mut reader).unwrap(),
342
            Section {
343
                line_terminators: vec![],
344
                space0: Whitespace {
345
                    value: String::new(),
346
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
347
                },
348
                line_terminator0: LineTerminator {
349
                    space0: Whitespace {
350
                        value: String::new(),
351
                        source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(1, 10)),
352
                    },
353
                    comment: None,
354
                    newline: Whitespace {
355
                        value: String::from("\n"),
356
                        source_info: SourceInfo::new(Pos::new(1, 10), Pos::new(2, 1)),
357
                    },
358
                },
359
                value: SectionValue::Asserts(vec![Assert {
360
                    line_terminators: vec![],
361
                    space0: Whitespace {
362
                        value: String::new(),
363
                        source_info: SourceInfo::new(Pos::new(2, 1), Pos::new(2, 1)),
364
                    },
365
                    query: Query {
366
                        source_info: SourceInfo::new(Pos::new(2, 1), Pos::new(2, 18)),
367
                        value: QueryValue::Header {
368
                            space0: Whitespace {
369
                                value: String::from(" "),
370
                                source_info: SourceInfo::new(Pos::new(2, 7), Pos::new(2, 8)),
371
                            },
372
                            name: Template {
373
                                delimiter: Some('"'),
374
                                elements: vec![TemplateElement::String {
375
                                    value: "Location".to_string(),
376
                                    encoded: "Location".to_string(),
377
                                }],
378
                                source_info: SourceInfo::new(Pos::new(2, 8), Pos::new(2, 18)),
379
                            },
380
                        },
381
                    },
382
                    filters: vec![],
383
                    space1: Whitespace {
384
                        value: String::from(" "),
385
                        source_info: SourceInfo::new(Pos::new(2, 18), Pos::new(2, 19)),
386
                    },
387
                    predicate: Predicate {
388
                        not: false,
389
                        space0: Whitespace {
390
                            value: String::new(),
391
                            source_info: SourceInfo::new(Pos::new(2, 19), Pos::new(2, 19)),
392
                        },
393
                        predicate_func: PredicateFunc {
394
                            source_info: SourceInfo::new(Pos::new(2, 19), Pos::new(2, 41)),
395
                            value: PredicateFuncValue::Equal {
396
                                space0: Whitespace {
397
                                    value: String::from(" "),
398
                                    source_info: SourceInfo::new(Pos::new(2, 21), Pos::new(2, 22)),
399
                                },
400
                                value: PredicateValue::String(Template {
401
                                    delimiter: Some('"'),
402
                                    elements: vec![TemplateElement::String {
403
                                        value: "https://google.fr".to_string(),
404
                                        encoded: "https://google.fr".to_string(),
405
                                    }],
406
                                    source_info: SourceInfo::new(Pos::new(2, 22), Pos::new(2, 41)),
407
                                }),
408
                                operator: true,
409
                            },
410
                        },
411
                    },
412
                    line_terminator0: LineTerminator {
413
                        space0: Whitespace {
414
                            value: String::new(),
415
                            source_info: SourceInfo::new(Pos::new(2, 41), Pos::new(2, 41)),
416
                        },
417
                        comment: None,
418
                        newline: Whitespace {
419
                            value: String::from("\n"),
420
                            source_info: SourceInfo::new(Pos::new(2, 41), Pos::new(3, 1)),
421
                        },
422
                    },
423
                }]),
424
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 10)),
425
            }
426
        );
427
    }
428

            
429
    #[test]
430
    fn test_asserts_section_error() {
431
        let mut reader = Reader::new("x[Assertsx]\nheader Location == \"https://google.fr\"\n");
432
        let error = response_section(&mut reader).err().unwrap();
433
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
434
        assert_eq!(
435
            error.kind,
436
            ParseErrorKind::Expecting {
437
                value: String::from("[")
438
            }
439
        );
440
        assert!(error.recoverable);
441

            
442
        let mut reader = Reader::new("[Assertsx]\nheader Location == \"https://google.fr\"\n");
443
        let error = response_section(&mut reader).err().unwrap();
444
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
445
        assert_eq!(
446
            error.kind,
447
            ParseErrorKind::ResponseSectionName {
448
                name: String::from("Assertsx")
449
            }
450
        );
451
        assert!(!error.recoverable);
452
    }
453

            
454
    #[test]
455
    fn test_cookie() {
456
        let mut reader = Reader::new("Foo: Bar");
457
        let c = cookie(&mut reader).unwrap();
458
        assert_eq!(c.name.to_string(), String::from("Foo"));
459
        assert_eq!(
460
            c.value,
461
            Template {
462
                delimiter: None,
463
                elements: vec![TemplateElement::String {
464
                    value: "Bar".to_string(),
465
                    encoded: "Bar".to_string(),
466
                }],
467
                source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 9)),
468
            }
469
        );
470
    }
471

            
472
    #[test]
473
    fn test_cookie_error() {
474
        let mut reader = Reader::new("Foo: {{Bar");
475
        let error = cookie(&mut reader).err().unwrap();
476
        assert_eq!(
477
            error.pos,
478
            Pos {
479
                line: 1,
480
                column: 11,
481
            }
482
        );
483
        assert!(!error.recoverable);
484
        assert_eq!(
485
            error.kind,
486
            ParseErrorKind::Expecting {
487
                value: "}}".to_string()
488
            }
489
        );
490
    }
491

            
492
    #[test]
493
    fn test_file_value() {
494
        let mut reader = Reader::new("file,hello.txt;");
495
        assert_eq!(
496
            file_value(&mut reader).unwrap(),
497
            FileValue {
498
                space0: Whitespace {
499
                    value: String::new(),
500
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
501
                },
502
                filename: Template {
503
                    delimiter: None,
504
                    elements: vec![TemplateElement::String {
505
                        value: "hello.txt".to_string(),
506
                        encoded: "hello.txt".to_string(),
507
                    }],
508
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 15)),
509
                },
510
                space1: Whitespace {
511
                    value: String::new(),
512
                    source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
513
                },
514
                space2: Whitespace {
515
                    value: String::new(),
516
                    source_info: SourceInfo::new(Pos::new(1, 16), Pos::new(1, 16)),
517
                },
518
                content_type: None,
519
            }
520
        );
521
        let mut reader = Reader::new("file,hello.txt; text/html");
522
        assert_eq!(
523
            file_value(&mut reader).unwrap(),
524
            FileValue {
525
                space0: Whitespace {
526
                    value: String::new(),
527
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 6)),
528
                },
529
                filename: Template {
530
                    elements: vec![TemplateElement::String {
531
                        value: "hello.txt".to_string(),
532
                        encoded: "hello.txt".to_string(),
533
                    }],
534
                    delimiter: None,
535
                    source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 15)),
536
                },
537
                space1: Whitespace {
538
                    value: String::new(),
539
                    source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 15)),
540
                },
541
                space2: Whitespace {
542
                    value: " ".to_string(),
543
                    source_info: SourceInfo::new(Pos::new(1, 16), Pos::new(1, 17)),
544
                },
545
                content_type: Some("text/html".to_string()),
546
            }
547
        );
548
    }
549

            
550
    #[test]
551
    fn test_file_content_type() {
552
        let mut reader = Reader::new("text/html");
553
        assert_eq!(
554
            file_content_type(&mut reader).unwrap(),
555
            "text/html".to_string()
556
        );
557
        assert_eq!(reader.cursor().index, 9);
558

            
559
        let mut reader = Reader::new("text/plain; charset=us-ascii");
560
        assert_eq!(
561
            file_content_type(&mut reader).unwrap(),
562
            "text/plain; charset=us-ascii".to_string()
563
        );
564
        assert_eq!(reader.cursor().index, 28);
565

            
566
        let mut reader = Reader::new("text/html # comment");
567
        assert_eq!(
568
            file_content_type(&mut reader).unwrap(),
569
            "text/html".to_string()
570
        );
571
        assert_eq!(reader.cursor().index, 9);
572
    }
573

            
574
    #[test]
575
    fn test_capture() {
576
        let mut reader = Reader::new("url: header \"Location\"");
577
        let capture0 = capture(&mut reader).unwrap();
578

            
579
        assert_eq!(
580
            capture0.name,
581
            Template {
582
                delimiter: None,
583
                elements: vec![TemplateElement::String {
584
                    value: "url".to_string(),
585
                    encoded: "url".to_string(),
586
                }],
587
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 4)),
588
            },
589
        );
590
        assert_eq!(
591
            capture0.query,
592
            Query {
593
                source_info: SourceInfo::new(Pos::new(1, 6), Pos::new(1, 23)),
594
                value: QueryValue::Header {
595
                    space0: Whitespace {
596
                        value: String::from(" "),
597
                        source_info: SourceInfo::new(Pos::new(1, 12), Pos::new(1, 13)),
598
                    },
599
                    name: Template {
600
                        delimiter: Some('"'),
601
                        elements: vec![TemplateElement::String {
602
                            value: "Location".to_string(),
603
                            encoded: "Location".to_string(),
604
                        }],
605
                        source_info: SourceInfo::new(Pos::new(1, 13), Pos::new(1, 23)),
606
                    },
607
                },
608
            }
609
        );
610
    }
611

            
612
    #[test]
613
    fn test_capture_with_filter() {
614
        let mut reader = Reader::new("token: header \"Location\" regex \"token=(.*)\"");
615
        let capture0 = capture(&mut reader).unwrap();
616

            
617
        assert_eq!(
618
            capture0.query,
619
            Query {
620
                source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 25)),
621
                value: QueryValue::Header {
622
                    space0: Whitespace {
623
                        value: String::from(" "),
624
                        source_info: SourceInfo::new(Pos::new(1, 14), Pos::new(1, 15)),
625
                    },
626
                    name: Template {
627
                        delimiter: Some('"'),
628
                        elements: vec![TemplateElement::String {
629
                            value: "Location".to_string(),
630
                            encoded: "Location".to_string(),
631
                        }],
632
                        source_info: SourceInfo::new(Pos::new(1, 15), Pos::new(1, 25)),
633
                    },
634
                },
635
            }
636
        );
637
        assert_eq!(reader.cursor().index, 43);
638
    }
639

            
640
    #[test]
641
    fn test_capture_with_filter_error() {
642
        let mut reader = Reader::new("token: header \"Location\" regex ");
643
        let error = capture(&mut reader).err().unwrap();
644
        assert_eq!(
645
            error.pos,
646
            Pos {
647
                line: 1,
648
                column: 32,
649
            }
650
        );
651
        assert_eq!(
652
            error.kind,
653
            ParseErrorKind::Expecting {
654
                value: "\" or /".to_string()
655
            }
656
        );
657
        assert!(!error.recoverable);
658

            
659
        let mut reader = Reader::new("token: header \"Location\" xxx");
660
        let error = capture(&mut reader).err().unwrap();
661
        assert_eq!(
662
            error.pos,
663
            Pos {
664
                line: 1,
665
                column: 26,
666
            }
667
        );
668
        assert_eq!(
669
            error.kind,
670
            ParseErrorKind::Expecting {
671
                value: "line_terminator".to_string()
672
            }
673
        );
674
        assert!(!error.recoverable);
675
    }
676

            
677
    #[test]
678
    fn test_assert() {
679
        let mut reader = Reader::new("header \"Location\" == \"https://google.fr\"");
680
        let assert0 = assert(&mut reader).unwrap();
681

            
682
        assert_eq!(
683
            assert0.query,
684
            Query {
685
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 18)),
686
                value: QueryValue::Header {
687
                    space0: Whitespace {
688
                        value: String::from(" "),
689
                        source_info: SourceInfo::new(Pos::new(1, 7), Pos::new(1, 8)),
690
                    },
691
                    name: Template {
692
                        delimiter: Some('"'),
693
                        elements: vec![TemplateElement::String {
694
                            value: "Location".to_string(),
695
                            encoded: "Location".to_string(),
696
                        }],
697
                        source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 18)),
698
                    },
699
                },
700
            }
701
        );
702
    }
703

            
704
    #[test]
705
    fn test_assert_jsonpath() {
706
        let mut reader = Reader::new("jsonpath \"$.errors\" == 5");
707

            
708
        assert_eq!(
709
            assert(&mut reader).unwrap().predicate,
710
            Predicate {
711
                not: false,
712
                space0: Whitespace {
713
                    value: String::new(),
714
                    source_info: SourceInfo::new(Pos::new(1, 21), Pos::new(1, 21)),
715
                },
716
                predicate_func: PredicateFunc {
717
                    source_info: SourceInfo::new(Pos::new(1, 21), Pos::new(1, 25)),
718
                    value: PredicateFuncValue::Equal {
719
                        space0: Whitespace {
720
                            value: String::from(" "),
721
                            source_info: SourceInfo::new(Pos::new(1, 23), Pos::new(1, 24)),
722
                        },
723
                        value: PredicateValue::Number(Number::Integer(5)),
724
                        operator: true,
725
                    },
726
                },
727
            }
728
        );
729
    }
730

            
731
    #[test]
732
    fn test_basicauth_section() {
733
        let mut reader = Reader::new("[BasicAuth]\nuser:password\n\nHTTP 200\n");
734

            
735
        assert_eq!(
736
            request_section(&mut reader).unwrap(),
737
            Section {
738
                line_terminators: vec![],
739
                space0: Whitespace {
740
                    value: String::new(),
741
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
742
                },
743
                line_terminator0: LineTerminator {
744
                    space0: Whitespace {
745
                        value: String::new(),
746
                        source_info: SourceInfo::new(Pos::new(1, 12), Pos::new(1, 12)),
747
                    },
748
                    comment: None,
749
                    newline: Whitespace {
750
                        value: String::from("\n"),
751
                        source_info: SourceInfo::new(Pos::new(1, 12), Pos::new(2, 1)),
752
                    },
753
                },
754
                value: SectionValue::BasicAuth(Some(KeyValue {
755
                    line_terminators: vec![],
756
                    space0: Whitespace {
757
                        value: String::new(),
758
                        source_info: SourceInfo::new(Pos::new(2, 1), Pos::new(2, 1))
759
                    },
760
                    key: Template {
761
                        delimiter: None,
762
                        elements: vec![TemplateElement::String {
763
                            value: "user".to_string(),
764
                            encoded: "user".to_string()
765
                        }],
766
                        source_info: SourceInfo::new(Pos::new(2, 1), Pos::new(2, 5)),
767
                    },
768
                    space1: Whitespace {
769
                        value: String::new(),
770
                        source_info: SourceInfo::new(Pos::new(2, 5), Pos::new(2, 5))
771
                    },
772
                    space2: Whitespace {
773
                        value: String::new(),
774
                        source_info: SourceInfo::new(Pos::new(2, 6), Pos::new(2, 6))
775
                    },
776
                    value: Template {
777
                        delimiter: None,
778
                        elements: vec![TemplateElement::String {
779
                            value: "password".to_string(),
780
                            encoded: "password".to_string()
781
                        }],
782
                        source_info: SourceInfo::new(Pos::new(2, 6), Pos::new(2, 14)),
783
                    },
784
                    line_terminator0: LineTerminator {
785
                        space0: Whitespace {
786
                            value: String::new(),
787
                            source_info: SourceInfo::new(Pos::new(2, 14), Pos::new(2, 14))
788
                        },
789
                        comment: None,
790
                        newline: Whitespace {
791
                            value: "\n".to_string(),
792
                            source_info: SourceInfo::new(Pos::new(2, 14), Pos::new(3, 1))
793
                        },
794
                    },
795
                })),
796
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 12)),
797
            }
798
        );
799
        assert_eq!(reader.cursor().pos, Pos { line: 3, column: 1 });
800

            
801
        let mut reader = Reader::new("[BasicAuth]\nHTTP 200\n");
802
        assert_eq!(
803
            request_section(&mut reader).unwrap(),
804
            Section {
805
                line_terminators: vec![],
806
                space0: Whitespace {
807
                    value: String::new(),
808
                    source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 1)),
809
                },
810
                line_terminator0: LineTerminator {
811
                    space0: Whitespace {
812
                        value: String::new(),
813
                        source_info: SourceInfo::new(Pos::new(1, 12), Pos::new(1, 12)),
814
                    },
815
                    comment: None,
816
                    newline: Whitespace {
817
                        value: String::from("\n"),
818
                        source_info: SourceInfo::new(Pos::new(1, 12), Pos::new(2, 1)),
819
                    },
820
                },
821
                value: SectionValue::BasicAuth(None),
822
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 12)),
823
            }
824
        );
825
        assert_eq!(reader.cursor().pos, Pos { line: 2, column: 1 });
826
    }
827
}