1
1
# -*- coding: utf-8 -*-
2
2
import pytest
3
3
4
- import env # noqa: F401
5
-
6
4
import pybind11_tests .class_sh_trampoline_shared_from_this as m
7
5
8
- import gc
9
- import weakref
10
-
11
6
12
7
class PySft (m .Sft ):
13
8
pass
14
9
15
10
16
- def test_pass_shared_ptr ():
11
+ def test_release_and_immediate_reclaim ():
17
12
obj = PySft ("PySft" )
18
13
assert obj .history == "PySft"
19
- assert obj .use_count () in [ 2 , - 1 ] # TODO: Be smarter/stricter.
20
- m .pass_shared_ptr (obj )
14
+ assert obj .use_count () == 1
15
+ assert m .pass_shared_ptr (obj ) == 2
21
16
assert obj .history == "PySft_PassSharedPtr"
22
- assert obj .use_count () in [2 , - 1 ]
23
- uc = m .pass_shared_ptr (obj )
24
- assert uc == 2 # +1 for passed argument, +1 for shared_from_this.
17
+ assert obj .use_count () == 1
18
+ assert m .pass_shared_ptr (obj ) == 2
25
19
assert obj .history == "PySft_PassSharedPtr_PassSharedPtr"
26
- assert obj .use_count () in [2 , - 1 ]
20
+ assert obj .use_count () == 1
21
+
22
+ obj = PySft ("" )
23
+ while True :
24
+ m .pass_shared_ptr (obj )
25
+ assert obj .history == ""
26
+ assert obj .use_count () == 1
27
+ break # Comment out for manual leak checking (use `top` command).
27
28
28
29
29
- def test_pass_shared_ptr_while_stashed ():
30
+ def test_release_to_cpp_stash ():
30
31
obj = PySft ("PySft" )
31
- obj_wr = weakref .ref (obj )
32
32
stash1 = m .SftSharedPtrStash (1 )
33
33
stash1 .Add (obj )
34
34
assert obj .history == "PySft_Stash1Add"
35
- assert obj .use_count () in [ 2 , - 1 ]
35
+ assert obj .use_count () == 1
36
36
assert stash1 .history (0 ) == "PySft_Stash1Add"
37
37
assert stash1 .use_count (0 ) == 1 # obj does NOT own the shared_ptr anymore.
38
- uc = m .pass_shared_ptr (obj )
39
- assert uc == 3 # +1 for passed argument, +1 for shared_from_this.
38
+ assert m .pass_shared_ptr (obj ) == 3
40
39
assert obj .history == "PySft_Stash1Add_PassSharedPtr"
41
- assert obj .use_count () in [ 2 , - 1 ]
40
+ assert obj .use_count () == 1
42
41
assert stash1 .history (0 ) == "PySft_Stash1Add_PassSharedPtr"
43
42
assert stash1 .use_count (0 ) == 1
44
43
stash2 = m .SftSharedPtrStash (2 )
45
44
stash2 .Add (obj )
46
45
assert obj .history == "PySft_Stash1Add_PassSharedPtr_Stash2Add"
47
- assert obj .use_count () in [ 3 , - 1 ]
46
+ assert obj .use_count () == 2
48
47
assert stash2 .history (0 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add"
49
48
assert stash2 .use_count (0 ) == 2
50
49
stash2 .Add (obj )
51
- assert obj .history == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
52
- assert obj .use_count () in [4 , - 1 ]
50
+ exp_oh = "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
51
+ assert obj .history == exp_oh
52
+ assert obj .use_count () == 3
53
+ assert stash1 .history (0 ) == exp_oh
53
54
assert stash1 .use_count (0 ) == 3
54
- assert stash1 .history (0 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
55
+ assert stash2 .history (0 ) == exp_oh
55
56
assert stash2 .use_count (0 ) == 3
56
- assert stash2 .history (0 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
57
+ assert stash2 .history (1 ) == exp_oh
57
58
assert stash2 .use_count (1 ) == 3
58
- assert stash2 .history (1 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
59
59
del obj
60
+ assert stash2 .history (0 ) == exp_oh
60
61
assert stash2 .use_count (0 ) == 3
61
- assert stash2 .history (0 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
62
+ assert stash2 .history (1 ) == exp_oh
62
63
assert stash2 .use_count (1 ) == 3
63
- assert stash2 .history (1 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
64
64
del stash2
65
- gc .collect ()
66
- assert obj_wr () is not None
67
- assert stash1 .history (0 ) == "PySft_Stash1Add_PassSharedPtr_Stash2Add_Stash2Add"
68
- del stash1
69
- gc .collect ()
70
- if not env .PYPY :
71
- assert obj_wr () is None
65
+ assert stash1 .history (0 ) == exp_oh
66
+ assert stash1 .use_count (0 ) == 1
72
67
73
68
74
- def test_pass_shared_ptr_while_stashed_with_shared_from_this ():
69
+ def test_release_to_cpp_stash_leak ():
70
+ obj = PySft ("" )
71
+ while True :
72
+ stash1 = m .SftSharedPtrStash (1 )
73
+ stash1 .Add (obj )
74
+ assert obj .history == ""
75
+ assert obj .use_count () == 1
76
+ assert stash1 .use_count (0 ) == 1
77
+ stash1 .Add (obj )
78
+ assert obj .history == ""
79
+ assert obj .use_count () == 2
80
+ assert stash1 .use_count (0 ) == 2
81
+ assert stash1 .use_count (1 ) == 2
82
+ break # Comment out for manual leak checking (use `top` command).
83
+
84
+
85
+ def test_release_to_cpp_stash_via_shared_from_this ():
75
86
obj = PySft ("PySft" )
76
- obj_wr = weakref .ref (obj )
77
87
stash1 = m .SftSharedPtrStash (1 )
78
88
stash1 .AddSharedFromThis (obj )
79
89
assert obj .history == "PySft_Stash1AddSharedFromThis"
@@ -82,11 +92,57 @@ def test_pass_shared_ptr_while_stashed_with_shared_from_this():
82
92
assert obj .history == "PySft_Stash1AddSharedFromThis_Stash1AddSharedFromThis"
83
93
assert stash1 .use_count (0 ) == 3
84
94
assert stash1 .use_count (1 ) == 3
85
- del obj
86
- del stash1
87
- gc .collect ()
88
- if not env .PYPY :
89
- assert obj_wr () is None
95
+
96
+
97
+ def test_release_to_cpp_stash_via_shared_from_this_leak_1 (): # WIP
98
+ m .to_cout ("" )
99
+ m .to_cout ("" )
100
+ m .to_cout ("Add first" )
101
+ obj = PySft ("" )
102
+ import weakref
103
+
104
+ obj_wr = weakref .ref (obj )
105
+ while True :
106
+ stash1 = m .SftSharedPtrStash (1 )
107
+ stash1 .Add (obj )
108
+ assert obj .history == ""
109
+ assert obj .use_count () == 1
110
+ assert stash1 .use_count (0 ) == 1
111
+ stash1 .AddSharedFromThis (obj )
112
+ assert obj .history == ""
113
+ assert obj .use_count () == 2
114
+ assert stash1 .use_count (0 ) == 2
115
+ assert stash1 .use_count (1 ) == 2
116
+ del obj
117
+ assert obj_wr () is not None
118
+ assert stash1 .use_count (0 ) == 2
119
+ assert stash1 .use_count (1 ) == 2
120
+ break # Comment out for manual leak checking (use `top` command).
121
+
122
+
123
+ def test_release_to_cpp_stash_via_shared_from_this_leak_2 (): # WIP
124
+ m .to_cout ("" )
125
+ m .to_cout ("AddSharedFromThis only" )
126
+ obj = PySft ("" )
127
+ import weakref
128
+
129
+ obj_wr = weakref .ref (obj )
130
+ while True :
131
+ stash1 = m .SftSharedPtrStash (1 )
132
+ stash1 .AddSharedFromThis (obj )
133
+ assert obj .history == ""
134
+ assert obj .use_count () == 2
135
+ assert stash1 .use_count (0 ) == 2
136
+ stash1 .AddSharedFromThis (obj )
137
+ assert obj .history == ""
138
+ assert obj .use_count () == 3
139
+ assert stash1 .use_count (0 ) == 3
140
+ assert stash1 .use_count (1 ) == 3
141
+ del obj
142
+ assert obj_wr () is None # BAD NEEDS FIXING
143
+ assert stash1 .use_count (0 ) == 2
144
+ assert stash1 .use_count (1 ) == 2
145
+ break # Comment out for manual leak checking (use `top` command).
90
146
91
147
92
148
def test_pass_released_shared_ptr_as_unique_ptr ():
0 commit comments