|
1 | | -use ixa::{Context, HashMap, IxaError, plan::PlanId, prelude::*}; |
| 1 | +use ixa::{Context, IxaError, prelude::*}; |
2 | 2 |
|
3 | 3 | use crate::{ |
4 | 4 | population_loader::{Alive, Person, PersonId}, |
5 | 5 | settings::ContextSettingExt, |
6 | 6 | symptom_status_manager::SymptomStatus, |
7 | 7 | }; |
8 | 8 |
|
9 | | -#[derive(Default)] |
10 | | -struct DeathDataContainer { |
11 | | - plans: HashMap<PersonId, Vec<PlanId>>, |
12 | | -} |
13 | | - |
14 | | -impl DeathDataContainer { |
15 | | - fn record_plan(&mut self, person: PersonId, plan: PlanId) { |
16 | | - self.plans.entry(person).or_default().push(plan); |
17 | | - } |
18 | | - |
19 | | - fn get_plans(&mut self, person: PersonId) -> Vec<PlanId> { |
20 | | - self.plans.get(&person).cloned().unwrap_or_default() |
21 | | - } |
22 | | - |
23 | | - fn remove_plan_records(&mut self, person: PersonId) { |
24 | | - self.plans.remove(&person); |
25 | | - } |
26 | | -} |
27 | | - |
28 | | -define_data_plugin!( |
29 | | - DeathDataPlugin, |
30 | | - DeathDataContainer, |
31 | | - DeathDataContainer::default() |
32 | | -); |
33 | | - |
34 | 9 | pub trait ContextDeathExt: PluginContext + ContextEntitiesExt { |
35 | 10 | fn is_alive(&self, person_id: PersonId) -> bool { |
36 | 11 | self.get_property::<Person, Alive>(person_id).0 |
37 | 12 | } |
38 | | - |
39 | | - fn record_plan(&mut self, person_id: PersonId, plan_id: PlanId) { |
40 | | - self.get_data_mut(DeathDataPlugin) |
41 | | - .record_plan(person_id, plan_id); |
42 | | - } |
43 | | - |
44 | | - fn cancel_plans(&mut self, person_id: PersonId) { |
45 | | - let plan_ids = self.get_data_mut(DeathDataPlugin).get_plans(person_id); |
46 | | - for plan_id in plan_ids { |
47 | | - self.cancel_plan(&plan_id); |
48 | | - } |
49 | | - self.get_data_mut(DeathDataPlugin) |
50 | | - .remove_plan_records(person_id); |
51 | | - } |
52 | 13 | } |
53 | 14 | impl ContextDeathExt for Context {} |
54 | 15 | pub fn init(context: &mut Context) -> Result<(), IxaError> { |
@@ -214,6 +175,39 @@ mod test { |
214 | 175 | context.execute(); |
215 | 176 | } |
216 | 177 |
|
| 178 | + #[test] |
| 179 | + fn test_dead_person_does_not_recover() { |
| 180 | + // This test verifies that when a person is dead, they do not transition to a recovered state. |
| 181 | + // We create a person, set them to dead, and then check that their infection status does not change to recovered over the course of the simulation. |
| 182 | + let mut context = setup_context(0, 5.0, 0.5, 10.0); |
| 183 | + let person_id: PersonId = context.add_entity((Age(30),)).unwrap(); |
| 184 | + infection_propagation_loop::init(&mut context).unwrap(); |
| 185 | + symptom_status_manager::init(&mut context).unwrap(); |
| 186 | + init(&mut context).unwrap(); |
| 187 | + // We schedule the person to be set to dead at time 0.0, |
| 188 | + // and then we check that their infection status does not change to recovered after the death event is processed. |
| 189 | + context.add_plan_with_phase( |
| 190 | + 0.0, |
| 191 | + move |context| { |
| 192 | + assert!(context.is_alive(person_id)); |
| 193 | + context.set_property::<Person, SymptomStatus>(person_id, SymptomStatus::Dead); |
| 194 | + context.infect_person(person_id, None, None, None); |
| 195 | + }, |
| 196 | + ExecutionPhase::First, |
| 197 | + ); |
| 198 | + context.subscribe_to_event::<PropertyChangeEvent<Person, InfectionStatus>>( |
| 199 | + move |_context, event| { |
| 200 | + if event.current == InfectionStatus::Recovered { |
| 201 | + panic!( |
| 202 | + "Dead person should not recover, but person {:?} did", |
| 203 | + event.entity_id |
| 204 | + ); |
| 205 | + } |
| 206 | + }, |
| 207 | + ); |
| 208 | + context.execute(); |
| 209 | + } |
| 210 | + |
217 | 211 | #[test] |
218 | 212 | fn test_no_infection_when_dead() { |
219 | 213 | // This test verifies that when a person is dead, they cannot infect others. |
@@ -249,11 +243,11 @@ mod test { |
249 | 243 | // Add a watcher if the other person is infected. |
250 | 244 | context.subscribe_to_event::<PropertyChangeEvent<Person, InfectionStatus>>( |
251 | 245 | move |context, event| { |
252 | | - if event.current == InfectionStatus::Infectious { |
253 | | - if event.entity_id != infectious_person { |
254 | | - *num_infected_clone.borrow_mut() += 1; |
255 | | - context.set_property(event.entity_id, InfectionData::Susceptible); |
256 | | - } |
| 246 | + if event.current == InfectionStatus::Infectious |
| 247 | + && event.entity_id != infectious_person |
| 248 | + { |
| 249 | + *num_infected_clone.borrow_mut() += 1; |
| 250 | + context.set_property(event.entity_id, InfectionData::Susceptible); |
257 | 251 | } |
258 | 252 | }, |
259 | 253 | ); |
|
0 commit comments