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::{choice, non_recover};
20
use crate::parser::duration::duration;
21
use crate::parser::error::*;
22
use crate::parser::number::{integer, natural, number};
23
use crate::parser::primitives::*;
24
use crate::parser::string::*;
25
use crate::parser::{filename, filename_password, ParseResult};
26
use crate::reader::Reader;
27
use crate::typing::Count;
28

            
29
use super::placeholder;
30

            
31
/// Parse an option in an `[Options]` section.
32
5005
pub fn parse(reader: &mut Reader) -> ParseResult<EntryOption> {
33
5005
    let line_terminators = optional_line_terminators(reader)?;
34
5005
    let space0 = zero_or_more_spaces(reader)?;
35
5005
    let start = reader.cursor();
36
5005
    // We accept '_' even if there is no option name with this character. We do this to be able to
37
5005
    // enter the parsing of the option name and to have better error description (ex: 'max-redirs'
38
5005
    // vs 'max_redirs').
39
5005
    let option =
40
38761
        reader.read_while(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.' || c == '_');
41
5005
    let space1 = zero_or_more_spaces(reader)?;
42
5005
    try_literal(":", reader)?;
43
3425
    let space2 = zero_or_more_spaces(reader)?;
44
3425
    let kind = match option.as_str() {
45
3425
        "aws-sigv4" => option_aws_sigv4(reader)?,
46
3385
        "cacert" => option_cacert(reader)?,
47
3325
        "cert" => option_cert(reader)?,
48
3260
        "compressed" => option_compressed(reader)?,
49
2850
        "connect-to" => option_connect_to(reader)?,
50
2785
        "connect-timeout" => option_connect_timeout(reader)?,
51
2755
        "delay" => option_delay(reader)?,
52
2660
        "insecure" => option_insecure(reader)?,
53
2560
        "http1.0" => option_http_10(reader)?,
54
2455
        "http1.1" => option_http_11(reader)?,
55
2380
        "http2" => option_http_2(reader)?,
56
2340
        "http3" => option_http_3(reader)?,
57
2310
        "ipv4" => option_ipv4(reader)?,
58
2280
        "ipv6" => option_ipv6(reader)?,
59
2250
        "key" => option_key(reader)?,
60
2200
        "limit-rate" => option_limit_rate(reader)?,
61
2165
        "location" => option_follow_location(reader)?,
62
1760
        "location-trusted" => option_follow_location_trusted(reader)?,
63
1710
        "max-redirs" => option_max_redirect(reader)?,
64
1605
        "netrc" => option_netrc(reader)?,
65
1575
        "netrc-file" => option_netrc_file(reader)?,
66
1540
        "netrc-optional" => option_netrc_optional(reader)?,
67
1510
        "output" => option_output(reader)?,
68
1380
        "path-as-is" => option_path_as_is(reader)?,
69
1345
        "proxy" => option_proxy(reader)?,
70
1275
        "repeat" => option_repeat(reader)?,
71
1195
        "resolve" => option_resolve(reader)?,
72
1145
        "retry" => option_retry(reader)?,
73
990
        "retry-interval" => option_retry_interval(reader)?,
74
880
        "skip" => option_skip(reader)?,
75
840
        "unix-socket" => option_unix_socket(reader)?,
76
810
        "user" => option_user(reader)?,
77
710
        "variable" => option_variable(reader)?,
78
155
        "verbose" => option_verbose(reader)?,
79
60
        "very-verbose" => option_very_verbose(reader)?,
80
        _ => {
81
10
            return Err(ParseError::new(
82
10
                start.pos,
83
10
                false,
84
10
                ParseErrorKind::InvalidOption(option.to_string()),
85
10
            ))
86
        }
87
    };
88

            
89
3390
    let line_terminator0 = line_terminator(reader)?;
90
3390
    Ok(EntryOption {
91
3390
        line_terminators,
92
3390
        space0,
93
3390
        space1,
94
3390
        space2,
95
3390
        kind,
96
3390
        line_terminator0,
97
3390
    })
98
}
99

            
100
40
fn option_aws_sigv4(reader: &mut Reader) -> ParseResult<OptionKind> {
101
40
    let value = unquoted_template(reader)?;
102
40
    Ok(OptionKind::AwsSigV4(value))
103
}
104

            
105
60
fn option_cacert(reader: &mut Reader) -> ParseResult<OptionKind> {
106
60
    let value = filename::parse(reader)?;
107
55
    Ok(OptionKind::CaCertificate(value))
108
}
109

            
110
65
fn option_cert(reader: &mut Reader) -> ParseResult<OptionKind> {
111
65
    let value = filename_password::parse(reader)?;
112
65
    Ok(OptionKind::ClientCert(value))
113
}
114

            
115
410
fn option_compressed(reader: &mut Reader) -> ParseResult<OptionKind> {
116
410
    let value = non_recover(boolean_option, reader)?;
117
410
    Ok(OptionKind::Compressed(value))
118
}
119

            
120
65
fn option_connect_to(reader: &mut Reader) -> ParseResult<OptionKind> {
121
65
    let value = unquoted_template(reader)?;
122
65
    Ok(OptionKind::ConnectTo(value))
123
}
124

            
125
30
fn option_connect_timeout(reader: &mut Reader) -> ParseResult<OptionKind> {
126
30
    let value = duration_option(reader)?;
127
30
    Ok(OptionKind::ConnectTimeout(value))
128
}
129

            
130
95
fn option_delay(reader: &mut Reader) -> ParseResult<OptionKind> {
131
95
    let value = duration_option(reader)?;
132
90
    Ok(OptionKind::Delay(value))
133
}
134

            
135
405
fn option_follow_location(reader: &mut Reader) -> ParseResult<OptionKind> {
136
405
    let value = non_recover(boolean_option, reader)?;
137
405
    Ok(OptionKind::FollowLocation(value))
138
}
139

            
140
50
fn option_follow_location_trusted(reader: &mut Reader) -> ParseResult<OptionKind> {
141
50
    let value = non_recover(boolean_option, reader)?;
142
50
    Ok(OptionKind::FollowLocationTrusted(value))
143
}
144

            
145
105
fn option_http_10(reader: &mut Reader) -> ParseResult<OptionKind> {
146
105
    let value = non_recover(boolean_option, reader)?;
147
105
    Ok(OptionKind::Http10(value))
148
}
149

            
150
75
fn option_http_11(reader: &mut Reader) -> ParseResult<OptionKind> {
151
75
    let value = non_recover(boolean_option, reader)?;
152
75
    Ok(OptionKind::Http11(value))
153
}
154

            
155
40
fn option_http_2(reader: &mut Reader) -> ParseResult<OptionKind> {
156
40
    let value = non_recover(boolean_option, reader)?;
157
40
    Ok(OptionKind::Http2(value))
158
}
159

            
160
30
fn option_http_3(reader: &mut Reader) -> ParseResult<OptionKind> {
161
30
    let value = non_recover(boolean_option, reader)?;
162
30
    Ok(OptionKind::Http3(value))
163
}
164

            
165
100
fn option_insecure(reader: &mut Reader) -> ParseResult<OptionKind> {
166
100
    let value = non_recover(boolean_option, reader)?;
167
95
    Ok(OptionKind::Insecure(value))
168
}
169

            
170
30
fn option_ipv4(reader: &mut Reader) -> ParseResult<OptionKind> {
171
30
    let value = non_recover(boolean_option, reader)?;
172
30
    Ok(OptionKind::IpV4(value))
173
}
174

            
175
30
fn option_ipv6(reader: &mut Reader) -> ParseResult<OptionKind> {
176
30
    let value = non_recover(boolean_option, reader)?;
177
30
    Ok(OptionKind::IpV6(value))
178
}
179

            
180
50
fn option_key(reader: &mut Reader) -> ParseResult<OptionKind> {
181
50
    let value = filename::parse(reader)?;
182
50
    Ok(OptionKind::ClientKey(value))
183
}
184

            
185
35
fn option_limit_rate(reader: &mut Reader) -> ParseResult<OptionKind> {
186
35
    let value = non_recover(natural_option, reader)?;
187
35
    Ok(OptionKind::LimitRate(value))
188
}
189

            
190
105
fn option_max_redirect(reader: &mut Reader) -> ParseResult<OptionKind> {
191
105
    let value = non_recover(count_option, reader)?;
192
105
    Ok(OptionKind::MaxRedirect(value))
193
}
194

            
195
30
fn option_netrc(reader: &mut Reader) -> ParseResult<OptionKind> {
196
30
    let value = non_recover(boolean_option, reader)?;
197
30
    Ok(OptionKind::NetRc(value))
198
}
199

            
200
35
fn option_netrc_file(reader: &mut Reader) -> ParseResult<OptionKind> {
201
35
    let value = unquoted_template(reader)?;
202
35
    Ok(OptionKind::NetRcFile(value))
203
}
204

            
205
30
fn option_netrc_optional(reader: &mut Reader) -> ParseResult<OptionKind> {
206
30
    let value = non_recover(boolean_option, reader)?;
207
30
    Ok(OptionKind::NetRcOptional(value))
208
}
209

            
210
130
fn option_output(reader: &mut Reader) -> ParseResult<OptionKind> {
211
130
    let value = filename::parse(reader)?;
212
130
    Ok(OptionKind::Output(value))
213
}
214

            
215
35
fn option_path_as_is(reader: &mut Reader) -> ParseResult<OptionKind> {
216
35
    let value = non_recover(boolean_option, reader)?;
217
35
    Ok(OptionKind::PathAsIs(value))
218
}
219

            
220
70
fn option_proxy(reader: &mut Reader) -> ParseResult<OptionKind> {
221
70
    let value = unquoted_template(reader)?;
222
70
    Ok(OptionKind::Proxy(value))
223
}
224

            
225
80
fn option_repeat(reader: &mut Reader) -> ParseResult<OptionKind> {
226
80
    let value = non_recover(count_option, reader)?;
227
80
    Ok(OptionKind::Repeat(value))
228
}
229

            
230
50
fn option_resolve(reader: &mut Reader) -> ParseResult<OptionKind> {
231
50
    let value = unquoted_template(reader)?;
232
50
    Ok(OptionKind::Resolve(value))
233
}
234

            
235
155
fn option_retry(reader: &mut Reader) -> ParseResult<OptionKind> {
236
155
    let value = non_recover(count_option, reader)?;
237
150
    Ok(OptionKind::Retry(value))
238
}
239

            
240
110
fn option_retry_interval(reader: &mut Reader) -> ParseResult<OptionKind> {
241
110
    let value = non_recover(duration_option, reader)?;
242
110
    Ok(OptionKind::RetryInterval(value))
243
}
244

            
245
40
fn option_skip(reader: &mut Reader) -> ParseResult<OptionKind> {
246
40
    let value = non_recover(boolean_option, reader)?;
247
40
    Ok(OptionKind::Skip(value))
248
}
249

            
250
100
fn option_user(reader: &mut Reader) -> ParseResult<OptionKind> {
251
100
    let value = unquoted_template(reader)?;
252
100
    Ok(OptionKind::User(value))
253
}
254

            
255
30
fn option_unix_socket(reader: &mut Reader) -> ParseResult<OptionKind> {
256
30
    let value = unquoted_template(reader)?;
257
30
    Ok(OptionKind::UnixSocket(value))
258
}
259

            
260
555
fn option_variable(reader: &mut Reader) -> ParseResult<OptionKind> {
261
555
    let value = variable_definition(reader)?;
262
550
    Ok(OptionKind::Variable(value))
263
}
264

            
265
95
fn option_verbose(reader: &mut Reader) -> ParseResult<OptionKind> {
266
95
    let value = non_recover(boolean_option, reader)?;
267
95
    Ok(OptionKind::Verbose(value))
268
}
269

            
270
50
fn option_very_verbose(reader: &mut Reader) -> ParseResult<OptionKind> {
271
50
    let value = non_recover(boolean_option, reader)?;
272
50
    Ok(OptionKind::VeryVerbose(value))
273
}
274

            
275
340
fn count(reader: &mut Reader) -> ParseResult<Count> {
276
340
    let start = reader.cursor();
277
340
    let value = non_recover(integer, reader)?;
278
240
    if value == -1 {
279
40
        Ok(Count::Infinite)
280
200
    } else if value >= 0 {
281
195
        Ok(Count::Finite(value as usize))
282
    } else {
283
5
        let kind = ParseErrorKind::Expecting {
284
5
            value: "Expecting a count value".to_string(),
285
5
        };
286
5
        Err(ParseError::new(start.pos, false, kind))
287
    }
288
}
289

            
290
1555
fn boolean_option(reader: &mut Reader) -> ParseResult<BooleanOption> {
291
1555
    let start = reader.cursor();
292
1555
    match boolean(reader) {
293
1270
        Ok(v) => Ok(BooleanOption::Literal(v)),
294
        Err(_) => {
295
285
            reader.seek(start);
296
286
            let exp = placeholder::parse(reader).map_err(|e| {
297
5
                let kind = ParseErrorKind::Expecting {
298
5
                    value: "true|false".to_string(),
299
5
                };
300
5
                ParseError::new(e.pos, false, kind)
301
286
            })?;
302
280
            Ok(BooleanOption::Placeholder(exp))
303
        }
304
    }
305
}
306

            
307
35
fn natural_option(reader: &mut Reader) -> ParseResult<NaturalOption> {
308
35
    let start = reader.cursor();
309
35
    match natural(reader) {
310
20
        Ok(v) => Ok(NaturalOption::Literal(v)),
311
        Err(_) => {
312
15
            reader.seek(start);
313
15
            let placeholder = placeholder::parse(reader).map_err(|e| {
314
                let kind = ParseErrorKind::Expecting {
315
                    value: "integer >= 0".to_string(),
316
                };
317
                ParseError::new(e.pos, false, kind)
318
15
            })?;
319
15
            Ok(NaturalOption::Placeholder(placeholder))
320
        }
321
    }
322
}
323

            
324
340
fn count_option(reader: &mut Reader) -> ParseResult<CountOption> {
325
340
    let start = reader.cursor();
326
340
    match count(reader) {
327
235
        Ok(v) => Ok(CountOption::Literal(v)),
328
        Err(_) => {
329
105
            reader.seek(start);
330
106
            let placeholder = placeholder::parse(reader).map_err(|e| {
331
5
                let kind = ParseErrorKind::Expecting {
332
5
                    value: "integer >= -1".to_string(),
333
5
                };
334
5
                ParseError::new(e.pos, false, kind)
335
106
            })?;
336
100
            Ok(CountOption::Placeholder(placeholder))
337
        }
338
    }
339
}
340

            
341
235
fn duration_option(reader: &mut Reader) -> ParseResult<DurationOption> {
342
235
    let start = reader.cursor();
343
235
    match duration(reader) {
344
180
        Ok(v) => Ok(DurationOption::Literal(v)),
345
55
        Err(e) => {
346
55
            if e.recoverable {
347
50
                reader.seek(start);
348
50
                let placeholder = placeholder::parse(reader).map_err(|e| {
349
                    let kind = ParseErrorKind::Expecting {
350
                        value: "integer".to_string(),
351
                    };
352
                    ParseError::new(e.pos, false, kind)
353
50
                })?;
354
50
                Ok(DurationOption::Placeholder(placeholder))
355
            } else {
356
5
                Err(e)
357
            }
358
        }
359
    }
360
}
361

            
362
555
fn variable_definition(reader: &mut Reader) -> ParseResult<VariableDefinition> {
363
555
    let start = reader.cursor();
364
555
    let name = variable_name(reader)?;
365
550
    let space0 = zero_or_more_spaces(reader)?;
366
550
    literal("=", reader)?;
367
550
    let space1 = zero_or_more_spaces(reader)?;
368
550
    let value = variable_value(reader)?;
369
550
    let end = reader.cursor();
370
550
    let source_info = SourceInfo {
371
550
        start: start.pos,
372
550
        end: end.pos,
373
550
    };
374
550
    Ok(VariableDefinition {
375
550
        source_info,
376
550
        name,
377
550
        space0,
378
550
        space1,
379
550
        value,
380
550
    })
381
}
382

            
383
555
fn variable_name(reader: &mut Reader) -> ParseResult<String> {
384
555
    let start = reader.cursor();
385
3161
    let name = reader.read_while(|c| c.is_alphanumeric() || c == '_' || c == '-');
386
555
    if name.is_empty() {
387
        let kind = ParseErrorKind::Expecting {
388
            value: "variable name".to_string(),
389
        };
390
        return Err(ParseError::new(start.pos, false, kind));
391
555
    } else if is_variable_reserved(&name) {
392
5
        let kind = ParseErrorKind::Variable(format!(
393
5
            "conflicts with the {name} function, use a different name"
394
5
        ));
395
5
        return Err(ParseError::new(start.pos, false, kind));
396
    }
397
550
    Ok(name)
398
}
399

            
400
550
fn variable_value(reader: &mut Reader) -> ParseResult<VariableValue> {
401
550
    choice(
402
550
        &[
403
660
            |p1| match null(p1) {
404
15
                Ok(()) => Ok(VariableValue::Null),
405
535
                Err(e) => Err(e),
406
660
            },
407
657
            |p1| match boolean(p1) {
408
20
                Ok(value) => Ok(VariableValue::Bool(value)),
409
515
                Err(e) => Err(e),
410
657
            },
411
653
            |p1| match number(p1) {
412
195
                Ok(value) => Ok(VariableValue::Number(value)),
413
320
                Err(e) => Err(e),
414
653
            },
415
614
            |p1| match quoted_template(p1) {
416
                Ok(value) => Ok(VariableValue::String(value)),
417
320
                Err(e) => Err(e),
418
614
            },
419
614
            |p1| match unquoted_template(p1) {
420
320
                Ok(value) => Ok(VariableValue::String(value)),
421
                Err(e) => Err(e),
422
614
            },
423
550
        ],
424
550
        reader,
425
550
    )
426
550
    .map_err(|e| {
427
        let kind = ParseErrorKind::Expecting {
428
            value: "variable value".to_string(),
429
        };
430
        ParseError::new(e.pos, false, kind)
431
550
    })
432
}
433

            
434
#[cfg(test)]
435
mod tests {
436
    use super::*;
437
    use crate::reader::Pos;
438

            
439
    #[test]
440
    fn test_option_insecure() {
441
        let mut reader = Reader::new("insecure: true");
442
        let option = parse(&mut reader).unwrap();
443
        assert_eq!(
444
            option,
445
            EntryOption {
446
                line_terminators: vec![],
447
                space0: Whitespace {
448
                    value: String::new(),
449
                    source_info: SourceInfo {
450
                        start: Pos { line: 1, column: 1 },
451
                        end: Pos { line: 1, column: 1 },
452
                    },
453
                },
454
                space1: Whitespace {
455
                    value: String::new(),
456
                    source_info: SourceInfo {
457
                        start: Pos { line: 1, column: 9 },
458
                        end: Pos { line: 1, column: 9 },
459
                    },
460
                },
461
                space2: Whitespace {
462
                    value: " ".to_string(),
463
                    source_info: SourceInfo {
464
                        start: Pos {
465
                            line: 1,
466
                            column: 10,
467
                        },
468
                        end: Pos {
469
                            line: 1,
470
                            column: 11,
471
                        },
472
                    },
473
                },
474
                kind: OptionKind::Insecure(BooleanOption::Literal(true)),
475
                line_terminator0: LineTerminator {
476
                    space0: Whitespace {
477
                        value: String::new(),
478
                        source_info: SourceInfo {
479
                            start: Pos {
480
                                line: 1,
481
                                column: 15,
482
                            },
483
                            end: Pos {
484
                                line: 1,
485
                                column: 15,
486
                            },
487
                        },
488
                    },
489
                    comment: None,
490
                    newline: Whitespace {
491
                        value: String::new(),
492
                        source_info: SourceInfo {
493
                            start: Pos {
494
                                line: 1,
495
                                column: 15,
496
                            },
497
                            end: Pos {
498
                                line: 1,
499
                                column: 15,
500
                            },
501
                        },
502
                    },
503
                },
504
            }
505
        );
506
    }
507

            
508
    #[test]
509
    fn test_option_insecure_error() {
510
        let mut reader = Reader::new("insecure: error");
511
        let error = parse(&mut reader).err().unwrap();
512
        assert!(!error.recoverable);
513
    }
514

            
515
    #[test]
516
    fn test_option_cacert() {
517
        let mut reader = Reader::new("cacert: /home/foo/cert.pem");
518
        let option = parse(&mut reader).unwrap();
519
        assert_eq!(
520
            option,
521
            EntryOption {
522
                line_terminators: vec![],
523
                space0: Whitespace {
524
                    value: String::new(),
525
                    source_info: SourceInfo {
526
                        start: Pos { line: 1, column: 1 },
527
                        end: Pos { line: 1, column: 1 },
528
                    },
529
                },
530
                space1: Whitespace {
531
                    value: String::new(),
532
                    source_info: SourceInfo {
533
                        start: Pos { line: 1, column: 7 },
534
                        end: Pos { line: 1, column: 7 },
535
                    },
536
                },
537
                space2: Whitespace {
538
                    value: " ".to_string(),
539
                    source_info: SourceInfo {
540
                        start: Pos { line: 1, column: 8 },
541
                        end: Pos { line: 1, column: 9 },
542
                    },
543
                },
544
                kind: OptionKind::CaCertificate(Template {
545
                    delimiter: None,
546
                    elements: vec![TemplateElement::String {
547
                        value: "/home/foo/cert.pem".to_string(),
548
                        encoded: "/home/foo/cert.pem".to_string()
549
                    }],
550
                    source_info: SourceInfo {
551
                        start: Pos { line: 1, column: 9 },
552
                        end: Pos {
553
                            line: 1,
554
                            column: 27,
555
                        },
556
                    },
557
                }),
558
                line_terminator0: LineTerminator {
559
                    space0: Whitespace {
560
                        value: String::new(),
561
                        source_info: SourceInfo {
562
                            start: Pos {
563
                                line: 1,
564
                                column: 27,
565
                            },
566
                            end: Pos {
567
                                line: 1,
568
                                column: 27,
569
                            },
570
                        },
571
                    },
572
                    comment: None,
573
                    newline: Whitespace {
574
                        value: String::new(),
575
                        source_info: SourceInfo {
576
                            start: Pos {
577
                                line: 1,
578
                                column: 27,
579
                            },
580
                            end: Pos {
581
                                line: 1,
582
                                column: 27,
583
                            },
584
                        },
585
                    },
586
                },
587
            }
588
        );
589
    }
590

            
591
    #[test]
592
    fn test_option_cacert_error() {
593
        let mut reader = Reader::new("cacert: ###");
594
        let error = parse(&mut reader).err().unwrap();
595
        assert!(!error.recoverable);
596
    }
597

            
598
    #[test]
599
    fn test_option_cert() {
600
        let mut reader = Reader::new("/etc/client-cert.pem #foo");
601

            
602
        assert_eq!(
603
            option_cert(&mut reader).unwrap(),
604
            OptionKind::ClientCert(Template {
605
                delimiter: None,
606
                elements: vec![TemplateElement::String {
607
                    value: "/etc/client-cert.pem".to_string(),
608
                    encoded: "/etc/client-cert.pem".to_string()
609
                }],
610
                source_info: SourceInfo {
611
                    start: Pos { line: 1, column: 1 },
612
                    end: Pos {
613
                        line: 1,
614
                        column: 21,
615
                    },
616
                },
617
            }),
618
        );
619
    }
620

            
621
    #[test]
622
    fn test_option_retry_error() {
623
        let mut reader = Reader::new("retry: ###");
624
        let error = parse(&mut reader).err().unwrap();
625
        assert!(!error.recoverable);
626
        assert_eq!(error.pos, Pos { line: 1, column: 8 });
627
        assert_eq!(
628
            error.kind,
629
            ParseErrorKind::Expecting {
630
                value: "integer >= -1".to_string()
631
            }
632
        );
633
    }
634

            
635
    #[test]
636
    fn test_variable_definition() {
637
        let mut reader = Reader::new("a=1");
638
        assert_eq!(
639
            variable_definition(&mut reader).unwrap(),
640
            VariableDefinition {
641
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 4)),
642
                name: "a".to_string(),
643
                space0: Whitespace {
644
                    value: String::new(),
645
                    source_info: SourceInfo::new(Pos::new(1, 2), Pos::new(1, 2)),
646
                },
647
                space1: Whitespace {
648
                    value: String::new(),
649
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 3)),
650
                },
651
                value: VariableValue::Number(Number::Integer(1)),
652
            }
