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