Fixed parsing of opening hours with a discount. Fixes #4
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+39
-6
@@ -309,7 +309,19 @@ impl TryFrom<&str> for DayHour {
|
||||
return Err(AppError::HourParseError)
|
||||
}
|
||||
|
||||
let times = value.split("-")
|
||||
// Optional discount in parentheses after the interval: "08:00 - 12:00 (10)"
|
||||
let (interval, discount) = match value.trim().strip_suffix(")") {
|
||||
Some(rest) => {
|
||||
let (interval, discount) = rest.rsplit_once("(").ok_or(AppError::HourParseError)?;
|
||||
if discount.is_empty() || !discount.chars().all(|c| c.is_ascii_digit()) {
|
||||
return Err(AppError::HourParseError)
|
||||
}
|
||||
(interval, Some(discount.parse::<i32>().map_err(|_| AppError::HourParseError)?))
|
||||
}
|
||||
None => (value, None)
|
||||
};
|
||||
|
||||
let times = interval.split("-")
|
||||
.map(|t| t.trim()).collect::<Vec<_>>();
|
||||
|
||||
if times.len() != 2 {
|
||||
@@ -326,7 +338,7 @@ impl TryFrom<&str> for DayHour {
|
||||
Ok(DayHour {
|
||||
from: from.unwrap(),
|
||||
to: to.unwrap(),
|
||||
discount: None
|
||||
discount
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -892,6 +904,24 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn day_hour_parses_discount() {
|
||||
let expected = DayHour::new(time(8, 0), time(12, 30), Some(10));
|
||||
|
||||
assert_eq!(DayHour::try_from("08:00 - 12:30 (10)"), Ok(expected.clone()));
|
||||
assert_eq!(DayHour::try_from("08:00-12:30(10)"), Ok(expected));
|
||||
assert_eq!(DayHour::try_from("08:00 - 12:30 (0)"), Ok(DayHour::new(time(8, 0), time(12, 30), Some(0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn day_hour_rejects_malformed_discount() {
|
||||
for input in ["08:00 - 12:00 ()", "08:00 - 12:00 (x)", "08:00 - 12:00 (-5)", "08:00 - 12:00 (1.5)", "08:00 - 12:00 (10",
|
||||
"08:00 - 12:00 10)", "(10) 08:00 - 12:00", "08:00 (10) - 12:00", "08:00 - 12:00 (10) (20)", "(10)",
|
||||
"08:00 - 12:00 (99999999999)"] {
|
||||
assert_eq!(DayHour::try_from(input), Err(AppError::HourParseError), "input: {:?}", input);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn day_hours_empty_string_is_closed_day() {
|
||||
let hours = DayHours::try_new("").unwrap();
|
||||
@@ -930,7 +960,8 @@ mod tests {
|
||||
fn day_hours_display_round_trip() {
|
||||
let hours = DayHours(vec![
|
||||
DayHour::new(time(8, 0), time(12, 0), None),
|
||||
DayHour::new(time(13, 0), time(17, 0), None)
|
||||
DayHour::new(time(13, 0), time(17, 0), Some(10)),
|
||||
DayHour::new(time(18, 0), time(20, 0), Some(0))
|
||||
]);
|
||||
|
||||
let parsed = DayHours::try_new(&hours.to_string()).unwrap();
|
||||
@@ -950,9 +981,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn week_hours_accepts_valid_hours() {
|
||||
for input in ["", "08:00 - 12:00", "08:00-12:00", "08:00 - 12:00, 13:00 - 17:00"] {
|
||||
for input in ["", "08:00 - 12:00", "08:00-12:00", "08:00 - 12:00, 13:00 - 17:00",
|
||||
"08:00 - 12:00 (10)", "08:00 - 12:00 (10), 13:00 - 17:00", "08:00 - 12:00, 13:00 - 17:00(20)"] {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
assert!(hours.validate().is_ok(), "input: {:?}", input);
|
||||
assert!(DayHours::try_new(input).is_ok(), "input: {:?}", input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,7 +1011,7 @@ mod tests {
|
||||
#[test]
|
||||
fn week_hours_validation_agrees_with_parser() {
|
||||
for input in ["", "08:00 - 12:00", "08:00-12:00", "08:00 - 12:00,13:00 - 17:00", "08:00 - 12:00 , 13:00 - 17:00",
|
||||
"08:00 - 12:00, nonsense", "08:00 - 12:00,", "25:00 - 26:00", "08:00 - 12:00 garbage"] {
|
||||
"08:00 - 12:00 (10)", "08:00 - 12:00 (10) , 13:00 - 17:00 (5)", "08:00 - 12:00 (99999999999)", "08:00 - 12:00, nonsense", "08:00 - 12:00,", "25:00 - 26:00", "08:00 - 12:00 garbage"] {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
if hours.validate().is_ok() {
|
||||
assert!(DayHours::try_new(input).is_ok(), "input: {:?}", input);
|
||||
@@ -1003,7 +1036,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn week_hours_rejects_to_before_from() {
|
||||
for input in ["12:00 - 08:00", "08:00 - 08:00", "08:00 - 12:00, 17:00 - 13:00"] {
|
||||
for input in ["12:00 - 08:00", "08:00 - 08:00", "08:00 - 12:00, 17:00 - 13:00", "12:00 - 08:00 (10)"] {
|
||||
let hours = WeekHours { day: Weekday::Mon, hours: input.to_string() };
|
||||
assert!(has_field_error(&hours, "__all__"), "input: {:?}", input);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user