653
        );
654
    }
655

            
656
    #[test]
657
    fn test_variable_value() {
658
        let mut reader = Reader::new("null");
659
        assert_eq!(variable_value(&mut reader).unwrap(), VariableValue::Null);
660

            
661
        let mut reader = Reader::new("true");
662
        assert_eq!(
663
            variable_value(&mut reader).unwrap(),
664
            VariableValue::Bool(true)
665
        );
666

            
667
        let mut reader = Reader::new("1");
668
        assert_eq!(
669
            variable_value(&mut reader).unwrap(),
670
            VariableValue::Number(Number::Integer(1))
671
        );
672

            
673
        let mut reader = Reader::new("toto");
674
        assert_eq!(
675
            variable_value(&mut reader).unwrap(),
676
            VariableValue::String(Template {
677
                delimiter: None,
678
                elements: vec![TemplateElement::String {
679
                    value: "toto".to_string(),
680
                    encoded: "toto".to_string(),
681
                }],
682
                source_info: SourceInfo {
683
                    start: Pos { line: 1, column: 1 },
684
                    end: Pos { line: 1, column: 5 },
685
                },
686
            })
687
        );
688
        let mut reader = Reader::new("\"123\"");
689
        assert_eq!(
690
            variable_value(&mut reader).unwrap(),
691
            VariableValue::String(Template {
692
                delimiter: Some('"'),
693
                elements: vec![TemplateElement::String {
694
                    value: "123".to_string(),
695
                    encoded: "123".to_string(),
696
                }],
697
                source_info: SourceInfo {
698
                    start: Pos { line: 1, column: 1 },
699
                    end: Pos { line: 1, column: 6 },
700
                },
701
            })
702
        );
703
    }
704
}