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::parser::number::natural;
19
use crate::parser::{ParseError, ParseErrorKind, ParseResult};
20
use crate::reader::Reader;
21
use crate::typing::{Duration, DurationUnit};
22
use std::str::FromStr;
23

            
24
235
pub fn duration(reader: &mut Reader) -> ParseResult<Duration> {
25
235
    let value = natural(reader)?;
26
185
    let unit = duration_unit(reader)?;
27
180
    Ok(Duration::new(value, unit))
28
}
29

            
30
185
fn duration_unit(reader: &mut Reader) -> ParseResult<Option<DurationUnit>> {
31
185
    let pos = reader.cursor().pos;
32
492
    let s = reader.read_while(|c| c.is_ascii_alphabetic());
33
185
    if s.is_empty() {
34
30
        Ok(None)
35
    } else {
36
155
        match DurationUnit::from_str(&s) {
37
150
            Ok(unit) => Ok(Some(unit)),
38
5
            Err(_) => Err(ParseError {
39
5
                pos,
40
5
                kind: ParseErrorKind::InvalidDurationUnit(s),
41
5
                recoverable: false,
42
5
            }),
43
        }
44
    }
45
}
46

            
47
#[cfg(test)]
48
mod tests {
49
    use super::*;
50
    use crate::ast::U64;
51
    use crate::reader::Pos;
52

            
53
    use crate::typing::DurationUnit;
54

            
55
    #[test]
56
    fn test_duration_unit() {
57
        let mut reader = Reader::new("");
58
        assert!(duration_unit(&mut reader).unwrap().is_none());
59
        let mut reader = Reader::new("\n");
60
        assert!(duration_unit(&mut reader).unwrap().is_none());
61
        let mut reader = Reader::new("s\n");
62
        assert_eq!(
63
            duration_unit(&mut reader).unwrap().unwrap(),
64
            DurationUnit::Second
65
        );
66
        let mut reader = Reader::new("ms\n");
67
        assert_eq!(
68
            duration_unit(&mut reader).unwrap().unwrap(),
69
            DurationUnit::MilliSecond
70
        );
71
        let mut reader = Reader::new("m\n");
72
        assert_eq!(
73
            duration_unit(&mut reader).unwrap().unwrap(),
74
            DurationUnit::Minute
75
        );
76
    }
77

            
78
    #[test]
79
    fn test_duration_unit_error() {
80
        let mut reader = Reader::new("mms\n");
81
        let error = duration_unit(&mut reader).unwrap_err();
82
        assert_eq!(error.pos, Pos::new(1, 1));
83
        assert_eq!(
84
            error.kind,
85
            ParseErrorKind::InvalidDurationUnit("mms".to_string())
86
        );
87
    }
88

            
89
    #[test]
90
    fn test_duration() {
91
        let mut reader = Reader::new("10");
92
        assert_eq!(
93
            duration(&mut reader).unwrap(),
94
            Duration::new(U64::new(10, "10".to_string()), None)
95
        );
96
        let mut reader = Reader::new("10s");
97
        assert_eq!(
98
            duration(&mut reader).unwrap(),
99
            Duration::new(U64::new(10, "10".to_string()), Some(DurationUnit::Second))
100
        );
101
        let mut reader = Reader::new("10000ms");
102
        assert_eq!(
103
            duration(&mut reader).unwrap(),
104
            Duration::new(
105
                U64::new(10000, "10000".to_string()),
106
                Some(DurationUnit::MilliSecond)
107
            )
108
        );
109
    }
110

            
111
    #[test]
112
    fn test_duration_error() {
113
        let mut reader = Reader::new("10mms\n");
114
        let error = duration(&mut reader).unwrap_err();
115
        assert_eq!(error.pos, Pos::new(1, 3));
116
        assert_eq!(
117
            error.kind,
118
            ParseErrorKind::InvalidDurationUnit("mms".to_string())
119
        );
120
    }
121
}