def test_shift_one(self) -> None: """ Test finding a shift of one """ # GIVEN sync_start = SyncStart(from_id="sg1", to_id="sg2") fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=40), GreenYellowInterval(start_greenyellow=50, end_greenyellow=70)], sg2=[GreenYellowInterval(start_greenyellow=50, end_greenyellow=60), GreenYellowInterval(start_greenyellow=10, end_greenyellow=30)]), period=100) # WHEN matches = find_other_sg_relation_matches(other_relation=sync_start, fts=fts, index_from=0) matches2 = find_other_sg_relation_matches(other_relation=sync_start, fts=fts, index_from=1) # THEN self.assertListEqual(matches, [0, 1]) self.assertListEqual(matches2, [1, 0])
def test_successful_validation2(self) -> None: """ Test validation for correct fts; we will modify this schedule to violate maximum green and red times """ # GIVEN fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[ GreenYellowInterval(start_greenyellow=0, end_greenyellow=50), GreenYellowInterval(start_greenyellow=120, end_greenyellow=170) ], sg2=[ GreenYellowInterval(start_greenyellow=60, end_greenyellow=110), GreenYellowInterval(start_greenyellow=180, end_greenyellow=230) ]), period=240) intersection = TestFTSValidationOfBounds.get_default_intersection() # WHEN validate_bounds(intersection=intersection, fts=fts)
def test_negative(self) -> None: """ Test initializing GreenYellowInterval object with negative start_greenyellow or end_greenyellow""" for key in TestIntervalInputValidation.get_default_inputs(): # GIVEN input_dict = TestIntervalInputValidation.get_default_inputs() input_dict[key] = -1 # should be positive with self.assertRaises(AssertionError): # WHEN initializing the queue lengths GreenYellowInterval(**input_dict)
def test_not_a_number(self) -> None: """ Test initializing GreenYellowInterval object with non-numeric arguments """ for key in TestIntervalInputValidation.get_default_inputs(): # GIVEN input_dict = TestIntervalInputValidation.get_default_inputs() input_dict[key] = "str" # each argument should be a number with self.assertRaises(ValueError): # WHEN initializing the queue lengths GreenYellowInterval(**input_dict)
def test_rate_no_greenyellow_interval(self) -> None: """ Test providing no GreenYellowInterval for the interval """ # GIVEN input_dict = TestFTSInputValidation.get_default_inputs() input_dict["greenyellow_intervals"]["id3"] = [ GreenYellowInterval(start_greenyellow=1, end_greenyellow=10), "3" ] with self.assertRaises(ValueError): # WHEN initializing the fts FixedTimeSchedule(**input_dict)
def test_no_shift_possible(self) -> None: """ Test finding the shifts for a schedule without an unambiguous shift""" # GIVEN sync_start = SyncStart(from_id="sg1", to_id="sg2") fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=30), GreenYellowInterval(start_greenyellow=40, end_greenyellow=50), GreenYellowInterval(start_greenyellow=60, end_greenyellow=80)], sg2=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=30), GreenYellowInterval(start_greenyellow=40, end_greenyellow=50), GreenYellowInterval(start_greenyellow=60, end_greenyellow=80)]), period=100) # swap two intervals (we do this after initialization as otherwise we would get a ValueError (not correct order # of greenyellow intervals) when initializing the FixedTimeSchedule fts._greenyellow_intervals["sg2"][:2] = reversed(fts._greenyellow_intervals["sg2"][:2]) # WHEN matches = find_other_sg_relation_matches(other_relation=sync_start, fts=fts, index_from=0) matches2 = find_other_sg_relation_matches(other_relation=sync_start, fts=fts, index_from=1) matches3 = find_other_sg_relation_matches(other_relation=sync_start, fts=fts, index_from=2) # THEN self.assertListEqual(matches, [0, 1, 0]) self.assertListEqual(matches2, [1, 0, 0]) self.assertListEqual(matches3, [0, 0, 1])
def test_incorrect_offset(self) -> None: """ Test that validation of incorrect offset raises SafetyViolation. :return: """ # GIVEN offset = Offset(from_id="sg3", to_id="sg4", seconds=20) fts_org = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[GreenYellowInterval(start_greenyellow=15, end_greenyellow=35)], sg2=[GreenYellowInterval(start_greenyellow=45, end_greenyellow=65)], sg3=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=40), GreenYellowInterval(start_greenyellow=50, end_greenyellow=70)], sg4=[GreenYellowInterval(start_greenyellow=30, end_greenyellow=40), GreenYellowInterval(start_greenyellow=69, end_greenyellow=90)]), period=100) signalgroup3 = TestFTSOtherSGRelationValidation.get_default_signalgroup(name="sg3") signalgroup4 = TestFTSOtherSGRelationValidation.get_default_signalgroup(name="sg4") intersection = TestFTSOtherSGRelationValidation.get_default_intersection( additional_signalgroups=[signalgroup3, signalgroup4], offsets=[offset]) for interval_shift in range(2): with self.subTest(f"interval_shift={interval_shift}"): fts = deepcopy(fts_org) fts._greenyellow_intervals["sg4"] = fts._greenyellow_intervals["sg4"][:interval_shift] + \ fts._greenyellow_intervals["sg4"][interval_shift:] with self.assertRaises(SafetyViolation): # WHEN validating validate_other_sg_relations(intersection=intersection, fts=fts)
def test_red_interval_too_large(self) -> None: """ Test red interval too large """ # GIVEN # red interval of signalgroup 3 is too large fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[ GreenYellowInterval(start_greenyellow=0, end_greenyellow=50), GreenYellowInterval(start_greenyellow=120, end_greenyellow=170) ], sg2=[ GreenYellowInterval(start_greenyellow=60, end_greenyellow=110), GreenYellowInterval(start_greenyellow=180, end_greenyellow=230) ], sg3=[ GreenYellowInterval(start_greenyellow=0, end_greenyellow=50), GreenYellowInterval(start_greenyellow=120, end_greenyellow=170) ]), period=240) signalgroup3 = TestFTSValidationOfBounds.get_default_signalgroup( name="sg3", max_red=60) intersection = TestFTSValidationOfBounds.get_default_intersection( additional_signalgroups=[signalgroup3]) with self.assertRaises(SafetyViolation): # WHEN validating validate_bounds(intersection=intersection, fts=fts)
def test_comparing_different_greenyellow_intervals(self): """ Test comparing two different fixed-time schedules (different ids) """ # GIVEN input_dict = TestFTSInputValidation.get_default_inputs() input_dict2 = TestFTSInputValidation.get_default_inputs( ) # ensure not same references input_dict2["greenyellow_intervals"]["sg2"][0] = GreenYellowInterval( start_greenyellow=13, end_greenyellow=23) fts1 = FixedTimeSchedule(**input_dict) fts2 = FixedTimeSchedule(**input_dict2) # WHEN same = fts1 == fts2 self.assertEqual(same, False)
def test_times_exceeding_period_duration(self) -> None: """ Test providing no GreenYellowInterval for the interval """ # GIVEN input_dict = TestFTSInputValidation.get_default_inputs() for time in ["start_greenyellow", "end_greenyellow"]: with self.subTest(f"{time} exceeding period duration"): greenyellow_interval_dict = dict(start_greenyellow=1, end_greenyellow=10) greenyellow_interval_dict[time] = input_dict["period"] + 1 input_dict["greenyellow_intervals"]["id3"] = [ GreenYellowInterval(**greenyellow_interval_dict) ] with self.assertRaises(ValueError): # WHEN initializing the fts FixedTimeSchedule(**input_dict)
def test_incorrect_greenyellow_trail(self) -> None: """ Test that validation of incorrect greenyellow-trail raises SafetyViolation. :return: """ # GIVEN min_greenyellow_trail = 20 max_greenyellow_trail = 30 greenyellow_lead = GreenyellowLead(from_id="sg3", to_id="sg4", min_seconds=min_greenyellow_trail, max_seconds=max_greenyellow_trail) fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[GreenYellowInterval(start_greenyellow=15, end_greenyellow=35)], sg2=[GreenYellowInterval(start_greenyellow=45, end_greenyellow=65)], sg3=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=40), GreenYellowInterval(start_greenyellow=50, end_greenyellow=70)], sg4=[GreenYellowInterval(start_greenyellow=30, end_greenyellow=40), GreenYellowInterval(start_greenyellow=69, end_greenyellow=90)]), period=100) signalgroup3 = TestFTSOtherSGRelationValidation.get_default_signalgroup(name="sg3") signalgroup4 = TestFTSOtherSGRelationValidation.get_default_signalgroup(name="sg4") intersection = TestFTSOtherSGRelationValidation.get_default_intersection( additional_signalgroups=[signalgroup3, signalgroup4], greenyellow_leads=[greenyellow_lead]) for trail_time in [min_greenyellow_trail - 1, max_greenyellow_trail + 1]: for interval_shift in range(2): fts_copy = deepcopy(fts) # adjust schedule to the specified greenyellow-lead for index, greenyellow_interval in enumerate(fts_copy.get_greenyellow_intervals(signalgroup4)): greenyellow_end = (greenyellow_interval.end_greenyellow - trail_time) % fts_copy.period greenyellow_start = (greenyellow_end - 20) % fts_copy.period fts_copy._greenyellow_intervals["sg3"][index] = GreenYellowInterval( start_greenyellow=greenyellow_start, end_greenyellow=greenyellow_end) fts_copy._greenyellow_intervals["sg4"] = fts_copy._greenyellow_intervals["sg4"][:interval_shift] + \ fts_copy._greenyellow_intervals["sg4"][interval_shift:] with self.subTest(f"greenyellow_lead={trail_time}, interval_shift={interval_shift}"): with self.assertRaises(SafetyViolation): # WHEN validating validate_other_sg_relations(intersection=intersection, fts=fts_copy)
def test_correct_sync_starts(self) -> None: """ Test that validation of correct synchronous start passes. :return: """ # GIVEN sync_start = SyncStart(from_id="sg3", to_id="sg4") fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[GreenYellowInterval(start_greenyellow=15, end_greenyellow=35)], sg2=[GreenYellowInterval(start_greenyellow=45, end_greenyellow=65)], sg3=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=40), GreenYellowInterval(start_greenyellow=50, end_greenyellow=70)], sg4=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=30), GreenYellowInterval(start_greenyellow=50, end_greenyellow=60)]), period=100) signalgroup3 = TestFTSOtherSGRelationValidation.get_default_signalgroup(name="sg3") signalgroup4 = TestFTSOtherSGRelationValidation.get_default_signalgroup(name="sg4") intersection = TestFTSOtherSGRelationValidation.get_default_intersection( additional_signalgroups=[signalgroup3, signalgroup4], sync_starts=[sync_start]) # WHEN validating validate_other_sg_relations(intersection=intersection, fts=fts)
def test_no_shift_possible(self) -> None: """ Test finding no shift is possible for a schedule without an unambiguous shift""" # GIVEN sync_start = SyncStart(from_id="sg1", to_id="sg2") fts = FixedTimeSchedule(greenyellow_intervals=dict( sg1=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=30), GreenYellowInterval(start_greenyellow=40, end_greenyellow=50), GreenYellowInterval(start_greenyellow=60, end_greenyellow=80)], sg2=[GreenYellowInterval(start_greenyellow=10, end_greenyellow=30), GreenYellowInterval(start_greenyellow=40, end_greenyellow=50), GreenYellowInterval(start_greenyellow=60, end_greenyellow=80)]), period=100) # Swap two intervals (we do this after initialization as otherwise we would get a ValueError (not correct order # of greenyellow intervals) fts._greenyellow_intervals["sg2"][:2] = reversed(fts._greenyellow_intervals["sg2"][:2]) # WHEN shift = get_other_sg_relation_shift(other_relation=sync_start, fts=fts) # THEN self.assertEqual(shift, None)