feat: Add natural language duration parsing to validate_duration
- Support parsing strings like '1 hour', '7 days' in addition to plain numbers - Maintain backwards compatibility with numeric input (e.g., '24') - Support units: hour(s), hr(s), day(s) - Add comprehensive test suite using rstest - Enforce 1-720 hour limit (1 hour to 30 days) - Provide clear error messages for invalid input
This commit is contained in:
@@ -51,12 +51,52 @@ pub fn validate_slots(text: &str) -> Result<i32, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_duration(text: &str) -> Result<ListingDuration, String> {
|
pub fn validate_duration(text: &str) -> Result<ListingDuration, String> {
|
||||||
match text.parse::<i32>() {
|
let text = text.trim().to_lowercase();
|
||||||
Ok(hours) if (1..=720).contains(&hours) => Ok(ListingDuration::hours(hours)), // 1 hour to 30 days
|
|
||||||
Ok(_) => Err(
|
// Try to parse as plain number first (backwards compatibility)
|
||||||
"❌ Duration must be between 1 and 720 hours. Please enter a valid number:".to_string(),
|
if let Ok(hours) = text.parse::<i32>() {
|
||||||
),
|
if (1..=720).contains(&hours) {
|
||||||
Err(_) => Err("❌ Invalid number. Please enter number of hours (1-720):".to_string()),
|
return Ok(ListingDuration::hours(hours));
|
||||||
|
} else {
|
||||||
|
return Err("❌ Duration must be between 1 hour and 30 days (720 hours). Please enter a valid duration:".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse natural language duration
|
||||||
|
let parts: Vec<&str> = text.split_whitespace().collect();
|
||||||
|
if parts.len() != 2 {
|
||||||
|
return Err(
|
||||||
|
"❌ Please enter duration like '1 hour', '7 days', or just hours (1-720):".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let number_str = parts[0];
|
||||||
|
let unit = parts[1];
|
||||||
|
|
||||||
|
let number = match number_str.parse::<i32>() {
|
||||||
|
Ok(n) if n > 0 => n,
|
||||||
|
_ => {
|
||||||
|
return Err(
|
||||||
|
"❌ Duration number must be a positive integer. Please enter a valid duration:"
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let hours = match unit {
|
||||||
|
"hour" | "hours" | "hr" | "hrs" => number,
|
||||||
|
"day" | "days" => number * 24,
|
||||||
|
_ => {
|
||||||
|
return Err(
|
||||||
|
"❌ Supported units: hour(s), day(s). Please enter a valid duration:".to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (1..=720).contains(&hours) {
|
||||||
|
Ok(ListingDuration::hours(hours))
|
||||||
|
} else {
|
||||||
|
Err("❌ Duration must be between 1 hour and 30 days (720 hours). Please enter a valid duration:".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,3 +112,34 @@ pub fn validate_start_time(text: &str) -> Result<ListingDuration, String> {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case("24", ListingDuration::hours(24))] // Plain number
|
||||||
|
#[case("1 hour", ListingDuration::hours(1))]
|
||||||
|
#[case("2 hours", ListingDuration::hours(2))]
|
||||||
|
#[case("1 day", ListingDuration::hours(24))]
|
||||||
|
#[case("7 days", ListingDuration::hours(168))]
|
||||||
|
#[case("30 days", ListingDuration::hours(720))] // Max 30 days
|
||||||
|
fn test_validate_duration_valid(#[case] input: &str, #[case] expected: ListingDuration) {
|
||||||
|
let result = validate_duration(input).unwrap();
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case("0")]
|
||||||
|
#[case("0 hours")]
|
||||||
|
#[case("721")] // Over limit
|
||||||
|
#[case("1 week")] // Unsupported unit
|
||||||
|
#[case("1 month")] // Unsupported unit
|
||||||
|
#[case("1 year")] // Unsupported unit
|
||||||
|
#[case("abc")] // Invalid text
|
||||||
|
#[case("-1 hour")] // Negative
|
||||||
|
fn test_validate_duration_invalid(#[case] input: &str) {
|
||||||
|
assert!(validate_duration(input).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user