Exemple #1
0
def testInterfaceCheckRequiresInterface() -> None:
    class M3:
        def m3(self, *args, **kwargs):
            ""

    with pytest.raises(InterfaceError):
        AssertImplements(M3(), M3)  # type:ignore[arg-type]

    with pytest.raises(InterfaceError):
        IsImplementation(M3(), M3)  # type:ignore[arg-type]

    assert IsImplementation(M3(), _InterfM3, requires_declaration=False)
    assert not IsImplementation(M3(), _InterfM3, requires_declaration=True)

    with pytest.raises(AssertionError):
        AssertImplements(M3(), _InterfM3, requires_declaration=True)
Exemple #2
0
    def __eq__(self, other: Any) -> bool:
        if not IsImplementation(other, IUnitSystem):
            return False

        return (self.GetId() == other.GetId()
                and self.GetCaption() == other.GetCaption()
                and self.GetUnitsMapping() == other.GetUnitsMapping()
                and self.IsReadOnly() == other.IsReadOnly())
Exemple #3
0
def testDeclareClassImplements() -> None:
    class I1(Interface):
        def M1(self):
            ""

    class I2(Interface):
        def M2(self):
            ""

    class C0:
        ""

    class C1:
        def M1(self):
            ""

    class C2:
        def M2(self):
            ""

    @ImplementsInterface(I2)
    class C2B:
        def M2(self):
            ""

    class C12B(C1, C2B):
        ""

    with pytest.raises(AssertionError):
        DeclareClassImplements(C0, I1)

    assert IsImplementation(C1, I1, requires_declaration=False) == True

    DeclareClassImplements(C1, I1)

    assert IsImplementation(C1, I1) == True
    AssertImplements(C1, I1)

    # C1 is parent of C12B, and, above, it was declared that C1 implements I1,
    # so C12B should automatically implement I1.
    assert IsImplementation(C12B, I1) == True  # automatic
    assert (IsImplementation(C12B, I2) == True
            )  # inheritance for Implements still works automatically

    DeclareClassImplements(C12B, I1)

    assert IsImplementation(C12B, I1) == True  # now it implements
    assert IsImplementation(C12B, I2) == True

    DeclareClassImplements(C2, I2)

    assert IsImplementation(C2, I2) == True
    AssertImplements(C2, I2)

    # Exception: if I define a class *after* using DeclareClassImplements in the base, it works:
    class C12(C1, C2):
        ""

    AssertImplements(C12, I1)
    AssertImplements(C12, I2)
Exemple #4
0
def testClassImplementMethod() -> None:
    """
    Tests replacing a method that implements an interface with a class.

    The class must be derived from "Method" in order to be accepted as a valid
    implementation.
    """
    @ImplementsInterface(_InterfM1)
    class My:
        def m1(self):
            ""

    class MyRightMethod(Method):
        def __call__(self):
            ""

    class MyWrongMethod:
        def __call__(self):
            ""

    # NOTE: It doesn't matter runtime modifications in the instance, what is really being tested
    #       is the *class* of the object (My) is what is really being tested.
    m = My()
    m.m1 = MyWrongMethod()  # type:ignore[assignment]
    assert IsImplementation(m, _InterfM1) == True

    m.m1 = MyRightMethod()  # type:ignore[assignment]
    assert IsImplementation(m, _InterfM1) == True

    # NOTE: Testing behaviour of private methods here.
    from oop_ext.interface._interface import _IsImplementationFullChecking

    m = My()
    m.m1 = MyWrongMethod()  # type:ignore[assignment]
    assert not _IsImplementationFullChecking(m, _InterfM1)

    m.m1 = MyRightMethod()  # type:ignore[assignment]
    assert _IsImplementationFullChecking(m, _InterfM1)

    del m.m1
    assert IsImplementation(m, _InterfM1) == True
Exemple #5
0
def testIsImplementationWithSubclasses() -> None:
    """
    Checks if the IsImplementation method works with subclasses interfaces.

    Given that an interface I2 inherits from I1 of a given object declared that it implements I2
    then it is implicitly declaring that implements I1.
    """
    @ImplementsInterface(_InterfM2)
    class My2:
        def m2(self):
            ""

    @ImplementsInterface(_InterfM3)
    class My3:
        def m3(self, arg1, arg2):
            ""

    @ImplementsInterface(_InterfM4)
    class My4:
        def m3(self, arg1, arg2):
            ""

        def m4(self):
            ""

    m2 = My2()
    m3 = My3()
    m4 = My4()

    # My2
    assert IsImplementation(m2, _InterfM3) == False

    # My3
    assert IsImplementation(m3, _InterfM3) == True
    assert IsImplementation(m3, _InterfM4) == False

    # My4
    assert IsImplementation(m4, _InterfM4) == True
    assert IsImplementation(m4, _InterfM3) == True

    # When wrapped in an m4 interface it should still accept m3 as a declared interface
    wrapped_intef_m4 = _InterfM4(m4)
    assert IsImplementation(wrapped_intef_m4, _InterfM4) == True
    assert IsImplementation(wrapped_intef_m4, _InterfM3) == True
