Skip to content

Commit

Permalink
Fixed invariants leak between related classes
Browse files Browse the repository at this point in the history
With pull request #292, we allowed users to specify the events which
trigger the invariant checks for each individual invariant.

This introduced a bug where invariants added to a child class were also
added to a parent class.

In this patch, we fixed the issue.

Fixes #295.
  • Loading branch information
mristin committed Sep 20, 2024
1 parent 577b503 commit 5c9c7ed
Showing 1 changed file with 90 additions and 0 deletions.
90 changes: 90 additions & 0 deletions tests/test_inheritance_invariant.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,96 @@ def some_func(self) -> int:
"Invariant is expected to run before and after the method call.",
)

def test_level_1_inheritance_of_invariants_does_not_leak_to_parents(self) -> None:
# NOTE (mristin):
# This is a regression test for:
# https://github.com/Parquery/icontract/issues/295
#
# The invariants added to a child class were unexpectedly leaked back to
# the parent class.

@icontract.invariant(lambda: True)
class Base(icontract.DBC):
pass

@icontract.invariant(lambda: False)
class Derived(Base):
pass

Base()

had_violation_error = False
try:
Derived()
except icontract.ViolationError:
had_violation_error = True

assert had_violation_error

def test_level_2_inheritance_of_invariants_does_not_leak_to_parents(self) -> None:
# NOTE (mristin):
# This is a regression test for:
# https://github.com/Parquery/icontract/issues/295
#
# The invariants added to a child class were unexpectedly leaked back to
# the parent class.

@icontract.invariant(lambda: True)
class Base(icontract.DBC):
pass

@icontract.invariant(lambda: True)
class Derived(Base):
pass

@icontract.invariant(lambda: False)
class DerivedDerived(Base):
pass

Base()
Derived()

had_violation_error = False
try:
DerivedDerived()
except icontract.ViolationError:
had_violation_error = True

assert had_violation_error

def test_level_3_inheritance_of_invariants_does_not_leak_to_parents(self) -> None:
# NOTE (mristin):
# This is a regression test for:
# https://github.com/Parquery/icontract/issues/295
#
# The invariants added to a child class were unexpectedly leaked back to
# the parent class.

class A(icontract.DBC):
def f(self):
pass

@icontract.invariant(lambda: True)
class B(A):
pass

# NOTE (mristin):
# CFalse should not in any way influence A, B and CTrue, but it did due to
# a bug.
@icontract.invariant(lambda: False)
class CFalse(B):
pass

@icontract.invariant(lambda: True)
class CTrue(B):
pass

CTrue()

# NOTE (mristin):
# This produced an unexpected violation error.
CTrue().f()


class TestViolation(unittest.TestCase):
def test_inherited(self) -> None:
Expand Down

0 comments on commit 5c9c7ed

Please sign in to comment.