Reorganize integration tests, simplify fn signatures

This commit is contained in:
2026-02-22 13:01:28 +02:00
parent a41d1cd469
commit 76d308351a
8 changed files with 270 additions and 344 deletions

View File

@@ -104,7 +104,7 @@ impl WorkloadBounds {
pub struct WorkloadTracker {
total_counts: HashMap<ResidentId, u8>,
type_counts: HashMap<(ResidentId, ShiftType), u8>,
holidays: HashMap<ResidentId, u8>,
holiday_counts: HashMap<ResidentId, u8>,
}
impl WorkloadTracker {
@@ -115,8 +115,8 @@ impl WorkloadTracker {
.entry((r_id, slot.shift_type()))
.or_insert(0) += 1;
if config.is_holiday_or_weekend_slot(slot.day.0) {
*self.holidays.entry(r_id).or_insert(0) += 1;
if config.is_holiday_or_weekend_slot(slot) {
*self.holiday_counts.entry(r_id).or_insert(0) += 1;
}
}
@@ -129,8 +129,8 @@ impl WorkloadTracker {
*count = count.saturating_sub(1);
}
if config.is_holiday_or_weekend_slot(slot.day.0) {
if let Some(count) = self.holidays.get_mut(&r_id) {
if config.is_holiday_or_weekend_slot(slot) {
if let Some(count) = self.holiday_counts.get_mut(&r_id) {
*count = count.saturating_sub(1);
}
}
@@ -141,7 +141,11 @@ impl WorkloadTracker {
}
pub fn current_holiday_workload(&self, r_id: &ResidentId) -> u8 {
*self.holidays.get(r_id).unwrap_or(&0)
*self.holiday_counts.get(r_id).unwrap_or(&0)
}
pub fn current_shift_type_workload(&self, r_id: &ResidentId, shift_type: ShiftType) -> u8 {
*self.type_counts.get(&(*r_id, shift_type)).unwrap_or(&0)
}
pub fn reached_workload_limit(&self, bounds: &WorkloadBounds, r_id: &ResidentId) -> bool {
@@ -172,9 +176,8 @@ impl WorkloadTracker {
&self,
bounds: &WorkloadBounds,
r_id: &ResidentId,
slot: &Slot,
shift_type: ShiftType,
) -> bool {
let shift_type = slot.shift_type();
let current_load = self.type_counts.get(&(*r_id, shift_type)).unwrap_or(&0);
if let Some(&max) = bounds.max_by_shift_type.get(&(*r_id, shift_type)) {
@@ -183,10 +186,6 @@ impl WorkloadTracker {
false
}
pub fn get_type_count(&self, r_id: &ResidentId, shift_type: ShiftType) -> u8 {
*self.type_counts.get(&(*r_id, shift_type)).unwrap_or(&0)
}
}
#[cfg(test)]
@@ -194,85 +193,23 @@ mod tests {
use crate::{
config::UserConfig,
fixtures::{complex_config, hard_config, minimal_config},
resident::{Resident, ResidentId},
resident::ResidentId,
schedule::ShiftType,
slot::{Day, ShiftPosition, Slot},
workload::{WorkloadBounds, WorkloadTracker},
};
use rstest::{fixture, rstest};
use rstest::rstest;
#[fixture]
fn config() -> UserConfig {
UserConfig::default().with_residents(vec![
Resident::new(1, "R1").with_max_shifts(2),
Resident::new(2, "R2").with_max_shifts(2),
Resident::new(3, "R3").with_reduced_load(),
Resident::new(4, "R4"),
Resident::new(5, "R5"),
])
}
#[fixture]
fn tracker() -> WorkloadTracker {
WorkloadTracker::default()
}
// Testing WorkloadBounds
#[rstest]
fn test_max_workloads(config: UserConfig) {
let bounds = WorkloadBounds::new_with_config(&config);
assert_eq!(2, bounds.max_workloads[&ResidentId(1)]);
assert_eq!(2, bounds.max_workloads[&ResidentId(2)]);
assert_eq!(13, bounds.max_workloads[&ResidentId(3)]);
assert_eq!(14, bounds.max_workloads[&ResidentId(4)]);
assert_eq!(14, bounds.max_workloads[&ResidentId(5)]);
}
#[rstest]
fn test_reached_workload_limit(mut tracker: WorkloadTracker, config: UserConfig) {
let r_id = ResidentId(1);
let mut bounds = WorkloadBounds::default();
bounds.max_workloads.insert(r_id, 1);
let slot_1 = Slot::new(Day(1), ShiftPosition::First);
let slot_2 = Slot::new(Day(2), ShiftPosition::First);
assert!(!tracker.reached_workload_limit(&bounds, &r_id,));
tracker.insert(r_id, &config, slot_1);
assert!(tracker.reached_workload_limit(&bounds, &r_id,));
tracker.insert(r_id, &config, slot_2);
assert!(tracker.reached_workload_limit(&bounds, &r_id,));
}
#[rstest]
fn test_reached_holiday_limit(mut tracker: WorkloadTracker, config: UserConfig) {
let r_id = ResidentId(1);
let mut bounds = WorkloadBounds::default();
bounds.max_holiday_shifts.insert(r_id, 1);
let sat = Slot::new(Day(11), ShiftPosition::First);
let sun = Slot::new(Day(12), ShiftPosition::First);
assert!(!tracker.reached_holiday_limit(&bounds, &r_id));
tracker.insert(r_id, &config, sat);
assert!(tracker.reached_holiday_limit(&bounds, &r_id));
tracker.insert(r_id, &config, sun);
assert!(tracker.reached_holiday_limit(&bounds, &r_id));
}
#[rstest]
fn test_backtracking_accuracy(mut tracker: WorkloadTracker, config: UserConfig) {
let r_id = ResidentId(1);
let slot = Slot::new(Day(1), ShiftPosition::First);
tracker.insert(r_id, &config, slot);
assert_eq!(tracker.current_workload(&r_id), 1);
tracker.remove(r_id, &config, slot);
assert_eq!(tracker.current_workload(&r_id), 0);
fn test_max_workloads(minimal_config: UserConfig) {
let bounds = WorkloadBounds::new_with_config(&minimal_config);
assert_eq!(9, bounds.max_workloads[&ResidentId(1)]);
assert_eq!(9, bounds.max_workloads[&ResidentId(2)]);
assert_eq!(9, bounds.max_workloads[&ResidentId(3)]);
assert_eq!(9, bounds.max_workloads[&ResidentId(4)]);
assert_eq!(9, bounds.max_workloads[&ResidentId(5)]);
}
#[rstest]
@@ -468,4 +405,88 @@ mod tests {
assert_eq!(5, *m.get(&(ResidentId(8), ShiftType::OpenSecond)).unwrap());
assert_eq!(0, *m.get(&(ResidentId(8), ShiftType::Closed)).unwrap());
}
// Testing WorkloadTracker
#[rstest]
fn test_reached_workload_limit(minimal_config: UserConfig) {
let mut tracker = WorkloadTracker::default();
let r_id = ResidentId(1);
let mut bounds = WorkloadBounds::default();
bounds.max_workloads.insert(r_id, 1);
let slot_1 = Slot::new(Day(1), ShiftPosition::First);
let slot_2 = Slot::new(Day(2), ShiftPosition::First);
assert!(!tracker.reached_workload_limit(&bounds, &r_id));
tracker.insert(r_id, &minimal_config, slot_1);
assert!(tracker.reached_workload_limit(&bounds, &r_id));
tracker.insert(r_id, &minimal_config, slot_2);
assert!(tracker.reached_workload_limit(&bounds, &r_id));
}
#[rstest]
fn test_reached_holiday_limit(minimal_config: UserConfig) {
let mut tracker = WorkloadTracker::default();
let r_id = ResidentId(1);
let mut bounds = WorkloadBounds::default();
bounds.max_holiday_shifts.insert(r_id, 1);
let sat = Slot::new(Day(11), ShiftPosition::First);
let sun = Slot::new(Day(12), ShiftPosition::First);
assert!(!tracker.reached_holiday_limit(&bounds, &r_id));
tracker.insert(r_id, &minimal_config, sat);
assert!(tracker.reached_holiday_limit(&bounds, &r_id));
tracker.insert(r_id, &minimal_config, sun);
assert!(tracker.reached_holiday_limit(&bounds, &r_id));
}
#[rstest]
fn test_reached_shift_type_limit(minimal_config: UserConfig) {
let mut tracker = WorkloadTracker::default();
let r_id = ResidentId(1);
let mut bounds = WorkloadBounds::default();
bounds
.max_by_shift_type
.insert((r_id, ShiftType::OpenFirst), 1);
let slot_1 = Slot::new(Day(1), ShiftPosition::First);
let slot_2 = Slot::new(Day(3), ShiftPosition::First);
let open_first = ShiftType::OpenFirst;
assert!(!tracker.reached_shift_type_limit(&bounds, &r_id, open_first));
tracker.insert(r_id, &minimal_config, slot_1);
assert!(tracker.reached_shift_type_limit(&bounds, &r_id, open_first));
tracker.insert(r_id, &minimal_config, slot_2);
assert!(tracker.reached_shift_type_limit(&bounds, &r_id, open_first));
}
#[rstest]
fn test_backtracking_state(minimal_config: UserConfig) {
let mut tracker = WorkloadTracker::default();
let r_id = ResidentId(1);
let sat = Slot::new(Day(11), ShiftPosition::First);
let sun = Slot::new(Day(12), ShiftPosition::First);
let open_first = ShiftType::OpenFirst;
let closed = ShiftType::Closed;
tracker.insert(r_id, &minimal_config, sat);
assert_eq!(1, tracker.current_workload(&r_id));
assert_eq!(1, tracker.current_holiday_workload(&r_id));
assert_eq!(1, tracker.current_shift_type_workload(&r_id, open_first));
tracker.insert(r_id, &minimal_config, sun);
assert_eq!(2, tracker.current_workload(&r_id));
assert_eq!(2, tracker.current_holiday_workload(&r_id));
assert_eq!(1, tracker.current_shift_type_workload(&r_id, open_first));
assert_eq!(1, tracker.current_shift_type_workload(&r_id, closed));
tracker.remove(r_id, &minimal_config, sun);
assert_eq!(1, tracker.current_workload(&r_id));
assert_eq!(1, tracker.current_holiday_workload(&r_id));
assert_eq!(1, tracker.current_shift_type_workload(&r_id, open_first));
assert_eq!(0, tracker.current_shift_type_workload(&r_id, closed));
tracker.remove(r_id, &minimal_config, sat);
assert_eq!(0, tracker.current_workload(&r_id));
assert_eq!(0, tracker.current_holiday_workload(&r_id));
assert_eq!(0, tracker.current_shift_type_workload(&r_id, open_first));
assert_eq!(0, tracker.current_shift_type_workload(&r_id, closed));
}
}