Пример #1
0
    def test_startsCurrentPeriod_endsCurrentPeriod_psiNotSatisfiable(self):
        """ Testing exit label 4 """
        chk1 = check(self.system.port) < 100
        chk2 = check(self.system.secondPort) == 5
        formula = tctl.EU(chk1, chk2)
        formula.interval > 2
        formula.interval < 6  # interval is completely in the period

        # prepare mocks
        mc = ModelChecker(self.ss)
        original_check = mc.check  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(name="is_satisfiable",
                                           return_value=False)
        self.ss.successors = mock.MagicMock(return_value=[
            mock.sentinel.successor, mock.sentinel.othersuccessor,
            mock.sentinel.thirdsuccessor
        ])
        mc.check = mock.MagicMock(name="check",
                                  side_effect=[False, [13, 22], False])

        # action
        result_trace = original_check(formula)

        # assert
        self.assertFalse(
            result_trace,
            "We correctly exited with False, since psi is not reachable and the interval ends before maxdt"
        )
        mc.check.assert_not_called()
Пример #2
0
    def test_PortCheck_not_issatisfiable_alsoNotInNextPeriod(self):
        """Testing whether a test that is not satisfiable here, and also not in next period returns False"""
        self.ss.successors = mock.MagicMock(
            return_value=[mock.sentinel.successor])  # return a successor

        # create check
        chk = check(
            self.system.secondPort
        ) > self.system.port  # secondPort grows at least as fast as port and is never reset

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(return_value=False)
        result_trace = original_is_satisfiable(chk, self.ss.graph["root"])

        # assert
        self.assertFalse(
            result_trace,
            "Assert that the model checker found it unsatisfiable")
        mc.is_satisfiable.assert_called_once()
        (formula, successorstate), kwargs = mc.is_satisfiable.call_args
        self.assertIs(mock.sentinel.successor, successorstate,
                      "The mock was not called with the correct successor")
        self.assertEqual(
            formula.interval.start, 0,
            "The mock was not called with the correct formula interval start")
        self.assertEqual(
            formula.interval.end, math.inf,
            "The mock was not called with the correct formula interval end")
Пример #3
0
    def test_PortCheck_issatisfiable_inAllNextPeriods(self):
        self.ss.successors = mock.MagicMock(return_value=[
            mock.sentinel.successor, mock.sentinel.othersuccessor
        ])

        # in one evolution the ports grow the same rate
        chk1 = check(self.system.port) == 300  # transition is at 10
        chk2 = check(
            self.system.secondPort) == self.system.port  # transition is at 10
        chk = chk1 & chk2

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(side_effect=[[17, 23], [5]])
        result_trace = original_is_satisfiable(chk, self.ss.graph["root"])

        # assert
        mc.is_satisfiable.assert_called_once(
        )  # exit after the first satisfiable
        self.assertIn(7, result_trace, "Assert that max_dt is in the trace")
        self.assertIn(17, result_trace,
                      "Assert that the future is in the trace")
        self.assertIn(23, result_trace,
                      "Assert that the future is in the trace")
Пример #4
0
    def test_PortCheck_issatisfiable_satisfiableInThisPeriod_BEFOREIntervalStart_intervalEndsAfterPeriod_recursion(
            self):
        """Tests whether a constraint that is satisfiable in this period is shown as False, iff the Formula interval is specified otherwise"""
        chk1 = check(self.system.port) < 5
        chk2 = check(self.system.secondPort) < 5
        chk = chk1 & chk2  # is valid until 2 time steps passed
        chk.interval > 2  # we want more time to pass

        self.ss.successors = mock.MagicMock(
            return_value=[mock.sentinel.successor])

        self.ss.graph["root"].apply()
        self.assertTrue(chk.check(), "the check is currently passing")

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(return_value=False)
        result_trace = original_is_satisfiable(chk, self.ss.graph["root"])

        # assert
        self.assertFalse(result_trace,
                         "Assert that the formula is unsatisfiable.")
        mc.is_satisfiable.assert_called_once(
        )  # recursion, should have been called once
        (formula, successorstate), kwargs = mc.is_satisfiable.call_args
        self.assertIs(mock.sentinel.successor, successorstate,
                      "The mock was not called with the correct successor")
        self.assertEqual(
            formula.interval.start, 0,
            "The mock was not called with the correct formula interval start")
        self.assertEqual(
            formula.interval.end, math.inf,
            "The mock was not called with the correct formula interval end")
Пример #5
0
    def test_PortCheck_not_issatisfiable_intervalEndsBeforeNextPeriod(self):
        chk = check(self.system.port) > self.system.secondPort
        chk.interval <= 9
        self.assertFalse(chk.check(), "the check is currently not working")

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock()
        result_trace = original_is_satisfiable(chk)

        # assert
        self.assertFalse(result_trace,
                         "Assert that the time advance of 7 is in the trace")
        mc.is_satisfiable.assert_not_called()
