use anyhow::{Context, Result, bail};
pub struct IntHandler;
impl IntHandler {
pub fn validate_and_canonicalize(
value: &str,
range: Option<&[i64; 2]>,
field_name: &str,
) -> Result<String> {
let parsed_value: i64 = value.parse().context(format!(
"Field '{}' must be a valid integer, got: '{}'",
field_name, value
))?;
if let Some([min, max]) = range {
if parsed_value < *min || parsed_value > *max {
bail!(
"Field '{}' value {} is outside allowed range [{}, {}]",
field_name,
parsed_value,
min,
max
);
}
tracing::debug!(
field_name = field_name,
input_value = value,
parsed_value = parsed_value,
min_allowed = min,
max_allowed = max,
"Integer successfully validated within range"
);
} else {
tracing::debug!(
field_name = field_name,
input_value = value,
parsed_value = parsed_value,
"Integer successfully validated (no range constraint)"
);
}
Ok(parsed_value.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_positive_integer() {
let result = IntHandler::validate_and_canonicalize("42", None, "count");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "42");
}
#[test]
fn test_valid_negative_integer() {
let result = IntHandler::validate_and_canonicalize("-42", None, "offset");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "-42");
}
#[test]
fn test_valid_zero() {
let result = IntHandler::validate_and_canonicalize("0", Some(&[-10, 10]), "value");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "0");
}
#[test]
fn test_valid_integer_within_range() {
let result = IntHandler::validate_and_canonicalize("50", Some(&[0, 100]), "step");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "50");
}
#[test]
fn test_valid_integer_at_range_boundaries() {
let result = IntHandler::validate_and_canonicalize("0", Some(&[0, 100]), "step");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "0");
let result = IntHandler::validate_and_canonicalize("100", Some(&[0, 100]), "step");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "100");
}
#[test]
fn test_integer_below_minimum() {
let result = IntHandler::validate_and_canonicalize("-5", Some(&[0, 100]), "step");
assert!(result.is_err());
}
#[test]
fn test_integer_above_maximum() {
let result = IntHandler::validate_and_canonicalize("150", Some(&[0, 100]), "step");
assert!(result.is_err());
}
#[test]
fn test_invalid_integer_format() {
let result = IntHandler::validate_and_canonicalize("abc", None, "count");
assert!(result.is_err());
}
#[test]
fn test_decimal_number_rejected() {
let result = IntHandler::validate_and_canonicalize("42.5", None, "count");
assert!(result.is_err());
}
#[test]
fn test_leading_zeros_canonicalized() {
let result = IntHandler::validate_and_canonicalize("0042", None, "count");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "42"); }
#[test]
fn test_large_integer() {
let result = IntHandler::validate_and_canonicalize("9223372036854775807", None, "big");
assert!(result.is_ok());
assert_eq!(result.unwrap(), "9223372036854775807");
}
}