Example #1
0
class TestActionTimerTick(unittest.TestCase):
    "Test the progress_callback functionality of the ActionTimer"
    def setUp(self) -> None:
        super().setUp()
        self.progress_callback = Mock()
        self.action_duration = 2
        self.action_timer = ActionTimer(self.action_duration, self.progress_callback)

    def assertTickCall(
        self,
        start_time: float,
        end_time: float,
        prev_progress: float,
    ) -> float:
        self.action_timer.tick(end_time)
        # recalculate the duration to avoid floating-point precision errors
        progress = (end_time - start_time) / self.action_duration

        self.progress_callback.assert_called_with(
            StationCode.BE,
            Claimant.ZONE_1,
            progress,
            prev_progress,
        )
        return progress

    def assertCallCount(self, call_count: int, context: str) -> None:
        self.assertEqual(
            self.progress_callback.call_count,
            call_count,
            f"Incorrect number of calls of progress_callback {context}"
            f" ({self.progress_callback.call_args_list})",
        )

    def test_successful_completion(self) -> None:
        """
        Test that progress_callback is called with appropriate arguments at the start
        and completion of the timer. Namely the progress parameter should be 0 when the
        timer starts and TIMER_COMPLETE when the timer action is successfully completed.
        Once TIMER_COMPLETE or TIMER_EXPIRE is parsed to progress_callback, the timer item
        is removed from the internal dict and should not cause progress_callback to be
        called on subsequent calls of tick().
        """
        start_time = random.uniform(0, 1000)
        self.action_timer.begin_action(StationCode.BE, Claimant.ZONE_1, start_time)
        self.progress_callback.assert_called_with(StationCode.BE, Claimant.ZONE_1, 0, 0)

        used_duration = random.uniform(1.8, 2.2)
        self.action_timer.has_begun_action_in_time_window(
            StationCode.BE,
            Claimant.ZONE_1,
            start_time + used_duration,
        )
        self.progress_callback.assert_called_with(
            StationCode.BE,
            Claimant.ZONE_1,
            ActionTimer.TIMER_COMPLETE,
            0,
        )

        self.action_timer.tick(start_time + used_duration)
        self.assertCallCount(2, "after action completion")

    def test_expired_timer(self) -> None:
        """
        Test that progress_callback is called with appropriate arguments at the start
        and expiry of the timer. Namely the progress parameter should be 0
        when the timer starts and TIMER_EXPIRE when the timer expires.
        """
        start_time = random.uniform(0, 1000)
        self.action_timer.begin_action(StationCode.BE, Claimant.ZONE_1, start_time)
        self.progress_callback.assert_called_with(StationCode.BE, Claimant.ZONE_1, 0, 0)

        # make timer expire
        used_duration = random.uniform(2.3, 10)
        self.action_timer.tick(start_time + used_duration)
        self.progress_callback.assert_called_with(
            StationCode.BE,
            Claimant.ZONE_1,
            ActionTimer.TIMER_EXPIRE,
            0,
        )

        self.action_timer.tick(start_time + used_duration)
        self.assertCallCount(2, "after timer expired")

    def test_tick_call(self) -> None:
        """
        Test that the progress_callback method is called will the given progress
        on each call to ActionTimer.tick
        """
        start_time = random.uniform(0, 1000)
        self.action_timer.begin_action(StationCode.BE, Claimant.ZONE_1, start_time)

        prev_progress = self.assertTickCall(start_time, start_time + 0.9, 0)

        self.assertTickCall(start_time, start_time + 2.1, prev_progress)

        self.assertCallCount(3, "")
Example #2
0
class TestActionTimer(unittest.TestCase):
    def setUp(self) -> None:
        super().setUp()
        self.action_timer = ActionTimer(1.9)

    def assertBegunInsideDuration(self, duration: float, expected_result: bool) -> None:
        start_time = random.uniform(0, 1000)
        self.action_timer.begin_action(StationCode.PN, Claimant.ZONE_1, start_time)

        actual_result = self.action_timer.has_begun_action_in_time_window(
            StationCode.PN,
            Claimant.ZONE_1,
            start_time + duration,
        )

        self.assertEqual(
            actual_result,
            expected_result,
            f"Timer gave incorect result with duration {duration}",
        )

    def test_exact_time(self) -> None:
        self.assertBegunInsideDuration(2, True)

    def test_too_short_time(self) -> None:
        self.assertBegunInsideDuration(1.7, False)

    def test_too_long_time(self) -> None:
        self.assertBegunInsideDuration(2.2, False)

    def test_marginal_short_time(self) -> None:
        self.assertBegunInsideDuration(1.72, True)

    def test_marginal_long_time(self) -> None:
        self.assertBegunInsideDuration(2.08, True)

    def test_different_stations(self) -> None:
        start_time = random.uniform(0, 1000)
        # Start action with station PN
        self.action_timer.begin_action(StationCode.PN, Claimant.ZONE_1, start_time)

        # Attempt to complete action with SZ
        result = self.action_timer.has_begun_action_in_time_window(
            StationCode.SZ,
            Claimant.ZONE_1,
            start_time + 1.9,
        )

        self.assertFalse(result)

    def test_different_claimants(self) -> None:
        start_time = random.uniform(0, 1000)
        # Zone 0 starts action
        self.action_timer.begin_action(StationCode.PN, Claimant.ZONE_0, start_time)

        # Zone 1 attempts to complete action
        result = self.action_timer.has_begun_action_in_time_window(
            StationCode.PN,
            Claimant.ZONE_1,
            start_time + 1.9,
        )

        self.assertFalse(result)