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 {
remove_connectionremove_connection22 explicit remove_connection(int v = 0, int i = -1) : value(v), idx(i) {}
23
operator ()remove_connection24 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
operator ==(const remove_connection & x,const remove_connection & y)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
test_remove_self()42 test_remove_self()
43 {
44 boost::signals2::signal<void ()> s0;
45
46 connections[0] = s0.connect(remove_connection(0));
47 connections[1] = s0.connect(remove_connection(1));
48 connections[2] = s0.connect(remove_connection(2, 2));
49 connections[3] = s0.connect(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(remove_connection(0));
65 connections[1] = s0.connect(remove_connection(1));
66 connections[2] = s0.connect(remove_connection(2));
67 connections[3] = s0.connect(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(remove_connection(0, 0));
83 connections[1] = s0.connect(remove_connection(1));
84 connections[2] = s0.connect(remove_connection(2));
85 connections[3] = s0.connect(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(remove_connection(0, 0));
101 connections[1] = s0.connect(remove_connection(1, 1));
102 connections[2] = s0.connect(remove_connection(2, 2));
103 connections[3] = s0.connect(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
test_remove_prior()117 test_remove_prior()
118 {
119 boost::signals2::signal<void ()> s0;
120
121 connections[0] = s0.connect(remove_connection(0));
122 connections[1] = s0.connect(remove_connection(1, 0));
123 connections[2] = s0.connect(remove_connection(2));
124 connections[3] = s0.connect(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(remove_connection(0));
140 connections[1] = s0.connect(remove_connection(1));
141 connections[2] = s0.connect(remove_connection(2));
142 connections[3] = s0.connect(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
test_remove_after()156 test_remove_after()
157 {
158 boost::signals2::signal<void ()> s0;
159
160 connections[0] = s0.connect(remove_connection(0, 1));
161 connections[1] = s0.connect(remove_connection(1));
162 connections[2] = s0.connect(remove_connection(2));
163 connections[3] = s0.connect(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(remove_connection(0));
179 connections[1] = s0.connect(remove_connection(1, 3));
180 connections[2] = s0.connect(remove_connection(2));
181 connections[3] = s0.connect(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
test_bloodbath()195 test_bloodbath()
196 {
197 boost::signals2::signal<void ()> s0;
198
199 connections[0] = s0.connect(remove_connection(0, 1));
200 connections[1] = s0.connect(remove_connection(1, 1));
201 connections[2] = s0.connect(remove_connection(2, 0));
202 connections[3] = s0.connect(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
test_disconnect_equal()216 test_disconnect_equal()
217 {
218 boost::signals2::signal<void ()> s0;
219
220 connections[0] = s0.connect(remove_connection(0));
221 connections[1] = s0.connect(remove_connection(1));
222 connections[2] = s0.connect(remove_connection(2));
223 connections[3] = s0.connect(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(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:
signal_deletion_testersignal_deletion_tester245 signal_deletion_tester() {
246 b_has_run = false;
247 sig = new boost::signals2::signal<void(void)>();
248 connection0 = sig->connect(0, boost::bind(&signal_deletion_tester::a, this));
249 connection1 = sig->connect(1, boost::bind(&signal_deletion_tester::b, this));
250 }
251
~signal_deletion_testersignal_deletion_tester252 ~signal_deletion_tester()
253 {
254 if(sig != 0)
255 delete sig;
256 }
257
asignal_deletion_tester258 void a()
259 {
260 if(sig != 0)
261 delete sig;
262 sig = 0;
263 }
264
bsignal_deletion_tester265 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.
test_signal_deletion()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
BOOST_AUTO_TEST_CASE(test_main)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