Skip to content

Commit 15f40d2

Browse files
committed
Cleanup nodelete holder objects in test_smart_ptr, and enable those tests
1 parent b756519 commit 15f40d2

File tree

3 files changed

+44
-13
lines changed

3 files changed

+44
-13
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,7 @@ jobs:
225225
--suppressions=tests/valgrind-misc.supp
226226
--gen-suppressions=all
227227
python -m pytest
228-
tests/test_[abcdefhijklmnopqrtuwxyz]*.py
229-
tests/test_sequences_and_iterators.py
230-
tests/test_stl.py
231-
tests/test_stl_binders.py
228+
tests/test_[abcdefhijklmnopqrstuwxyz]*.py
232229
233230
234231
# # Testing on clang using the excellent silkeh clang docker images

tests/test_smart_ptr.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,33 +176,59 @@ TEST_SUBMODULE(smart_ptr, m) {
176176

177177
// test_unique_nodelete
178178
// Object with a private destructor
179+
class MyObject4;
180+
static std::unordered_set<MyObject4 *> myobject4_instances;
179181
class MyObject4 {
180182
public:
181-
MyObject4(int value) : value{value} { print_created(this); }
183+
MyObject4(int value) : value{value} {
184+
print_created(this);
185+
myobject4_instances.insert(this);
186+
}
182187
int value;
188+
189+
static void cleanupAllInstances() {
190+
for (auto o : std::exchange(myobject4_instances, {}))
191+
delete o;
192+
}
183193
private:
184-
~MyObject4() { print_destroyed(this); }
194+
~MyObject4() {
195+
myobject4_instances.erase(this);
196+
print_destroyed(this);
197+
}
185198
};
186199
py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4")
187200
.def(py::init<int>())
188-
.def_readwrite("value", &MyObject4::value);
201+
.def_readwrite("value", &MyObject4::value)
202+
.def_static("cleanup_all_instances", &MyObject4::cleanupAllInstances);
189203

190204
// test_unique_deleter
191205
// Object with std::unique_ptr<T, D> where D is not matching the base class
192206
// Object with a protected destructor
207+
class MyObject4a;
208+
static std::unordered_set<MyObject4a *> myobject4a_instances;
193209
class MyObject4a {
194210
public:
195211
MyObject4a(int i) {
196212
value = i;
197213
print_created(this);
214+
myobject4a_instances.insert(this);
198215
};
199216
int value;
217+
218+
static void cleanupAllInstances() {
219+
for (auto o : std::exchange(myobject4a_instances, {}))
220+
delete o;
221+
}
200222
protected:
201-
virtual ~MyObject4a() { print_destroyed(this); }
223+
virtual ~MyObject4a() {
224+
myobject4a_instances.erase(this);
225+
print_destroyed(this);
226+
}
202227
};
203228
py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a")
204229
.def(py::init<int>())
205-
.def_readwrite("value", &MyObject4a::value);
230+
.def_readwrite("value", &MyObject4a::value)
231+
.def_static("cleanup_all_instances", &MyObject4a::cleanupAllInstances);
206232

207233
// Object derived but with public destructor and no Deleter in default holder
208234
class MyObject4b : public MyObject4a {

tests/test_smart_ptr.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ def test_unique_nodelete():
125125
cstats = ConstructorStats.get(m.MyObject4)
126126
assert cstats.alive() == 1
127127
del o
128-
assert cstats.alive() == 1 # Leak, but that's intentional
128+
assert cstats.alive() == 1
129+
m.MyObject4.cleanup_all_instances()
130+
assert cstats.alive() == 0
129131

130132

131133
def test_unique_nodelete4a():
@@ -134,19 +136,25 @@ def test_unique_nodelete4a():
134136
cstats = ConstructorStats.get(m.MyObject4a)
135137
assert cstats.alive() == 1
136138
del o
137-
assert cstats.alive() == 1 # Leak, but that's intentional
139+
assert cstats.alive() == 1
140+
m.MyObject4a.cleanup_all_instances()
141+
assert cstats.alive() == 0
138142

139143

140144
def test_unique_deleter():
145+
m.MyObject4a(0)
141146
o = m.MyObject4b(23)
142147
assert o.value == 23
143148
cstats4a = ConstructorStats.get(m.MyObject4a)
144-
assert cstats4a.alive() == 2 # Two because of previous test
149+
assert cstats4a.alive() == 2
145150
cstats4b = ConstructorStats.get(m.MyObject4b)
146151
assert cstats4b.alive() == 1
147152
del o
148-
assert cstats4a.alive() == 1 # Should now only be one leftover from previous test
153+
assert cstats4a.alive() == 1 # Should now only be one leftover
149154
assert cstats4b.alive() == 0 # Should be deleted
155+
m.MyObject4a.cleanup_all_instances()
156+
assert cstats4a.alive() == 0
157+
assert cstats4b.alive() == 0
150158

151159

152160
def test_large_holder():

0 commit comments

Comments
 (0)