1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2026 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 std::str::FromStr;
19

            
20
use super::number::natural;
21
use super::{ParseError, ParseErrorKind, ParseResult};
22

            
23
use crate::ast::Duration;
24
use crate::reader::Reader;
25
use crate::types::DurationUnit;
26

            
27
805
pub fn duration(reader: &mut Reader) -> ParseResult<Duration> {
28
805
    let value = natural(reader)?;
29
720
    let unit = duration_unit(reader)?;
30
715
    Ok(Duration::new(value, unit))
31
}
32

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

            
50
#[cfg(test)]
51
mod tests {
52
    use super::*;
53
    use crate::ast::U64;
54
    use crate::reader::Pos;
55
    use crate::types::{DurationUnit, ToSource};
56

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

            
85
    #[test]
86
    fn test_duration_unit_error() {
87
        let mut reader = Reader::new("mms\n");
88
        let error = duration_unit(&mut reader).unwrap_err();
89
        assert_eq!(error.pos, Pos::new(1, 1));
90
        assert_eq!(
91
            error.kind,
92
            ParseErrorKind::InvalidDurationUnit("mms".to_string())
93
        );
94
    }
95

            
96
    #[test]
97
    fn test_duration() {
98
        let mut reader = Reader::new("10");
99
        assert_eq!(
100
            duration(&mut reader).unwrap(),
101
            Duration::new(U64::new(10, "10".to_source()), None)
102
        );
103
        let mut reader = Reader::new("10s");
104
        assert_eq!(
105
            duration(&mut reader).unwrap(),
106
            Duration::new(U64::new(10, "10".to_source()), Some(DurationUnit::Second))
107
        );
108
        let mut reader = Reader::new("10000ms");
109
        assert_eq!(
110
            duration(&mut reader).unwrap(),
111
            Duration::new(
112
                U64::new(10000, "10000".to_source()),
113
                Some(DurationUnit::MilliSecond)
114
            )
115
        );
116
        let mut reader = Reader::new("1m");
117
        assert_eq!(
118
            duration(&mut reader).unwrap(),
119
            Duration::new(U64::new(1, "1".to_source()), Some(DurationUnit::Minute))
120
        );
121
        let mut reader = Reader::new("1h");
122
        assert_eq!(
123
            duration(&mut reader).unwrap(),
124
            Duration::new(U64::new(1, "1".to_source()), Some(DurationUnit::Hour))
125
        );
126
    }
127

            
128
    #[test]
129
    fn test_duration_error() {
130
        let mut reader = Reader::new("10mms\n");
131
        let error = duration(&mut reader).unwrap_err();
132
        assert_eq!(error.pos, Pos::new(1, 3));
133
        assert_eq!(
134
            error.kind,
135
            ParseErrorKind::InvalidDurationUnit("mms".to_string())
136
        );
137
    }
138
}