1 | // Boost.Signals2 library |
2 | |
3 | // Copyright Douglas Gregor 2001-2003. |
4 | // Use, modification and |
5 | // distribution is subject to the Boost Software License, Version |
6 | // 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
7 | // http://www.boost.org/LICENSE_1_0.txt) |
8 | |
9 | // For more information, see http://www.boost.org |
10 | |
11 | #include <boost/signals2.hpp> |
12 | #define BOOST_TEST_MODULE deletion_test |
13 | #include <boost/test/included/unit_test.hpp> |
14 | #include <iostream> |
15 | #include <string> |
16 | |
17 | static boost::signals2::connection connections[5]; |
18 | |
19 | static std::string test_output; |
20 | |
21 | struct remove_connection { |
22 | explicit remove_connection(int v = 0, int i = -1) : value(v), idx(i) {} |
23 | |
24 | void operator()() const { |
25 | if (idx >= 0) |
26 | connections[idx].disconnect(); |
27 | |
28 | //return value; |
29 | std::cout << value << " " ; |
30 | |
31 | test_output += static_cast<char>(value + '0'); |
32 | } |
33 | |
34 | int value; |
35 | int idx; |
36 | }; |
37 | |
38 | bool operator==(const remove_connection& x, const remove_connection& y) |
39 | { return x.value == y.value && x.idx == y.idx; } |
40 | |
41 | static void |
42 | test_remove_self() |
43 | { |
44 | boost::signals2::signal<void ()> s0; |
45 | |
46 | connections[0] = s0.connect(slot: remove_connection(0)); |
47 | connections[1] = s0.connect(slot: remove_connection(1)); |
48 | connections[2] = s0.connect(slot: remove_connection(2, 2)); |
49 | connections[3] = s0.connect(slot: remove_connection(3)); |
50 | |
51 | std::cout << "Deleting 2" << std::endl; |
52 | |
53 | test_output = "" ; |
54 | s0(); std::cout << std::endl; |
55 | BOOST_CHECK(test_output == "0123" ); |
56 | |
57 | test_output = "" ; |
58 | s0(); std::cout << std::endl; |
59 | BOOST_CHECK(test_output == "013" ); |
60 | |
61 | s0.disconnect_all_slots(); |
62 | BOOST_CHECK(s0.empty()); |
63 | |
64 | connections[0] = s0.connect(slot: remove_connection(0)); |
65 | connections[1] = s0.connect(slot: remove_connection(1)); |
66 | connections[2] = s0.connect(slot: remove_connection(2)); |
67 | connections[3] = s0.connect(slot: remove_connection(3, 3)); |
68 | |
69 | std::cout << "Deleting 3" << std::endl; |
70 | |
71 | test_output = "" ; |
72 | s0(); std::cout << std::endl; |
73 | BOOST_CHECK(test_output == "0123" ); |
74 | |
75 | test_output = "" ; |
76 | s0(); std::cout << std::endl; |
77 | BOOST_CHECK(test_output == "012" ); |
78 | |
79 | s0.disconnect_all_slots(); |
80 | BOOST_CHECK(s0.num_slots() == 0); |
81 | |
82 | connections[0] = s0.connect(slot: remove_connection(0, 0)); |
83 | connections[1] = s0.connect(slot: remove_connection(1)); |
84 | connections[2] = s0.connect(slot: remove_connection(2)); |
85 | connections[3] = s0.connect(slot: remove_connection(3)); |
86 | |
87 | std::cout << "Deleting 0" << std::endl; |
88 | |
89 | test_output = "" ; |
90 | s0(); std::cout << std::endl; |
91 | BOOST_CHECK(test_output == "0123" ); |
92 | |
93 | test_output = "" ; |
94 | s0(); std::cout << std::endl; |
95 | BOOST_CHECK(test_output == "123" ); |
96 | |
97 | s0.disconnect_all_slots(); |
98 | BOOST_CHECK(s0.empty()); |
99 | |
100 | connections[0] = s0.connect(slot: remove_connection(0, 0)); |
101 | connections[1] = s0.connect(slot: remove_connection(1, 1)); |
102 | connections[2] = s0.connect(slot: remove_connection(2, 2)); |
103 | connections[3] = s0.connect(slot: remove_connection(3, 3)); |
104 | |
105 | std::cout << "Mass suicide" << std::endl; |
106 | |
107 | test_output = "" ; |
108 | s0(); std::cout << std::endl; |
109 | BOOST_CHECK(test_output == "0123" ); |
110 | |
111 | test_output = "" ; |
112 | s0(); std::cout << std::endl; |
113 | BOOST_CHECK(test_output == "" ); |
114 | } |
115 | |
116 | static void |
117 | test_remove_prior() |
118 | { |
119 | boost::signals2::signal<void ()> s0; |
120 | |
121 | connections[0] = s0.connect(slot: remove_connection(0)); |
122 | connections[1] = s0.connect(slot: remove_connection(1, 0)); |
123 | connections[2] = s0.connect(slot: remove_connection(2)); |
124 | connections[3] = s0.connect(slot: remove_connection(3)); |
125 | |
126 | std::cout << "1 removes 0" << std::endl; |
127 | |
128 | test_output = "" ; |
129 | s0(); std::cout << std::endl; |
130 | BOOST_CHECK(test_output == "0123" ); |
131 | |
132 | test_output = "" ; |
133 | s0(); std::cout << std::endl; |
134 | BOOST_CHECK(test_output == "123" ); |
135 | |
136 | s0.disconnect_all_slots(); |
137 | BOOST_CHECK(s0.empty()); |
138 | |
139 | connections[0] = s0.connect(slot: remove_connection(0)); |
140 | connections[1] = s0.connect(slot: remove_connection(1)); |
141 | connections[2] = s0.connect(slot: remove_connection(2)); |
142 | connections[3] = s0.connect(slot: remove_connection(3, 2)); |
143 | |
144 | std::cout << "3 removes 2" << std::endl; |
145 | |
146 | test_output = "" ; |
147 | s0(); std::cout << std::endl; |
148 | BOOST_CHECK(test_output == "0123" ); |
149 | |
150 | test_output = "" ; |
151 | s0(); std::cout << std::endl; |
152 | BOOST_CHECK(test_output == "013" ); |
153 | } |
154 | |
155 | static void |
156 | test_remove_after() |
157 | { |
158 | boost::signals2::signal<void ()> s0; |
159 | |
160 | connections[0] = s0.connect(slot: remove_connection(0, 1)); |
161 | connections[1] = s0.connect(slot: remove_connection(1)); |
162 | connections[2] = s0.connect(slot: remove_connection(2)); |
163 | connections[3] = s0.connect(slot: remove_connection(3)); |
164 | |
165 | std::cout << "0 removes 1" << std::endl; |
166 | |
167 | test_output = "" ; |
168 | s0(); std::cout << std::endl; |
169 | BOOST_CHECK(test_output == "023" ); |
170 | |
171 | test_output = "" ; |
172 | s0(); std::cout << std::endl; |
173 | BOOST_CHECK(test_output == "023" ); |
174 | |
175 | s0.disconnect_all_slots(); |
176 | BOOST_CHECK(s0.empty()); |
177 | |
178 | connections[0] = s0.connect(slot: remove_connection(0)); |
179 | connections[1] = s0.connect(slot: remove_connection(1, 3)); |
180 | connections[2] = s0.connect(slot: remove_connection(2)); |
181 | connections[3] = s0.connect(slot: remove_connection(3)); |
182 | |
183 | std::cout << "1 removes 3" << std::endl; |
184 | |
185 | test_output = "" ; |
186 | s0(); std::cout << std::endl; |
187 | BOOST_CHECK(test_output == "012" ); |
188 | |
189 | test_output = "" ; |
190 | s0(); std::cout << std::endl; |
191 | BOOST_CHECK(test_output == "012" ); |
192 | } |
193 | |
194 | static void |
195 | test_bloodbath() |
196 | { |
197 | boost::signals2::signal<void ()> s0; |
198 | |
199 | connections[0] = s0.connect(slot: remove_connection(0, 1)); |
200 | connections[1] = s0.connect(slot: remove_connection(1, 1)); |
201 | connections[2] = s0.connect(slot: remove_connection(2, 0)); |
202 | connections[3] = s0.connect(slot: remove_connection(3, 2)); |
203 | |
204 | std::cout << "0 removes 1, 2 removes 0, 3 removes 2" << std::endl; |
205 | |
206 | test_output = "" ; |
207 | s0(); std::cout << std::endl; |
208 | BOOST_CHECK(test_output == "023" ); |
209 | |
210 | test_output = "" ; |
211 | s0(); std::cout << std::endl; |
212 | BOOST_CHECK(test_output == "3" ); |
213 | } |
214 | |
215 | static void |
216 | test_disconnect_equal() |
217 | { |
218 | boost::signals2::signal<void ()> s0; |
219 | |
220 | connections[0] = s0.connect(slot: remove_connection(0)); |
221 | connections[1] = s0.connect(slot: remove_connection(1)); |
222 | connections[2] = s0.connect(slot: remove_connection(2)); |
223 | connections[3] = s0.connect(slot: remove_connection(3)); |
224 | |
225 | std::cout << "Deleting 2" << std::endl; |
226 | |
227 | test_output = "" ; |
228 | s0(); std::cout << std::endl; |
229 | BOOST_CHECK(test_output == "0123" ); |
230 | |
231 | #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
232 | connections[2].disconnect(); |
233 | #else |
234 | s0.disconnect(slot: remove_connection(2)); |
235 | #endif |
236 | |
237 | test_output = "" ; |
238 | s0(); std::cout << std::endl; |
239 | BOOST_CHECK(test_output == "013" ); |
240 | } |
241 | |
242 | struct signal_deletion_tester |
243 | { |
244 | public: |
245 | signal_deletion_tester() { |
246 | b_has_run = false; |
247 | sig = new boost::signals2::signal<void(void)>(); |
248 | connection0 = sig->connect(group: 0, slot: boost::bind(f: &signal_deletion_tester::a, a1: this)); |
249 | connection1 = sig->connect(group: 1, slot: boost::bind(f: &signal_deletion_tester::b, a1: this)); |
250 | } |
251 | |
252 | ~signal_deletion_tester() |
253 | { |
254 | if(sig != 0) |
255 | delete sig; |
256 | } |
257 | |
258 | void a() |
259 | { |
260 | if(sig != 0) |
261 | delete sig; |
262 | sig = 0; |
263 | } |
264 | |
265 | void b() |
266 | { |
267 | b_has_run = true; |
268 | } |
269 | |
270 | boost::signals2::signal<void(void)> *sig; |
271 | bool b_has_run; |
272 | boost::signals2::connection connection0; |
273 | boost::signals2::connection connection1; |
274 | }; |
275 | |
276 | // If a signal is deleted mid-invocation, the invocation in progress |
277 | // should complete normally. Once all invocations complete, all |
278 | // slots which were connected to the deleted signal should be in the |
279 | // disconnected state. |
280 | static void test_signal_deletion() |
281 | { |
282 | signal_deletion_tester tester; |
283 | (*tester.sig)(); |
284 | BOOST_CHECK(tester.b_has_run); |
285 | BOOST_CHECK(tester.connection0.connected() == false); |
286 | BOOST_CHECK(tester.connection1.connected() == false); |
287 | } |
288 | |
289 | BOOST_AUTO_TEST_CASE(test_main) |
290 | { |
291 | test_remove_self(); |
292 | test_remove_prior(); |
293 | test_remove_after(); |
294 | test_bloodbath(); |
295 | test_disconnect_equal(); |
296 | test_signal_deletion(); |
297 | } |
298 | |