test_smart_ptr.py revision 11986
1import pytest 2from pybind11_tests import ConstructorStats 3 4 5def test_smart_ptr(capture): 6 # Object1 7 from pybind11_tests import (MyObject1, make_object_1, make_object_2, 8 print_object_1, print_object_2, print_object_3, print_object_4) 9 10 for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1): 11 assert o.getRefCount() == 1 12 with capture: 13 print_object_1(o) 14 print_object_2(o) 15 print_object_3(o) 16 print_object_4(o) 17 assert capture == "MyObject1[{i}]\n".format(i=i) * 4 18 19 from pybind11_tests import (make_myobject1_1, make_myobject1_2, 20 print_myobject1_1, print_myobject1_2, 21 print_myobject1_3, print_myobject1_4) 22 23 for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4): 24 print(o) 25 with capture: 26 if not isinstance(o, int): 27 print_object_1(o) 28 print_object_2(o) 29 print_object_3(o) 30 print_object_4(o) 31 print_myobject1_1(o) 32 print_myobject1_2(o) 33 print_myobject1_3(o) 34 print_myobject1_4(o) 35 assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8) 36 37 cstats = ConstructorStats.get(MyObject1) 38 assert cstats.alive() == 0 39 expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4 40 assert cstats.values() == expected_values 41 assert cstats.default_constructions == 0 42 assert cstats.copy_constructions == 0 43 # assert cstats.move_constructions >= 0 # Doesn't invoke any 44 assert cstats.copy_assignments == 0 45 assert cstats.move_assignments == 0 46 47 # Object2 48 from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2, 49 make_myobject3_1, make_myobject3_2, 50 print_myobject2_1, print_myobject2_2, 51 print_myobject2_3, print_myobject2_4) 52 53 for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]): 54 print(o) 55 with capture: 56 print_myobject2_1(o) 57 print_myobject2_2(o) 58 print_myobject2_3(o) 59 print_myobject2_4(o) 60 assert capture == "MyObject2[{i}]\n".format(i=i) * 4 61 62 cstats = ConstructorStats.get(MyObject2) 63 assert cstats.alive() == 1 64 o = None 65 assert cstats.alive() == 0 66 assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]'] 67 assert cstats.default_constructions == 0 68 assert cstats.copy_constructions == 0 69 # assert cstats.move_constructions >= 0 # Doesn't invoke any 70 assert cstats.copy_assignments == 0 71 assert cstats.move_assignments == 0 72 73 # Object3 74 from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2, 75 print_myobject3_3, print_myobject3_4) 76 77 for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]): 78 print(o) 79 with capture: 80 print_myobject3_1(o) 81 print_myobject3_2(o) 82 print_myobject3_3(o) 83 print_myobject3_4(o) 84 assert capture == "MyObject3[{i}]\n".format(i=i) * 4 85 86 cstats = ConstructorStats.get(MyObject3) 87 assert cstats.alive() == 1 88 o = None 89 assert cstats.alive() == 0 90 assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]'] 91 assert cstats.default_constructions == 0 92 assert cstats.copy_constructions == 0 93 # assert cstats.move_constructions >= 0 # Doesn't invoke any 94 assert cstats.copy_assignments == 0 95 assert cstats.move_assignments == 0 96 97 # Object and ref 98 from pybind11_tests import Object, cstats_ref 99 100 cstats = ConstructorStats.get(Object) 101 assert cstats.alive() == 0 102 assert cstats.values() == [] 103 assert cstats.default_constructions == 10 104 assert cstats.copy_constructions == 0 105 # assert cstats.move_constructions >= 0 # Doesn't invoke any 106 assert cstats.copy_assignments == 0 107 assert cstats.move_assignments == 0 108 109 cstats = cstats_ref() 110 assert cstats.alive() == 0 111 assert cstats.values() == ['from pointer'] * 10 112 assert cstats.default_constructions == 30 113 assert cstats.copy_constructions == 12 114 # assert cstats.move_constructions >= 0 # Doesn't invoke any 115 assert cstats.copy_assignments == 30 116 assert cstats.move_assignments == 0 117 118 119def test_unique_nodelete(): 120 from pybind11_tests import MyObject4 121 o = MyObject4(23) 122 assert o.value == 23 123 cstats = ConstructorStats.get(MyObject4) 124 assert cstats.alive() == 1 125 del o 126 cstats = ConstructorStats.get(MyObject4) 127 assert cstats.alive() == 1 # Leak, but that's intentional 128 129 130def test_shared_ptr_and_references(): 131 from pybind11_tests.smart_ptr import SharedPtrRef, A 132 133 s = SharedPtrRef() 134 stats = ConstructorStats.get(A) 135 assert stats.alive() == 2 136 137 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false) 138 assert stats.alive() == 2 139 assert s.set_ref(ref) 140 with pytest.raises(RuntimeError) as excinfo: 141 assert s.set_holder(ref) 142 assert "Unable to cast from non-held to held instance" in str(excinfo.value) 143 144 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true) 145 assert stats.alive() == 3 146 assert s.set_ref(copy) 147 assert s.set_holder(copy) 148 149 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false) 150 assert stats.alive() == 3 151 assert s.set_ref(holder_ref) 152 assert s.set_holder(holder_ref) 153 154 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true) 155 assert stats.alive() == 3 156 assert s.set_ref(holder_copy) 157 assert s.set_holder(holder_copy) 158 159 del ref, copy, holder_ref, holder_copy, s 160 assert stats.alive() == 0 161 162 163def test_shared_ptr_from_this_and_references(): 164 from pybind11_tests.smart_ptr import SharedFromThisRef, B 165 166 s = SharedFromThisRef() 167 stats = ConstructorStats.get(B) 168 assert stats.alive() == 2 169 170 ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false) 171 assert stats.alive() == 2 172 assert s.set_ref(ref) 173 assert s.set_holder(ref) # std::enable_shared_from_this can create a holder from a reference 174 175 bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true) 176 assert stats.alive() == 2 177 assert s.set_ref(bad_wp) 178 with pytest.raises(RuntimeError) as excinfo: 179 assert s.set_holder(bad_wp) 180 assert "Unable to cast from non-held to held instance" in str(excinfo.value) 181 182 copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false) 183 assert stats.alive() == 3 184 assert s.set_ref(copy) 185 assert s.set_holder(copy) 186 187 holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false) 188 assert stats.alive() == 3 189 assert s.set_ref(holder_ref) 190 assert s.set_holder(holder_ref) 191 192 holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false) 193 assert stats.alive() == 3 194 assert s.set_ref(holder_copy) 195 assert s.set_holder(holder_copy) 196 197 del ref, bad_wp, copy, holder_ref, holder_copy, s 198 assert stats.alive() == 0 199