• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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