Пример #6
0
    def test_startsCurrentPeriod_endsCurrentPeriod_psiSatisfiable_phiNOTValidUntilPsi(
            self):
        """ Testing exit label 9) """
        chk1 = check(self.system.port) < 100
        chk2 = check(self.system.secondPort) == 5
        formula = tctl.EU(chk1, chk2)
        formula.interval > 2
        formula.interval < 6  # interval ends after this period

        # prepare mocks
        self.ss.successors = mock.MagicMock(return_value=[
            mock.sentinel.successor, mock.sentinel.othersuccessor,
            mock.sentinel.thirdsuccessor
        ])
        mc = ModelChecker(self.ss)
        original_check = mc.check  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(
            name="is_satisfiable",
            return_value=[5])  # psi is satisfied after 5 units
        mc.is_valid = mock.MagicMock(name="is_valid", return_value=[
            3
        ])  # is valid produces a counter example (when it's invalid)

        # action
        result_trace = original_check(formula)

        # assert that the resulting trace is correct
        self.assertFalse(
            result_trace,
            "Assert that if the first formula is invalid in this period, the result is False"
        )

        # assert that is valid was called on the formula
        mc.is_valid.assert_called_once()
        (formula,
         systemstate), kwargs = mc.is_valid.call_args  # get the last callargs
        self.assertEqual(
            formula.interval.start, 0,
            "phi was checked for validity from the start of the period")
        self.assertEqual(
            formula.interval.end, 5,
            "The phi validity check was called with the correct interval end")
        self.assertEqual(
            systemstate, self.ss.graph["root"],
            "The phi validity check was called on the correct state")
Пример #7
0
    def test_PortCheck_issatisfiable_inThisPeriod(self):
        """The AtomicFormula is reached before the period ends"""
        # create check
        chk1 = check(self.system.port) >= 7  # transition is at 10
        chk2 = check(self.system.secondPort) >= 7  # transition is at 10
        chk = chk1 & chk2

        self.ss.graph["root"].apply()
        self.assertFalse(chk.check(), "the check gave the wrong result")

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock()
        result_trace = original_is_satisfiable(chk)

        # assert
        self.assertIn(4, result_trace,
                      "Assert that the time advance of 7 is in the trace")
        mc.is_satisfiable.assert_not_called(
        )  # it was satisfiable in this period, no recursion
Пример #8
0
    def test_PortCheck_issatisfiable_noTimeAdvance(self):
        """The AtomicFormula is satisfied already"""
        # create check
        chk1 = check(self.system.port) == 3  # port initial value is 3
        chk2 = check(self.system.secondPort) == 3  # port initial value is 3
        chk = chk1 & chk2

        self.ss.graph["root"].apply()
        self.assertTrue(chk.check(), "the check gave the wrong result")

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock()
        result_trace = original_is_satisfiable(chk, self.ss.graph["root"])

        # assert
        self.assertIn(0, result_trace,
                      "Assert that the time advance of 7 is in the trace")
        mc.is_satisfiable.assert_not_called(
        )  # it was satisfiable in this period, no recursion
Пример #9
0
    def test_PortCheck_not_issatisfiable_noNextPeriod(self):
        chk = check(
            self.system.port) > self.system.secondPort  # cannot be bigger

        self.ss.successors = mock.MagicMock(
            return_value=[])  # assert that there are no successors
        self.ss.graph["root"].max_dt = math.inf

        self.ss.graph["root"].apply()
        self.assertFalse(chk.check(), "the check is currently not working")

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock()
        result_trace = original_is_satisfiable(chk)

        # assert
        self.assertFalse(result_trace,
                         "Assert that the check will not become enabled")
        mc.is_satisfiable.assert_not_called()
Пример #10
0
    def test_startsCurrentPeriod_endsFuturePeriod_phiNotValid(self):
        """ Testing exit label 5 """
        chk1 = check(self.system.port) < 100
        chk2 = check(self.system.secondPort) == 5
        formula = tctl.EU(chk1, chk2)
        formula.interval > 2
        formula.interval < 23  # interval ends after this period

        # prepare mocks
        mc = ModelChecker(self.ss)
        original_check = mc.check  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(name="is_satisfiable",
                                           return_value=False)
        mc.is_valid = mock.MagicMock(name="is_valid", return_value=False)
        mc.check = mock.MagicMock(name="check")

        # action (on original check)
        result_trace = original_check(formula)

        # assert that the return value was correct
        self.assertFalse(
            result_trace,
            "Assert that if the first formula is invalid in this period, the result is False"
        )

        # assert that is_valid was called with the correct values
        mc.is_valid.assert_called_once()
        (formula,
         systemstate), kwargs = mc.is_valid.call_args  # get the last callargs
        self.assertEqual(
            formula.interval.end, 7,
            "The subformula validity check was called with the correct interval end"
        )
        self.assertEqual(
            systemstate, self.ss.graph["root"],
            "The subformula validity check was called on the correct state")

        # assert that the check was not called (we exited early)
        mc.check.assert_not_called()
