mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
uucore: parser: parse_time: Handle infinity and nan
There were some missing corner cases when handling infinity and nan: - inf/infinity can be capitalized - nan must always be rejected, even if a suffix is provided Also, return Duration::MAX with infinite values, just for consistency (num.fract() returns 0 for infinity so technically we were just short of that). Add unit tests too. Fixes some of #7475.
This commit is contained in:
parent
b860ce8553
commit
94a26e170e
1 changed files with 29 additions and 9 deletions
|
@ -3,7 +3,7 @@
|
||||||
// For the full copyright and license information, please view the LICENSE
|
// For the full copyright and license information, please view the LICENSE
|
||||||
// file that was distributed with this source code.
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
// spell-checker:ignore (vars) NANOS numstr
|
// spell-checker:ignore (vars) NANOS numstr infinityh INFD nans nanh
|
||||||
//! Parsing a duration from a string.
|
//! Parsing a duration from a string.
|
||||||
//!
|
//!
|
||||||
//! Use the [`from_str`] function to parse a [`Duration`] from a string.
|
//! Use the [`from_str`] function to parse a [`Duration`] from a string.
|
||||||
|
@ -58,22 +58,23 @@ pub fn from_str(string: &str) -> Result<Duration, String> {
|
||||||
'h' => (slice, 60 * 60),
|
'h' => (slice, 60 * 60),
|
||||||
'd' => (slice, 60 * 60 * 24),
|
'd' => (slice, 60 * 60 * 24),
|
||||||
val if !val.is_alphabetic() => (string, 1),
|
val if !val.is_alphabetic() => (string, 1),
|
||||||
_ => {
|
_ => match string.to_ascii_lowercase().as_str() {
|
||||||
if string == "inf" || string == "infinity" {
|
"inf" | "infinity" => ("inf", 1),
|
||||||
("inf", 1)
|
_ => return Err(format!("invalid time interval {}", string.quote())),
|
||||||
} else {
|
},
|
||||||
return Err(format!("invalid time interval {}", string.quote()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let num = numstr
|
let num = numstr
|
||||||
.parse::<f64>()
|
.parse::<f64>()
|
||||||
.map_err(|e| format!("invalid time interval {}: {}", string.quote(), e))?;
|
.map_err(|e| format!("invalid time interval {}: {}", string.quote(), e))?;
|
||||||
|
|
||||||
if num < 0. {
|
if num < 0. || num.is_nan() {
|
||||||
return Err(format!("invalid time interval {}", string.quote()));
|
return Err(format!("invalid time interval {}", string.quote()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if num.is_infinite() {
|
||||||
|
return Ok(Duration::MAX);
|
||||||
|
}
|
||||||
|
|
||||||
const NANOS_PER_SEC: u32 = 1_000_000_000;
|
const NANOS_PER_SEC: u32 = 1_000_000_000;
|
||||||
let whole_secs = num.trunc();
|
let whole_secs = num.trunc();
|
||||||
let nanos = (num.fract() * (NANOS_PER_SEC as f64)).trunc();
|
let nanos = (num.fract() * (NANOS_PER_SEC as f64)).trunc();
|
||||||
|
@ -127,6 +128,24 @@ mod tests {
|
||||||
assert!(from_str("-1").is_err());
|
assert!(from_str("-1").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_infinity() {
|
||||||
|
assert_eq!(from_str("inf"), Ok(Duration::MAX));
|
||||||
|
assert_eq!(from_str("infinity"), Ok(Duration::MAX));
|
||||||
|
assert_eq!(from_str("infinityh"), Ok(Duration::MAX));
|
||||||
|
assert_eq!(from_str("INF"), Ok(Duration::MAX));
|
||||||
|
assert_eq!(from_str("INFs"), Ok(Duration::MAX));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nan() {
|
||||||
|
assert!(from_str("nan").is_err());
|
||||||
|
assert!(from_str("nans").is_err());
|
||||||
|
assert!(from_str("-nanh").is_err());
|
||||||
|
assert!(from_str("NAN").is_err());
|
||||||
|
assert!(from_str("-NAN").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
/// Test that capital letters are not allowed in suffixes.
|
/// Test that capital letters are not allowed in suffixes.
|
||||||
#[test]
|
#[test]
|
||||||
fn test_no_capital_letters() {
|
fn test_no_capital_letters() {
|
||||||
|
@ -134,5 +153,6 @@ mod tests {
|
||||||
assert!(from_str("1M").is_err());
|
assert!(from_str("1M").is_err());
|
||||||
assert!(from_str("1H").is_err());
|
assert!(from_str("1H").is_err());
|
||||||
assert!(from_str("1D").is_err());
|
assert!(from_str("1D").is_err());
|
||||||
|
assert!(from_str("INFD").is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue