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