X Tutup
# -*- coding: utf-8 -*- # FIXME: This test module randomly passes/fails even if all tests are skipped. # Something fishy is going on with the Test fixtures. Behavior seen on CI on # both Linux and Windows # TODO: Remove delay of class creations. Adding SetUp/TearDown may help """Test sub-classing managed types""" import System import pytest from Python.Test import (IInterfaceTest, SubClassTest, EventArgsTest, FunctionsTest, IGenericInterface, GenericVirtualMethodTest, SimpleClass, ISayHello1) from System.Collections.Generic import List def interface_test_class_fixture(subnamespace): """Delay creation of class until test starts.""" class InterfaceTestClass(IInterfaceTest): """class that implements the test interface""" __namespace__ = "Python.Test." + subnamespace def foo(self): return "InterfaceTestClass" def bar(self, x, i): return "/".join([x] * i) return InterfaceTestClass def interface_generic_class_fixture(subnamespace): class GenericInterfaceImpl(IGenericInterface[int]): __namespace__ = "Python.Test." + subnamespace def Get(self, x): return x return GenericInterfaceImpl def derived_class_fixture(subnamespace): """Delay creation of class until test starts.""" class DerivedClass(SubClassTest): """class that derives from a class deriving from IInterfaceTest""" __namespace__ = "Python.Test." + subnamespace def foo(self): return "DerivedClass" def base_foo(self): return SubClassTest.foo(self) def super_foo(self): return super(DerivedClass, self).foo() def bar(self, x, i): return "_".join([x] * i) def return_list(self): l = List[str]() l.Add("A") l.Add("B") l.Add("C") return l return DerivedClass def broken_derived_class_fixture(subnamespace): """Delay creation of class until test starts.""" class DerivedClass(SubClassTest): """class that derives from a class deriving from IInterfaceTest""" __namespace__ = 3 return DerivedClass def derived_event_test_class_fixture(subnamespace): """Delay creation of class until test starts.""" class DerivedEventTest(IInterfaceTest): """class that implements IInterfaceTest.TestEvent""" __namespace__ = "Python.Test." + subnamespace def __init__(self): self.event_handlers = [] # event handling def add_TestEvent(self, handler): self.event_handlers.append(handler) def remove_TestEvent(self, handler): self.event_handlers.remove(handler) def OnTestEvent(self, value): args = EventArgsTest(value) for handler in self.event_handlers: handler(self, args) return DerivedEventTest def test_base_class(): """Test base class managed type""" ob = SubClassTest() assert ob.foo() == "foo" assert FunctionsTest.test_foo(ob) == "foo" assert ob.bar("bar", 2) == "bar" assert FunctionsTest.test_bar(ob, "bar", 2) == "bar" assert ob.not_overriden() == "not_overriden" assert list(ob.return_list()) == ["a", "b", "c"] assert list(SubClassTest.test_list(ob)) == ["a", "b", "c"] def test_interface(): """Test python classes can derive from C# interfaces""" InterfaceTestClass = interface_test_class_fixture(test_interface.__name__) ob = InterfaceTestClass() assert ob.foo() == "InterfaceTestClass" assert FunctionsTest.test_foo(ob) == "InterfaceTestClass" assert ob.bar("bar", 2) == "bar/bar" assert FunctionsTest.test_bar(ob, "bar", 2) == "bar/bar" # pass_through will convert from InterfaceTestClass -> IInterfaceTest, # causing a new wrapper object to be created. Hence id will differ. x = FunctionsTest.pass_through_interface(ob) assert id(x) != id(ob) def test_derived_class(): """Test python class derived from managed type""" DerivedClass = derived_class_fixture(test_derived_class.__name__) ob = DerivedClass() assert ob.foo() == "DerivedClass" assert ob.base_foo() == "foo" assert ob.super_foo() == "foo" assert FunctionsTest.test_foo(ob) == "DerivedClass" assert ob.bar("bar", 2) == "bar_bar" assert FunctionsTest.test_bar(ob, "bar", 2) == "bar_bar" assert ob.not_overriden() == "not_overriden" assert list(ob.return_list()) == ["A", "B", "C"] assert list(SubClassTest.test_list(ob)) == ["A", "B", "C"] x = FunctionsTest.pass_through(ob) assert id(x) == id(ob) def test_broken_derived_class(): """Test python class derived from managed type with invalid namespace""" with pytest.raises(TypeError): DerivedClass = broken_derived_class_fixture(test_derived_class.__name__) ob = DerivedClass() def test_derived_traceback(): """Test python exception traceback in class derived from managed base""" class DerivedClass(SubClassTest): __namespace__ = "Python.Test.traceback" def foo(self): print (xyzname) return None import sys,traceback ob = DerivedClass() # direct call try: ob.foo() assert False except: e = sys.exc_info() assert "xyzname" in str(e[1]) location = traceback.extract_tb(e[2])[-1] assert location[2] == "foo" # call through managed code try: FunctionsTest.test_foo(ob) assert False except: e = sys.exc_info() assert "xyzname" in str(e[1]) location = traceback.extract_tb(e[2])[-1] assert location[2] == "foo" def test_create_instance(): """Test derived instances can be created from managed code""" DerivedClass = derived_class_fixture(test_create_instance.__name__) ob = FunctionsTest.create_instance(DerivedClass) assert ob.foo() == "DerivedClass" assert FunctionsTest.test_foo(ob) == "DerivedClass" assert ob.bar("bar", 2) == "bar_bar" assert FunctionsTest.test_bar(ob, "bar", 2) == "bar_bar" assert ob.not_overriden() == "not_overriden" x = FunctionsTest.pass_through(ob) assert id(x) == id(ob) InterfaceTestClass = interface_test_class_fixture(test_create_instance.__name__) ob2 = FunctionsTest.create_instance_interface(InterfaceTestClass) assert ob2.foo() == "InterfaceTestClass" assert FunctionsTest.test_foo(ob2) == "InterfaceTestClass" assert ob2.bar("bar", 2) == "bar/bar" assert FunctionsTest.test_bar(ob2, "bar", 2) == "bar/bar" y = FunctionsTest.pass_through_interface(ob2) assert id(y) != id(ob2) def test_events(): class EventHandler(object): def handler(self, x, args): self.value = args.value event_handler = EventHandler() x = SubClassTest() x.TestEvent += event_handler.handler assert FunctionsTest.test_event(x, 1) == 1 assert event_handler.value == 1 InterfaceTestClass = interface_test_class_fixture(test_events.__name__) i = InterfaceTestClass() with pytest.raises(System.NotImplementedException): FunctionsTest.test_event(i, 2) DerivedEventTest = derived_event_test_class_fixture(test_events.__name__) d = DerivedEventTest() d.add_TestEvent(event_handler.handler) assert FunctionsTest.test_event(d, 3) == 3 assert event_handler.value == 3 assert len(d.event_handlers) == 1 def test_isinstance_check(): a = [str(x) for x in range(0, 1000)] b = [System.String(x) for x in a] for x in a: assert not isinstance(x, System.Object) assert not isinstance(x, System.String) for x in b: assert isinstance(x, System.Object) assert isinstance(x, System.String) def test_namespace_and_init(): calls = [] class TestX(System.Object): __namespace__ = "test_clr_subclass_with_init_args" def __init__(self, *args, **kwargs): calls.append((args, kwargs)) t = TestX(1,2,3,foo="bar") assert len(calls) == 1 assert calls[0][0] == (1,2,3) assert calls[0][1] == {"foo":"bar"} def test_namespace_and_argless_init(): calls = [] class TestX(System.Object): __namespace__ = "test_clr_subclass_without_init_args" def __init__(self): calls.append(True) t = TestX() assert len(calls) == 1 assert calls[0] == True def test_namespace_and_no_init(): class TestX(System.Object): __namespace__ = "test_clr_subclass_without_init" q = 1 t = TestX() assert t.q == 1 def test_construction_from_clr(): import clr calls = [] class TestX(System.Object): __namespace__ = "test_clr_subclass_init_from_clr" @clr.clrmethod(None, [int, str]) def __init__(self, i, s): calls.append((i, s)) # Construct a TestX from Python t = TestX(1, "foo") assert len(calls) == 1 assert calls[0][0] == 1 assert calls[0][1] == "foo" # Reset calls and construct a TestX from CLR calls = [] tp = t.GetType() t2 = tp.GetConstructors()[0].Invoke(None) assert len(calls) == 0 # The object has only been constructed, now it needs to be initialized as well tp.GetMethod("__init__").Invoke(t2, [1, "foo"]) assert len(calls) == 1 assert calls[0][0] == 1 assert calls[0][1] == "foo" # regression test for https://github.com/pythonnet/pythonnet/issues/1565 def test_can_be_collected_by_gc(): from Python.Test import BaseClass class Derived(BaseClass): __namespace__ = 'test_can_be_collected_by_gc' inst = Derived() cycle = [inst] del inst cycle.append(cycle) del cycle import gc gc.collect() def test_generic_interface(): from System import Int32 from Python.Test import GenericInterfaceUser, SpecificInterfaceUser GenericInterfaceImpl = interface_generic_class_fixture(test_generic_interface.__name__) obj = GenericInterfaceImpl() SpecificInterfaceUser(obj, Int32(0)) GenericInterfaceUser[Int32](obj, Int32(0)) def test_virtual_generic_method(): class OverloadingSubclass(GenericVirtualMethodTest): __namespace__ = "test_virtual_generic_method_cls" class OverloadingSubclass2(OverloadingSubclass): __namespace__ = "test_virtual_generic_method_cls" obj = OverloadingSubclass() assert obj.VirtMethod[int](5) == 5 obj = OverloadingSubclass2() assert obj.VirtMethod[int](5) == 5 def test_implement_interface_and_class(): class DualSubClass0(ISayHello1, SimpleClass): __namespace__ = "Test" def SayHello(self): return "hello" obj = DualSubClass0()
X Tutup