Merge branch 'feature/server_side_validation' into 'master'
Server side validation improvements Closes #132 See merge request cara/cara!381
This commit is contained in:
commit
2d83cfe3b6
2 changed files with 114 additions and 0 deletions
|
|
@ -185,6 +185,10 @@ class FormData:
|
|||
return form_dict
|
||||
|
||||
def validate(self):
|
||||
# Validate number of infected <= number of total people
|
||||
if self.infected_people > self.total_people:
|
||||
raise ValueError('Number of infected people cannot be more than number of total people.')
|
||||
|
||||
# Validate time intervals selected by user
|
||||
time_intervals = [
|
||||
['exposed_start', 'exposed_finish'],
|
||||
|
|
@ -202,6 +206,43 @@ class FormData:
|
|||
raise ValueError(
|
||||
f"{start_name} must be less than {end_name}. Got {start} and {end}.")
|
||||
|
||||
def validate_lunch(start, finish):
|
||||
lunch_start = getattr(self, f'{population}_lunch_start')
|
||||
lunch_finish = getattr(self, f'{population}_lunch_finish')
|
||||
return (start <= lunch_start <= finish and
|
||||
start <= lunch_finish <= finish)
|
||||
|
||||
def get_lunch_mins(population):
|
||||
lunch_mins = 0
|
||||
if getattr(self, f'{population}_lunch_option'):
|
||||
lunch_mins = getattr(self, f'{population}_lunch_finish') - getattr(self, f'{population}_lunch_start')
|
||||
return lunch_mins
|
||||
|
||||
def get_coffee_mins(population):
|
||||
coffee_mins = 0
|
||||
if getattr(self, f'{population}_coffee_break_option') != 'coffee_break_0':
|
||||
coffee_mins = COFFEE_OPTIONS_INT[getattr(self, f'{population}_coffee_break_option')] * getattr(self, f'{population}_coffee_duration')
|
||||
return coffee_mins
|
||||
|
||||
def get_activity_mins(population):
|
||||
return getattr(self, f'{population}_finish') - getattr(self, f'{population}_start')
|
||||
|
||||
populations = ['exposed', 'infected'] if self.infected_dont_have_breaks_with_exposed else ['exposed']
|
||||
for population in populations:
|
||||
# Validate lunch time within the activity times.
|
||||
if (getattr(self, f'{population}_lunch_option') and
|
||||
not validate_lunch(getattr(self, f'{population}_start'), getattr(self, f'{population}_finish'))
|
||||
):
|
||||
raise ValueError(
|
||||
f"{population} lunch break must be within presence times."
|
||||
)
|
||||
|
||||
# Length of breaks < length of activity
|
||||
if (get_lunch_mins(population) + get_coffee_mins(population)) >= get_activity_mins(population):
|
||||
raise ValueError(
|
||||
f"Length of breaks >= Length of {population} presence."
|
||||
)
|
||||
|
||||
validation_tuples = [('activity_type', ACTIVITY_TYPES),
|
||||
('exposed_coffee_break_option', COFFEE_OPTIONS_INT),
|
||||
('infected_coffee_break_option', COFFEE_OPTIONS_INT),
|
||||
|
|
@ -229,6 +270,11 @@ class FormData:
|
|||
"window_opening_regime cannot be 'not-applicable' if "
|
||||
"ventilation_type is 'natural_ventilation'"
|
||||
)
|
||||
if (self.window_opening_regime == 'windows_open_periodically' and
|
||||
self.windows_duration > self.windows_frequency):
|
||||
raise ValueError(
|
||||
'Duration cannot be bigger than frequency.'
|
||||
)
|
||||
|
||||
if (self.ventilation_type == 'mechanical_ventilation'
|
||||
and self.mechanical_ventilation_type == 'not-applicable'):
|
||||
|
|
|
|||
|
|
@ -167,6 +167,13 @@ def test_ventilation_window_hepa(baseline_form: model_generator.FormData):
|
|||
assert ventilation == baseline_vent
|
||||
|
||||
|
||||
def test_infected_less_than_total_people(baseline_form: model_generator.FormData):
|
||||
baseline_form.total_people = 10
|
||||
baseline_form.infected_people = 11
|
||||
with pytest.raises(ValueError, match='Number of infected people cannot be more than number of total people.'):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
def present_times(interval: models.Interval) -> models.BoundarySequence_t:
|
||||
assert isinstance(interval, models.SpecificInterval)
|
||||
return interval.present_times
|
||||
|
|
@ -255,6 +262,59 @@ def test_exposed_present_lunch_end_before_beginning(baseline_form: model_generat
|
|||
baseline_form.validate()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exposed_lunch_start, exposed_lunch_finish",
|
||||
[
|
||||
[8, 14], # lunch_start before the presence begining
|
||||
[19, 20], # lunch_start after the presence finishing
|
||||
[7, 8], # lunch_finish before the presence begining
|
||||
[9, 20], # lunch_finish after the presence finishing
|
||||
],
|
||||
)
|
||||
def test_exposed_presence_lunch_break(baseline_form: model_generator.FormData, exposed_lunch_start, exposed_lunch_finish):
|
||||
baseline_form.exposed_lunch_start = minutes_since_midnight(exposed_lunch_start * 60)
|
||||
baseline_form.exposed_lunch_finish = minutes_since_midnight(exposed_lunch_finish * 60)
|
||||
with pytest.raises(ValueError, match='exposed lunch break must be within presence times.'):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"infected_lunch_start, infected_lunch_finish",
|
||||
[
|
||||
[8, 14], # lunch_start before the presence begining
|
||||
[19, 20], # lunch_start after the presence finishing
|
||||
[7, 8], # lunch_finish before the presence begining
|
||||
[9, 20], # lunch_finish after the presence finishing
|
||||
],
|
||||
)
|
||||
def test_infected_presence_lunch_break(baseline_form: model_generator.FormData, infected_lunch_start, infected_lunch_finish):
|
||||
baseline_form.infected_lunch_start = minutes_since_midnight(infected_lunch_start * 60)
|
||||
baseline_form.infected_lunch_finish = minutes_since_midnight(infected_lunch_finish * 60)
|
||||
with pytest.raises(ValueError, match='infected lunch break must be within presence times.'):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
def test_exposed_breaks_length(baseline_form: model_generator.FormData):
|
||||
baseline_form.exposed_coffee_break_option = 'coffee_break_4'
|
||||
baseline_form.exposed_coffee_duration = 30
|
||||
baseline_form.exposed_start = minutes_since_midnight(10 * 60)
|
||||
baseline_form.exposed_finish = minutes_since_midnight(11 * 60)
|
||||
baseline_form.exposed_lunch_option = False
|
||||
with pytest.raises(ValueError, match='Length of breaks >= Length of exposed presence.'):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
def test_infected_breaks_length(baseline_form: model_generator.FormData):
|
||||
baseline_form.infected_start = minutes_since_midnight(9 * 60)
|
||||
baseline_form.infected_finish = minutes_since_midnight(12 * 60)
|
||||
baseline_form.infected_lunch_start = minutes_since_midnight(10 * 60)
|
||||
baseline_form.infected_lunch_finish = minutes_since_midnight(11 * 60)
|
||||
baseline_form.infected_coffee_break_option = 'coffee_break_4'
|
||||
baseline_form.infected_coffee_duration = 30
|
||||
with pytest.raises(ValueError, match='Length of breaks >= Length of infected presence.'):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def coffee_break_between_1045_and_1115(baseline_form: model_generator.FormData):
|
||||
baseline_form.exposed_coffee_break_option = 'coffee_break_1'
|
||||
|
|
@ -435,6 +495,14 @@ def test_key_validation_natural_ventilation_window_opening_regime_na(baseline_fo
|
|||
model_generator.FormData.from_dict(baseline_form_data)
|
||||
|
||||
|
||||
def test_natural_ventilation_window_opening_periodically(baseline_form: model_generator.FormData):
|
||||
baseline_form.window_opening_regime = 'windows_open_periodically'
|
||||
baseline_form.windows_duration = 20
|
||||
baseline_form.windows_frequency = 10
|
||||
with pytest.raises(ValueError, match='Duration cannot be bigger than frequency.'):
|
||||
baseline_form.validate()
|
||||
|
||||
|
||||
def test_key_validation_mech_ventilation_type_na(baseline_form_data):
|
||||
baseline_form_data['ventilation_type'] = 'mechanical_ventilation'
|
||||
baseline_form_data['mechanical_ventilation_type'] = 'not-applicable'
|
||||
|
|
|
|||
Loading…
Reference in a new issue