Exemple #6
0
def testBasics() -> None:
    class I(Interface):
        def foo(self, a, b=None):
            ""

        def bar(self):
            ""

    @ImplementsInterface(I)
    class C:
        def foo(self, a, b=None):
            ""

        def bar(self):
            ""

    class C2:
        def foo(self, a, b=None):
            ""

        def bar(self):
            ""

    class D:
        ""

    assert IsImplementation(I(C()), I) == True  # OK

    assert IsImplementation(C, I) == True  # OK
    # C2 shouldn't need to declare `@ImplementsInterface(I)`
    assert IsImplementation(C2, I, requires_declaration=False) == True
    assert IsImplementation(C2, I, requires_declaration=True) == False
    assert not IsImplementation(D, I) == True  # nope

    assert I(C) is C  # type:ignore[comparison-overlap]
    assert I(C2) is C2  # type:ignore[comparison-overlap]
    with pytest.raises(InterfaceError):
        I()

    with pytest.raises(BadImplementationError):
        I(D)

    # Now declare that C2 implements I
    DeclareClassImplements(C2, I)

    assert (IsImplementation(C2, I, requires_declaration=True) == True
            )  # Even if it doesn't declare
Exemple #7
0
def testImplementsInterfaceAsBoolError() -> None:
    """
    Test if the common erroneous use of interface.ImplementsInterface() instead of
    interface.IsImplementation() to test if an object implements an interface correctly
    raises a RuntimeError.
    """
    class I1(Interface):
        def M1(self):
            pass

    @ImplementsInterface(I1)
    class C1:
        def M1(self):
            pass

    obj = C1()

    assert IsImplementation(obj, I1)

    with pytest.raises(RuntimeError):
        if ImplementsInterface(obj, I1):  # type:ignore[arg-type]
            pytest.fail('Managed to test "if ImplementsInterface(obj, I1):"')
Exemple #8
0
def testIsImplementationWithBuiltInObjects() -> None:

    my_number = 10
    assert IsImplementation(my_number, _InterfM1) == False
Exemple #9
0
def testAttributes() -> None:
    class IZoo(Interface):
        zoo = Attribute(int)

    class I(Interface):
        foo = Attribute(int)
        bar = Attribute(str)
        foobar = Attribute(int, None)
        a_zoo = Attribute(IZoo)

    @ImplementsInterface(IZoo)
    class Zoo:
        pass

    # NOTE: This class 'C' doesn't REALLY implements 'I', although it says so. The problem is
    #       that there's a flaw with attributes *not being checked*.

    # In fact: Attributes should not be in the  (Abstract) properties COULD be in
    #          the interface, but they SHOULD NOT be type-checked (because it involves a
    #          getter call, and this affects runtime behaviour).
    #          This should be reviewed later.
    @ImplementsInterface(I)
    class C:
        pass

    c1 = C()
    c1.foo = 10  # type:ignore[attr-defined]
    c1.bar = "hello"  # type:ignore[attr-defined]
    c1.foobar = 20  # type:ignore[attr-defined]

    a_zoo = Zoo()
    a_zoo.zoo = 99  # type:ignore[attr-defined]
    c1.a_zoo = a_zoo  # type:ignore[attr-defined]

    c2 = C()

    assert IsImplementation(C, I) == True
    assert IsImplementation(c1, I) == True
    assert IsImplementation(c2, I) == True

    # NOTE: Testing private methods here
    # If we do a deprecated "full check", then its behaviour is a little bit more correct.
    from oop_ext.interface._interface import _IsImplementationFullChecking

    assert not _IsImplementationFullChecking(
        C, I) == True  # only works with instances
    assert _IsImplementationFullChecking(c1, I) == True  # OK, has attributes
    assert (not _IsImplementationFullChecking(c2, I) == True
            )  # not all the attributes necessary

    # must not be true if including an object that doesn't implement IZoo interface expected for
    # a_zoo attribute
    c1.a_zoo = "wrong"  # type:ignore[attr-defined]
    assert not _IsImplementationFullChecking(
        c1, I) == True  # failed, invalid attr type
    c1.a_zoo = a_zoo  # type:ignore[attr-defined]

    # test if we can set foobar to None
    c1.foobar = None  # type:ignore[attr-defined]
    assert IsImplementation(c1, I) == True  # OK

    c1.foobar = "hello"  # type:ignore[attr-defined]
    assert not _IsImplementationFullChecking(
        c1, I) == True  # failed, invalid attr type