Пример #11
0
    def test_PortCheck_issatisfiable_inOneNextPeriod(self):
        self.ss.successors = mock.MagicMock(return_value=[
            mock.sentinel.successor, mock.sentinel.othersuccessor
        ])

        # in one evolution the ports grow the same rate
        chk1 = check(self.system.port) == 300  # transition is at 10
        chk2 = check(
            self.system.secondPort) == self.system.port  # transition is at 10
        chk = chk1 & chk2

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(side_effect=[False, [5]])
        result_trace = original_is_satisfiable(chk, self.ss.graph["root"])

        # assert
        self.assertEqual(2, mc.is_satisfiable.call_count,
                         "assert that the mock was called twice")
        self.assertIn(7, result_trace, "Assert that max_dt is in the trace")
        self.assertIn(5, result_trace,
                      "Assert that the future is in the trace")
Пример #12
0
    def test_PortCheck_issatisfiable_satisfiableInThisPeriod_BEFOREIntervalStart_intervalEndsBeforeNextPeriod(
            self):
        """Tests whether a constraint that is satisfiable in this period is shown as False, iff the Formula interval is specified otherwise"""
        chk1 = check(self.system.port) < 5
        chk2 = check(self.system.secondPort) < 5
        chk = chk1 & chk2  # is valid until 2 time steps passed

        chk.interval > 2  # we want more time to pass
        chk.interval < 6

        self.ss.graph["root"].apply()
        self.assertTrue(chk.check(), "the check is currently passing")

        # action
        mc = ModelChecker(self.ss)
        original_is_satisfiable = mc.is_satisfiable  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock()
        result_trace = original_is_satisfiable(chk, self.ss.graph["root"])

        # assert
        self.assertFalse(result_trace,
                         "Assert that the formula is unsatisfiable.")
        mc.is_satisfiable.assert_not_called(
        )  # no recursion, because the interval ended before the end of this period
Пример #13
0
    def test_startsCurrentPeriod_endsFuturePeriod_secondSuccessorSatisfiable_doesNotCallThird(
            self):
        """ Testing exit label 6) """
        chk1 = check(self.system.port) < 100
        chk2 = check(self.system.secondPort) == 5
        formula = tctl.EU(chk1, chk2)
        formula.interval > 2
        formula.interval < 23  # interval ends after this period

        # prepare mocks
        self.ss.successors = mock.MagicMock(return_value=[
            mock.sentinel.successor, mock.sentinel.othersuccessor,
            mock.sentinel.thirdsuccessor
        ])
        mc = ModelChecker(self.ss)
        original_check = mc.check  # copy reference, so we can now safely mock the potentially recursive call
        mc.is_satisfiable = mock.MagicMock(name="is_satisfiable",
                                           return_value=False)
        mc.is_valid = mock.MagicMock(return_value=True)
        mc.check = mock.MagicMock(side_effect=[False, [13, 22], False])

        # action
        result_trace = original_check(formula)

        # assert that the resulting trace is correct
        self.assertEqual(
            result_trace, [7, 13, 22],
            "Assert that if the first formula is invalid in this period, the result is False"
        )

        # assert that is valid was called on the formula
        mc.is_valid.assert_called_once()
        (formula,
         systemstate), kwargs = mc.is_valid.call_args  # get the last callargs
        self.assertEqual(
            formula.interval.end, 7,
            "The subformula validity check was called with the correct interval end"
        )
        self.assertEqual(
            systemstate, self.ss.graph["root"],
            "The subformula validity check was called on the correct state")

        # assert that a modified version of the formula (-= maxdt) was called on each successor
        self.assertEqual(
            mc.check.call_count, 2,
            "Check recursed on each of the successors, because both returned False"
        )

        (formula, systemstate
         ), kwargs = mc.check.call_args_list[0]  # get the last callargs
        self.assertEqual(
            formula.interval.start, -5,
            "The recursion check was called with the correct interval start")
        self.assertEqual(
            formula.interval.end, 16,
            "The recursion check was called with the correct interval end")
        self.assertEqual(
            systemstate, mock.sentinel.successor,
            "The recursion check was called on the correct state")

        (formula, systemstate
         ), kwargs = mc.check.call_args_list[1]  # get the last callargs
        self.assertEqual(
            formula.interval.start, -5,
            "The recursion check was called with the correct interval start")
        self.assertEqual(
            formula.interval.end, 16,
            "The recursion check was called with the correct interval end")
        self.assertEqual(
            systemstate, mock.sentinel.othersuccessor,
            "The recursion check was called on the correct state")