From 6ea438e6177f8fa9db26d78d561e237a09b32baf Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 28 May 2026 15:18:00 +0000 Subject: [PATCH] fix(fraction): reject NaN in Fraction::new NaN passed both the upper-bound and lower-bound comparisons because every ordered comparison against NaN is false, so an invalid value reached the constructor. Add an explicit is_nan check and a NotANumber variant so the value is rejected at the boundary instead of relying on downstream consumers to special-case NaN. https://claude.ai/code/session_01SEknK8pBtZzArSLx7wvrLj --- src/args/fraction.rs | 6 ++++++ tests/args_fraction.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/args/fraction.rs b/src/args/fraction.rs index 8a1639fc..e7bef60a 100644 --- a/src/args/fraction.rs +++ b/src/args/fraction.rs @@ -18,12 +18,18 @@ pub enum ConversionError { /// Provided value is less than 0. #[display("less than 0")] LowerBound, + /// Provided value is `NaN`. + #[display("not a number")] + NotANumber, } impl Fraction { /// Create a [`Fraction`]. pub fn new(value: f32) -> Result { use ConversionError::*; + if value.is_nan() { + return Err(NotANumber); + } if value >= 1.0 { return Err(UpperBound); } diff --git a/tests/args_fraction.rs b/tests/args_fraction.rs index d436b097..6413218f 100644 --- a/tests/args_fraction.rs +++ b/tests/args_fraction.rs @@ -48,6 +48,18 @@ fn equal_to_one() { ); } +#[test] +fn not_a_number() { + let actual_error = "NaN".parse::().expect_err("cause nan error"); + let actual_message = actual_error.to_string(); + let expected_error = Conversion(NotANumber); + let expected_message = "not a number".to_string(); + assert_eq!( + (actual_error, actual_message), + (expected_error, expected_message), + ); +} + #[test] fn invalid_float_literal() { let actual = "a"