test_factory_constructors.py revision 12391
112391Sjason@lowepower.comimport pytest 212391Sjason@lowepower.comimport re 312391Sjason@lowepower.com 412391Sjason@lowepower.comfrom pybind11_tests import factory_constructors as m 512391Sjason@lowepower.comfrom pybind11_tests.factory_constructors import tag 612391Sjason@lowepower.comfrom pybind11_tests import ConstructorStats 712391Sjason@lowepower.com 812391Sjason@lowepower.com 912391Sjason@lowepower.comdef test_init_factory_basic(): 1012391Sjason@lowepower.com """Tests py::init_factory() wrapper around various ways of returning the object""" 1112391Sjason@lowepower.com 1212391Sjason@lowepower.com cstats = [ConstructorStats.get(c) for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]] 1312391Sjason@lowepower.com cstats[0].alive() # force gc 1412391Sjason@lowepower.com n_inst = ConstructorStats.detail_reg_inst() 1512391Sjason@lowepower.com 1612391Sjason@lowepower.com x1 = m.TestFactory1(tag.unique_ptr, 3) 1712391Sjason@lowepower.com assert x1.value == "3" 1812391Sjason@lowepower.com y1 = m.TestFactory1(tag.pointer) 1912391Sjason@lowepower.com assert y1.value == "(empty)" 2012391Sjason@lowepower.com z1 = m.TestFactory1("hi!") 2112391Sjason@lowepower.com assert z1.value == "hi!" 2212391Sjason@lowepower.com 2312391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 3 2412391Sjason@lowepower.com 2512391Sjason@lowepower.com x2 = m.TestFactory2(tag.move) 2612391Sjason@lowepower.com assert x2.value == "(empty2)" 2712391Sjason@lowepower.com y2 = m.TestFactory2(tag.pointer, 7) 2812391Sjason@lowepower.com assert y2.value == "7" 2912391Sjason@lowepower.com z2 = m.TestFactory2(tag.unique_ptr, "hi again") 3012391Sjason@lowepower.com assert z2.value == "hi again" 3112391Sjason@lowepower.com 3212391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 6 3312391Sjason@lowepower.com 3412391Sjason@lowepower.com x3 = m.TestFactory3(tag.shared_ptr) 3512391Sjason@lowepower.com assert x3.value == "(empty3)" 3612391Sjason@lowepower.com y3 = m.TestFactory3(tag.pointer, 42) 3712391Sjason@lowepower.com assert y3.value == "42" 3812391Sjason@lowepower.com z3 = m.TestFactory3("bye") 3912391Sjason@lowepower.com assert z3.value == "bye" 4012391Sjason@lowepower.com 4112391Sjason@lowepower.com with pytest.raises(TypeError) as excinfo: 4212391Sjason@lowepower.com m.TestFactory3(tag.null_ptr) 4312391Sjason@lowepower.com assert str(excinfo.value) == "pybind11::init(): factory function returned nullptr" 4412391Sjason@lowepower.com 4512391Sjason@lowepower.com assert [i.alive() for i in cstats] == [3, 3, 3] 4612391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 9 4712391Sjason@lowepower.com 4812391Sjason@lowepower.com del x1, y2, y3, z3 4912391Sjason@lowepower.com assert [i.alive() for i in cstats] == [2, 2, 1] 5012391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 5 5112391Sjason@lowepower.com del x2, x3, y1, z1, z2 5212391Sjason@lowepower.com assert [i.alive() for i in cstats] == [0, 0, 0] 5312391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst 5412391Sjason@lowepower.com 5512391Sjason@lowepower.com assert [i.values() for i in cstats] == [ 5612391Sjason@lowepower.com ["3", "hi!"], 5712391Sjason@lowepower.com ["7", "hi again"], 5812391Sjason@lowepower.com ["42", "bye"] 5912391Sjason@lowepower.com ] 6012391Sjason@lowepower.com assert [i.default_constructions for i in cstats] == [1, 1, 1] 6112391Sjason@lowepower.com 6212391Sjason@lowepower.com 6312391Sjason@lowepower.comdef test_init_factory_signature(msg): 6412391Sjason@lowepower.com with pytest.raises(TypeError) as excinfo: 6512391Sjason@lowepower.com m.TestFactory1("invalid", "constructor", "arguments") 6612391Sjason@lowepower.com assert msg(excinfo.value) == """ 6712391Sjason@lowepower.com __init__(): incompatible constructor arguments. The following argument types are supported: 6812391Sjason@lowepower.com 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) 6912391Sjason@lowepower.com 2. m.factory_constructors.TestFactory1(arg0: str) 7012391Sjason@lowepower.com 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag) 7112391Sjason@lowepower.com 4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle) 7212391Sjason@lowepower.com 7312391Sjason@lowepower.com Invoked with: 'invalid', 'constructor', 'arguments' 7412391Sjason@lowepower.com """ # noqa: E501 line too long 7512391Sjason@lowepower.com 7612391Sjason@lowepower.com assert msg(m.TestFactory1.__init__.__doc__) == """ 7712391Sjason@lowepower.com __init__(*args, **kwargs) 7812391Sjason@lowepower.com Overloaded function. 7912391Sjason@lowepower.com 8012391Sjason@lowepower.com 1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None 8112391Sjason@lowepower.com 8212391Sjason@lowepower.com 2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None 8312391Sjason@lowepower.com 8412391Sjason@lowepower.com 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None 8512391Sjason@lowepower.com 8612391Sjason@lowepower.com 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None 8712391Sjason@lowepower.com """ # noqa: E501 line too long 8812391Sjason@lowepower.com 8912391Sjason@lowepower.com 9012391Sjason@lowepower.comdef test_init_factory_casting(): 9112391Sjason@lowepower.com """Tests py::init_factory() wrapper with various upcasting and downcasting returns""" 9212391Sjason@lowepower.com 9312391Sjason@lowepower.com cstats = [ConstructorStats.get(c) for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]] 9412391Sjason@lowepower.com cstats[0].alive() # force gc 9512391Sjason@lowepower.com n_inst = ConstructorStats.detail_reg_inst() 9612391Sjason@lowepower.com 9712391Sjason@lowepower.com # Construction from derived references: 9812391Sjason@lowepower.com a = m.TestFactory3(tag.pointer, tag.TF4, 4) 9912391Sjason@lowepower.com assert a.value == "4" 10012391Sjason@lowepower.com b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5) 10112391Sjason@lowepower.com assert b.value == "5" 10212391Sjason@lowepower.com c = m.TestFactory3(tag.pointer, tag.TF5, 6) 10312391Sjason@lowepower.com assert c.value == "6" 10412391Sjason@lowepower.com d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7) 10512391Sjason@lowepower.com assert d.value == "7" 10612391Sjason@lowepower.com 10712391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 4 10812391Sjason@lowepower.com 10912391Sjason@lowepower.com # Shared a lambda with TF3: 11012391Sjason@lowepower.com e = m.TestFactory4(tag.pointer, tag.TF4, 8) 11112391Sjason@lowepower.com assert e.value == "8" 11212391Sjason@lowepower.com 11312391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 5 11412391Sjason@lowepower.com assert [i.alive() for i in cstats] == [5, 3, 2] 11512391Sjason@lowepower.com 11612391Sjason@lowepower.com del a 11712391Sjason@lowepower.com assert [i.alive() for i in cstats] == [4, 2, 2] 11812391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 4 11912391Sjason@lowepower.com 12012391Sjason@lowepower.com del b, c, e 12112391Sjason@lowepower.com assert [i.alive() for i in cstats] == [1, 0, 1] 12212391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 1 12312391Sjason@lowepower.com 12412391Sjason@lowepower.com del d 12512391Sjason@lowepower.com assert [i.alive() for i in cstats] == [0, 0, 0] 12612391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst 12712391Sjason@lowepower.com 12812391Sjason@lowepower.com assert [i.values() for i in cstats] == [ 12912391Sjason@lowepower.com ["4", "5", "6", "7", "8"], 13012391Sjason@lowepower.com ["4", "5", "8"], 13112391Sjason@lowepower.com ["6", "7"] 13212391Sjason@lowepower.com ] 13312391Sjason@lowepower.com 13412391Sjason@lowepower.com 13512391Sjason@lowepower.comdef test_init_factory_alias(): 13612391Sjason@lowepower.com """Tests py::init_factory() wrapper with value conversions and alias types""" 13712391Sjason@lowepower.com 13812391Sjason@lowepower.com cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()] 13912391Sjason@lowepower.com cstats[0].alive() # force gc 14012391Sjason@lowepower.com n_inst = ConstructorStats.detail_reg_inst() 14112391Sjason@lowepower.com 14212391Sjason@lowepower.com a = m.TestFactory6(tag.base, 1) 14312391Sjason@lowepower.com assert a.get() == 1 14412391Sjason@lowepower.com assert not a.has_alias() 14512391Sjason@lowepower.com b = m.TestFactory6(tag.alias, "hi there") 14612391Sjason@lowepower.com assert b.get() == 8 14712391Sjason@lowepower.com assert b.has_alias() 14812391Sjason@lowepower.com c = m.TestFactory6(tag.alias, 3) 14912391Sjason@lowepower.com assert c.get() == 3 15012391Sjason@lowepower.com assert c.has_alias() 15112391Sjason@lowepower.com d = m.TestFactory6(tag.alias, tag.pointer, 4) 15212391Sjason@lowepower.com assert d.get() == 4 15312391Sjason@lowepower.com assert d.has_alias() 15412391Sjason@lowepower.com e = m.TestFactory6(tag.base, tag.pointer, 5) 15512391Sjason@lowepower.com assert e.get() == 5 15612391Sjason@lowepower.com assert not e.has_alias() 15712391Sjason@lowepower.com f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6) 15812391Sjason@lowepower.com assert f.get() == 6 15912391Sjason@lowepower.com assert f.has_alias() 16012391Sjason@lowepower.com 16112391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 6 16212391Sjason@lowepower.com assert [i.alive() for i in cstats] == [6, 4] 16312391Sjason@lowepower.com 16412391Sjason@lowepower.com del a, b, e 16512391Sjason@lowepower.com assert [i.alive() for i in cstats] == [3, 3] 16612391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 3 16712391Sjason@lowepower.com del f, c, d 16812391Sjason@lowepower.com assert [i.alive() for i in cstats] == [0, 0] 16912391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst 17012391Sjason@lowepower.com 17112391Sjason@lowepower.com class MyTest(m.TestFactory6): 17212391Sjason@lowepower.com def __init__(self, *args): 17312391Sjason@lowepower.com m.TestFactory6.__init__(self, *args) 17412391Sjason@lowepower.com 17512391Sjason@lowepower.com def get(self): 17612391Sjason@lowepower.com return -5 + m.TestFactory6.get(self) 17712391Sjason@lowepower.com 17812391Sjason@lowepower.com # Return Class by value, moved into new alias: 17912391Sjason@lowepower.com z = MyTest(tag.base, 123) 18012391Sjason@lowepower.com assert z.get() == 118 18112391Sjason@lowepower.com assert z.has_alias() 18212391Sjason@lowepower.com 18312391Sjason@lowepower.com # Return alias by value, moved into new alias: 18412391Sjason@lowepower.com y = MyTest(tag.alias, "why hello!") 18512391Sjason@lowepower.com assert y.get() == 5 18612391Sjason@lowepower.com assert y.has_alias() 18712391Sjason@lowepower.com 18812391Sjason@lowepower.com # Return Class by pointer, moved into new alias then original destroyed: 18912391Sjason@lowepower.com x = MyTest(tag.base, tag.pointer, 47) 19012391Sjason@lowepower.com assert x.get() == 42 19112391Sjason@lowepower.com assert x.has_alias() 19212391Sjason@lowepower.com 19312391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 3 19412391Sjason@lowepower.com assert [i.alive() for i in cstats] == [3, 3] 19512391Sjason@lowepower.com del x, y, z 19612391Sjason@lowepower.com assert [i.alive() for i in cstats] == [0, 0] 19712391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst 19812391Sjason@lowepower.com 19912391Sjason@lowepower.com assert [i.values() for i in cstats] == [ 20012391Sjason@lowepower.com ["1", "8", "3", "4", "5", "6", "123", "10", "47"], 20112391Sjason@lowepower.com ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"] 20212391Sjason@lowepower.com ] 20312391Sjason@lowepower.com 20412391Sjason@lowepower.com 20512391Sjason@lowepower.comdef test_init_factory_dual(): 20612391Sjason@lowepower.com """Tests init factory functions with dual main/alias factory functions""" 20712391Sjason@lowepower.com from pybind11_tests.factory_constructors import TestFactory7 20812391Sjason@lowepower.com 20912391Sjason@lowepower.com cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()] 21012391Sjason@lowepower.com cstats[0].alive() # force gc 21112391Sjason@lowepower.com n_inst = ConstructorStats.detail_reg_inst() 21212391Sjason@lowepower.com 21312391Sjason@lowepower.com class PythFactory7(TestFactory7): 21412391Sjason@lowepower.com def get(self): 21512391Sjason@lowepower.com return 100 + TestFactory7.get(self) 21612391Sjason@lowepower.com 21712391Sjason@lowepower.com a1 = TestFactory7(1) 21812391Sjason@lowepower.com a2 = PythFactory7(2) 21912391Sjason@lowepower.com assert a1.get() == 1 22012391Sjason@lowepower.com assert a2.get() == 102 22112391Sjason@lowepower.com assert not a1.has_alias() 22212391Sjason@lowepower.com assert a2.has_alias() 22312391Sjason@lowepower.com 22412391Sjason@lowepower.com b1 = TestFactory7(tag.pointer, 3) 22512391Sjason@lowepower.com b2 = PythFactory7(tag.pointer, 4) 22612391Sjason@lowepower.com assert b1.get() == 3 22712391Sjason@lowepower.com assert b2.get() == 104 22812391Sjason@lowepower.com assert not b1.has_alias() 22912391Sjason@lowepower.com assert b2.has_alias() 23012391Sjason@lowepower.com 23112391Sjason@lowepower.com c1 = TestFactory7(tag.mixed, 5) 23212391Sjason@lowepower.com c2 = PythFactory7(tag.mixed, 6) 23312391Sjason@lowepower.com assert c1.get() == 5 23412391Sjason@lowepower.com assert c2.get() == 106 23512391Sjason@lowepower.com assert not c1.has_alias() 23612391Sjason@lowepower.com assert c2.has_alias() 23712391Sjason@lowepower.com 23812391Sjason@lowepower.com d1 = TestFactory7(tag.base, tag.pointer, 7) 23912391Sjason@lowepower.com d2 = PythFactory7(tag.base, tag.pointer, 8) 24012391Sjason@lowepower.com assert d1.get() == 7 24112391Sjason@lowepower.com assert d2.get() == 108 24212391Sjason@lowepower.com assert not d1.has_alias() 24312391Sjason@lowepower.com assert d2.has_alias() 24412391Sjason@lowepower.com 24512391Sjason@lowepower.com # Both return an alias; the second multiplies the value by 10: 24612391Sjason@lowepower.com e1 = TestFactory7(tag.alias, tag.pointer, 9) 24712391Sjason@lowepower.com e2 = PythFactory7(tag.alias, tag.pointer, 10) 24812391Sjason@lowepower.com assert e1.get() == 9 24912391Sjason@lowepower.com assert e2.get() == 200 25012391Sjason@lowepower.com assert e1.has_alias() 25112391Sjason@lowepower.com assert e2.has_alias() 25212391Sjason@lowepower.com 25312391Sjason@lowepower.com f1 = TestFactory7(tag.shared_ptr, tag.base, 11) 25412391Sjason@lowepower.com f2 = PythFactory7(tag.shared_ptr, tag.base, 12) 25512391Sjason@lowepower.com assert f1.get() == 11 25612391Sjason@lowepower.com assert f2.get() == 112 25712391Sjason@lowepower.com assert not f1.has_alias() 25812391Sjason@lowepower.com assert f2.has_alias() 25912391Sjason@lowepower.com 26012391Sjason@lowepower.com g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13) 26112391Sjason@lowepower.com assert g1.get() == 13 26212391Sjason@lowepower.com assert not g1.has_alias() 26312391Sjason@lowepower.com with pytest.raises(TypeError) as excinfo: 26412391Sjason@lowepower.com PythFactory7(tag.shared_ptr, tag.invalid_base, 14) 26512391Sjason@lowepower.com assert (str(excinfo.value) == 26612391Sjason@lowepower.com "pybind11::init(): construction failed: returned holder-wrapped instance is not an " 26712391Sjason@lowepower.com "alias instance") 26812391Sjason@lowepower.com 26912391Sjason@lowepower.com assert [i.alive() for i in cstats] == [13, 7] 27012391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 13 27112391Sjason@lowepower.com 27212391Sjason@lowepower.com del a1, a2, b1, d1, e1, e2 27312391Sjason@lowepower.com assert [i.alive() for i in cstats] == [7, 4] 27412391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst + 7 27512391Sjason@lowepower.com del b2, c1, c2, d2, f1, f2, g1 27612391Sjason@lowepower.com assert [i.alive() for i in cstats] == [0, 0] 27712391Sjason@lowepower.com assert ConstructorStats.detail_reg_inst() == n_inst 27812391Sjason@lowepower.com 27912391Sjason@lowepower.com assert [i.values() for i in cstats] == [ 28012391Sjason@lowepower.com ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"], 28112391Sjason@lowepower.com ["2", "4", "6", "8", "9", "100", "12"] 28212391Sjason@lowepower.com ] 28312391Sjason@lowepower.com 28412391Sjason@lowepower.com 28512391Sjason@lowepower.comdef test_no_placement_new(capture): 28612391Sjason@lowepower.com """Prior to 2.2, `py::init<...>` relied on the type supporting placement 28712391Sjason@lowepower.com new; this tests a class without placement new support.""" 28812391Sjason@lowepower.com with capture: 28912391Sjason@lowepower.com a = m.NoPlacementNew(123) 29012391Sjason@lowepower.com 29112391Sjason@lowepower.com found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) 29212391Sjason@lowepower.com assert found 29312391Sjason@lowepower.com assert a.i == 123 29412391Sjason@lowepower.com with capture: 29512391Sjason@lowepower.com del a 29612391Sjason@lowepower.com pytest.gc_collect() 29712391Sjason@lowepower.com assert capture == "operator delete called on " + found.group(1) 29812391Sjason@lowepower.com 29912391Sjason@lowepower.com with capture: 30012391Sjason@lowepower.com b = m.NoPlacementNew() 30112391Sjason@lowepower.com 30212391Sjason@lowepower.com found = re.search(r'^operator new called, returning (\d+)\n$', str(capture)) 30312391Sjason@lowepower.com assert found 30412391Sjason@lowepower.com assert b.i == 100 30512391Sjason@lowepower.com with capture: 30612391Sjason@lowepower.com del b 30712391Sjason@lowepower.com pytest.gc_collect() 30812391Sjason@lowepower.com assert capture == "operator delete called on " + found.group(1) 30912391Sjason@lowepower.com 31012391Sjason@lowepower.com 31112391Sjason@lowepower.comdef test_multiple_inheritance(): 31212391Sjason@lowepower.com class MITest(m.TestFactory1, m.TestFactory2): 31312391Sjason@lowepower.com def __init__(self): 31412391Sjason@lowepower.com m.TestFactory1.__init__(self, tag.unique_ptr, 33) 31512391Sjason@lowepower.com m.TestFactory2.__init__(self, tag.move) 31612391Sjason@lowepower.com 31712391Sjason@lowepower.com a = MITest() 31812391Sjason@lowepower.com assert m.TestFactory1.value.fget(a) == "33" 31912391Sjason@lowepower.com assert m.TestFactory2.value.fget(a) == "(empty2)" 32012391Sjason@lowepower.com 32112391Sjason@lowepower.com 32212391Sjason@lowepower.comdef create_and_destroy(*args): 32312391Sjason@lowepower.com a = m.NoisyAlloc(*args) 32412391Sjason@lowepower.com print("---") 32512391Sjason@lowepower.com del a 32612391Sjason@lowepower.com pytest.gc_collect() 32712391Sjason@lowepower.com 32812391Sjason@lowepower.com 32912391Sjason@lowepower.comdef strip_comments(s): 33012391Sjason@lowepower.com return re.sub(r'\s+#.*', '', s) 33112391Sjason@lowepower.com 33212391Sjason@lowepower.com 33312391Sjason@lowepower.comdef test_reallocations(capture, msg): 33412391Sjason@lowepower.com """When the constructor is overloaded, previous overloads can require a preallocated value. 33512391Sjason@lowepower.com This test makes sure that such preallocated values only happen when they might be necessary, 33612391Sjason@lowepower.com and that they are deallocated properly""" 33712391Sjason@lowepower.com 33812391Sjason@lowepower.com pytest.gc_collect() 33912391Sjason@lowepower.com 34012391Sjason@lowepower.com with capture: 34112391Sjason@lowepower.com create_and_destroy(1) 34212391Sjason@lowepower.com assert msg(capture) == """ 34312391Sjason@lowepower.com noisy new 34412391Sjason@lowepower.com noisy placement new 34512391Sjason@lowepower.com NoisyAlloc(int 1) 34612391Sjason@lowepower.com --- 34712391Sjason@lowepower.com ~NoisyAlloc() 34812391Sjason@lowepower.com noisy delete 34912391Sjason@lowepower.com """ 35012391Sjason@lowepower.com with capture: 35112391Sjason@lowepower.com create_and_destroy(1.5) 35212391Sjason@lowepower.com assert msg(capture) == strip_comments(""" 35312391Sjason@lowepower.com noisy new # allocation required to attempt first overload 35412391Sjason@lowepower.com noisy delete # have to dealloc before considering factory init overload 35512391Sjason@lowepower.com noisy new # pointer factory calling "new", part 1: allocation 35612391Sjason@lowepower.com NoisyAlloc(double 1.5) # ... part two, invoking constructor 35712391Sjason@lowepower.com --- 35812391Sjason@lowepower.com ~NoisyAlloc() # Destructor 35912391Sjason@lowepower.com noisy delete # operator delete 36012391Sjason@lowepower.com """) 36112391Sjason@lowepower.com 36212391Sjason@lowepower.com with capture: 36312391Sjason@lowepower.com create_and_destroy(2, 3) 36412391Sjason@lowepower.com assert msg(capture) == strip_comments(""" 36512391Sjason@lowepower.com noisy new # pointer factory calling "new", allocation 36612391Sjason@lowepower.com NoisyAlloc(int 2) # constructor 36712391Sjason@lowepower.com --- 36812391Sjason@lowepower.com ~NoisyAlloc() # Destructor 36912391Sjason@lowepower.com noisy delete # operator delete 37012391Sjason@lowepower.com """) 37112391Sjason@lowepower.com 37212391Sjason@lowepower.com with capture: 37312391Sjason@lowepower.com create_and_destroy(2.5, 3) 37412391Sjason@lowepower.com assert msg(capture) == strip_comments(""" 37512391Sjason@lowepower.com NoisyAlloc(double 2.5) # construction (local func variable: operator_new not called) 37612391Sjason@lowepower.com noisy new # return-by-value "new" part 1: allocation 37712391Sjason@lowepower.com ~NoisyAlloc() # moved-away local func variable destruction 37812391Sjason@lowepower.com --- 37912391Sjason@lowepower.com ~NoisyAlloc() # Destructor 38012391Sjason@lowepower.com noisy delete # operator delete 38112391Sjason@lowepower.com """) 38212391Sjason@lowepower.com 38312391Sjason@lowepower.com with capture: 38412391Sjason@lowepower.com create_and_destroy(3.5, 4.5) 38512391Sjason@lowepower.com assert msg(capture) == strip_comments(""" 38612391Sjason@lowepower.com noisy new # preallocation needed before invoking placement-new overload 38712391Sjason@lowepower.com noisy placement new # Placement new 38812391Sjason@lowepower.com NoisyAlloc(double 3.5) # construction 38912391Sjason@lowepower.com --- 39012391Sjason@lowepower.com ~NoisyAlloc() # Destructor 39112391Sjason@lowepower.com noisy delete # operator delete 39212391Sjason@lowepower.com """) 39312391Sjason@lowepower.com 39412391Sjason@lowepower.com with capture: 39512391Sjason@lowepower.com create_and_destroy(4, 0.5) 39612391Sjason@lowepower.com assert msg(capture) == strip_comments(""" 39712391Sjason@lowepower.com noisy new # preallocation needed before invoking placement-new overload 39812391Sjason@lowepower.com noisy delete # deallocation of preallocated storage 39912391Sjason@lowepower.com noisy new # Factory pointer allocation 40012391Sjason@lowepower.com NoisyAlloc(int 4) # factory pointer construction 40112391Sjason@lowepower.com --- 40212391Sjason@lowepower.com ~NoisyAlloc() # Destructor 40312391Sjason@lowepower.com noisy delete # operator delete 40412391Sjason@lowepower.com """) 40512391Sjason@lowepower.com 40612391Sjason@lowepower.com with capture: 40712391Sjason@lowepower.com create_and_destroy(5, "hi") 40812391Sjason@lowepower.com assert msg(capture) == strip_comments(""" 40912391Sjason@lowepower.com noisy new # preallocation needed before invoking first placement new 41012391Sjason@lowepower.com noisy delete # delete before considering new-style constructor 41112391Sjason@lowepower.com noisy new # preallocation for second placement new 41212391Sjason@lowepower.com noisy placement new # Placement new in the second placement new overload 41312391Sjason@lowepower.com NoisyAlloc(int 5) # construction 41412391Sjason@lowepower.com --- 41512391Sjason@lowepower.com ~NoisyAlloc() # Destructor 41612391Sjason@lowepower.com noisy delete # operator delete 41712391Sjason@lowepower.com """) 41812391Sjason@lowepower.com 41912391Sjason@lowepower.com 42012391Sjason@lowepower.com@pytest.unsupported_on_py2 42112391Sjason@lowepower.comdef test_invalid_self(): 42212391Sjason@lowepower.com """Tests invocation of the pybind-registered base class with an invalid `self` argument. You 42312391Sjason@lowepower.com can only actually do this on Python 3: Python 2 raises an exception itself if you try.""" 42412391Sjason@lowepower.com class NotPybindDerived(object): 42512391Sjason@lowepower.com pass 42612391Sjason@lowepower.com 42712391Sjason@lowepower.com # Attempts to initialize with an invalid type passed as `self`: 42812391Sjason@lowepower.com class BrokenTF1(m.TestFactory1): 42912391Sjason@lowepower.com def __init__(self, bad): 43012391Sjason@lowepower.com if bad == 1: 43112391Sjason@lowepower.com a = m.TestFactory2(tag.pointer, 1) 43212391Sjason@lowepower.com m.TestFactory1.__init__(a, tag.pointer) 43312391Sjason@lowepower.com elif bad == 2: 43412391Sjason@lowepower.com a = NotPybindDerived() 43512391Sjason@lowepower.com m.TestFactory1.__init__(a, tag.pointer) 43612391Sjason@lowepower.com 43712391Sjason@lowepower.com # Same as above, but for a class with an alias: 43812391Sjason@lowepower.com class BrokenTF6(m.TestFactory6): 43912391Sjason@lowepower.com def __init__(self, bad): 44012391Sjason@lowepower.com if bad == 1: 44112391Sjason@lowepower.com a = m.TestFactory2(tag.pointer, 1) 44212391Sjason@lowepower.com m.TestFactory6.__init__(a, tag.base, 1) 44312391Sjason@lowepower.com elif bad == 2: 44412391Sjason@lowepower.com a = m.TestFactory2(tag.pointer, 1) 44512391Sjason@lowepower.com m.TestFactory6.__init__(a, tag.alias, 1) 44612391Sjason@lowepower.com elif bad == 3: 44712391Sjason@lowepower.com m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.base, 1) 44812391Sjason@lowepower.com elif bad == 4: 44912391Sjason@lowepower.com m.TestFactory6.__init__(NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1) 45012391Sjason@lowepower.com 45112391Sjason@lowepower.com for arg in (1, 2): 45212391Sjason@lowepower.com with pytest.raises(TypeError) as excinfo: 45312391Sjason@lowepower.com BrokenTF1(arg) 45412391Sjason@lowepower.com assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" 45512391Sjason@lowepower.com 45612391Sjason@lowepower.com for arg in (1, 2, 3, 4): 45712391Sjason@lowepower.com with pytest.raises(TypeError) as excinfo: 45812391Sjason@lowepower.com BrokenTF6(arg) 45912391Sjason@lowepower.com assert str(excinfo.value) == "__init__(self, ...) called with invalid `self` argument" 460