Skip to main content

nt_time/file_time/
from_str.rs

1// SPDX-FileCopyrightText: 2023 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Utilities for parsing a [`FileTime`] from a string.
6
7use core::str::FromStr;
8
9use super::FileTime;
10use crate::error::ParseFileTimeError;
11
12impl FromStr for FileTime {
13    type Err = ParseFileTimeError;
14
15    fn from_str(src: &str) -> Result<Self, Self::Err> {
16        let ft = src.parse().map_err(ParseFileTimeError::new)?;
17        Ok(Self::new(ft))
18    }
19}
20
21#[cfg(test)]
22mod tests {
23    use core::{
24        error::Error,
25        num::{IntErrorKind, ParseIntError},
26    };
27    #[cfg(feature = "std")]
28    use std::string::String;
29
30    #[cfg(feature = "std")]
31    use proptest::{prop_assert, prop_assert_eq};
32    #[cfg(feature = "std")]
33    use test_strategy::proptest;
34
35    use super::*;
36
37    #[test]
38    fn from_str() {
39        assert_eq!(FileTime::from_str("0").unwrap(), FileTime::NT_TIME_EPOCH);
40        assert_eq!(FileTime::from_str("+0").unwrap(), FileTime::NT_TIME_EPOCH);
41        assert_eq!(
42            FileTime::from_str("116444736000000000").unwrap(),
43            FileTime::UNIX_EPOCH
44        );
45        assert_eq!(
46            FileTime::from_str("+116444736000000000").unwrap(),
47            FileTime::UNIX_EPOCH
48        );
49        assert_eq!(
50            FileTime::from_str("9223372036854775807").unwrap(),
51            FileTime::SIGNED_MAX
52        );
53        assert_eq!(
54            FileTime::from_str("+9223372036854775807").unwrap(),
55            FileTime::SIGNED_MAX
56        );
57        assert_eq!(
58            FileTime::from_str("18446744073709551615").unwrap(),
59            FileTime::MAX
60        );
61        assert_eq!(
62            FileTime::from_str("+18446744073709551615").unwrap(),
63            FileTime::MAX
64        );
65    }
66
67    #[cfg(feature = "std")]
68    #[proptest]
69    fn from_str_roundtrip(#[strategy(r"\+?[0-9]{1,19}")] s: String) {
70        let ft = s.parse().unwrap();
71        prop_assert_eq!(FileTime::from_str(&s).unwrap(), FileTime::new(ft));
72    }
73
74    #[test]
75    fn from_str_when_empty() {
76        assert_eq!(
77            FileTime::from_str("")
78                .unwrap_err()
79                .source()
80                .unwrap()
81                .downcast_ref::<ParseIntError>()
82                .unwrap()
83                .kind(),
84            &IntErrorKind::Empty
85        );
86    }
87
88    #[test]
89    fn from_str_with_invalid_digit() {
90        assert_eq!(
91            FileTime::from_str("a")
92                .unwrap_err()
93                .source()
94                .unwrap()
95                .downcast_ref::<ParseIntError>()
96                .unwrap()
97                .kind(),
98            &IntErrorKind::InvalidDigit
99        );
100        assert_eq!(
101            FileTime::from_str("_")
102                .unwrap_err()
103                .source()
104                .unwrap()
105                .downcast_ref::<ParseIntError>()
106                .unwrap()
107                .kind(),
108            &IntErrorKind::InvalidDigit
109        );
110        assert_eq!(
111            FileTime::from_str("-1")
112                .unwrap_err()
113                .source()
114                .unwrap()
115                .downcast_ref::<ParseIntError>()
116                .unwrap()
117                .kind(),
118            &IntErrorKind::InvalidDigit
119        );
120        assert_eq!(
121            FileTime::from_str("+")
122                .unwrap_err()
123                .source()
124                .unwrap()
125                .downcast_ref::<ParseIntError>()
126                .unwrap()
127                .kind(),
128            &IntErrorKind::InvalidDigit
129        );
130        assert_eq!(
131            FileTime::from_str("-")
132                .unwrap_err()
133                .source()
134                .unwrap()
135                .downcast_ref::<ParseIntError>()
136                .unwrap()
137                .kind(),
138            &IntErrorKind::InvalidDigit
139        );
140        assert_eq!(
141            FileTime::from_str(" 0")
142                .unwrap_err()
143                .source()
144                .unwrap()
145                .downcast_ref::<ParseIntError>()
146                .unwrap()
147                .kind(),
148            &IntErrorKind::InvalidDigit
149        );
150        assert_eq!(
151            FileTime::from_str("0 ")
152                .unwrap_err()
153                .source()
154                .unwrap()
155                .downcast_ref::<ParseIntError>()
156                .unwrap()
157                .kind(),
158            &IntErrorKind::InvalidDigit
159        );
160    }
161
162    #[cfg(feature = "std")]
163    #[proptest]
164    fn from_str_with_invalid_digit_roundtrip(#[strategy(r"-[0-9]+|[^0-9]+")] s: String) {
165        prop_assert!(FileTime::from_str(&s).is_err());
166    }
167
168    #[test]
169    fn from_str_when_positive_overflow() {
170        assert_eq!(
171            FileTime::from_str("18446744073709551616")
172                .unwrap_err()
173                .source()
174                .unwrap()
175                .downcast_ref::<ParseIntError>()
176                .unwrap()
177                .kind(),
178            &IntErrorKind::PosOverflow
179        );
180    }
181}