1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2025 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 crate::parser::number::natural;
21
use crate::parser::{ParseError, ParseErrorKind, ParseResult};
22
use crate::reader::Reader;
23
use crate::types::{Duration, DurationUnit};
24

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

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

            
48
#[cfg(test)]
49
mod tests {
50
    use super::*;
51
    use crate::ast::U64;
52
    use crate::reader::Pos;
53
    use crate::types::{DurationUnit, ToSource};
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
        let mut reader = Reader::new("h\n");
77
        assert_eq!(
78
            duration_unit(&mut reader).unwrap().unwrap(),
79
            DurationUnit::Hour
80
        );
81
    }
82

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

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

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