1 // Boost.Signals library
2
3 // Copyright Frank Mori Hess 2008-2009.
4 // Copyright Douglas Gregor 2001-2003.
5 //
6 // Use, modification and
7 // distribution is subject to the Boost Software License, Version
8 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10
11 // For more information, see http://www.boost.org
12
13 #include <boost/bind/bind.hpp>
14 #include <boost/optional.hpp>
15 #include <boost/signals2.hpp>
16 #define BOOST_TEST_MODULE signal_test
17 #include <boost/test/included/unit_test.hpp>
18 #include <functional>
19 #include <iostream>
20 #include <typeinfo>
21
22 using namespace boost::placeholders;
23
24 template<typename T>
25 struct max_or_default {
26 typedef T result_type;
27 template<typename InputIterator>
28 typename InputIterator::value_type
operator ()max_or_default29 operator()(InputIterator first, InputIterator last) const
30 {
31 boost::optional<T> max;
32 for (; first != last; ++first)
33 {
34 try
35 {
36 if(!max) max = *first;
37 else max = (*first > max.get())? *first : max;
38 }
39 catch(const boost::bad_weak_ptr &)
40 {}
41 }
42 if(max) return max.get();
43 return T();
44 }
45 };
46
47 struct make_int {
make_intmake_int48 make_int(int n, int cn) : N(n), CN(cn) {}
49
operator ()make_int50 int operator()() { return N; }
operator ()make_int51 int operator()() const { return CN; }
52
53 int N;
54 int CN;
55 };
56
57 template<int N>
58 struct make_increasing_int {
make_increasing_intmake_increasing_int59 make_increasing_int() : n(N) {}
60
operator ()make_increasing_int61 int operator()() const { return n++; }
62
63 mutable int n;
64 };
65
66 static void
test_zero_args()67 test_zero_args()
68 {
69 make_int i42(42, 41);
70 make_int i2(2, 1);
71 make_int i72(72, 71);
72 make_int i63(63, 63);
73 make_int i62(62, 61);
74
75 {
76 boost::signals2::signal<int (), max_or_default<int> > s0;
77
78 std::cout << "sizeof(signal) = " << sizeof(s0) << std::endl;
79 boost::signals2::connection c2 = s0.connect(i2);
80 boost::signals2::connection c72 = s0.connect(72, i72);
81 boost::signals2::connection c62 = s0.connect(60, i62);
82 boost::signals2::connection c42 = s0.connect(i42);
83
84 BOOST_CHECK(s0() == 72);
85
86 s0.disconnect(72);
87 BOOST_CHECK(s0() == 62);
88
89 c72.disconnect(); // Double-disconnect should be safe
90 BOOST_CHECK(s0() == 62);
91
92 s0.disconnect(72); // Triple-disconect should be safe
93 BOOST_CHECK(s0() == 62);
94
95 // Also connect 63 in the same group as 62
96 s0.connect(60, i63);
97 BOOST_CHECK(s0() == 63);
98
99 // Disconnect all of the 60's
100 s0.disconnect(60);
101 BOOST_CHECK(s0() == 42);
102
103 c42.disconnect();
104 BOOST_CHECK(s0() == 2);
105
106 c2.disconnect();
107 BOOST_CHECK(s0() == 0);
108 }
109
110 {
111 boost::signals2::signal<int (), max_or_default<int> > s0;
112 boost::signals2::connection c2 = s0.connect(i2);
113 boost::signals2::connection c72 = s0.connect(i72);
114 boost::signals2::connection c62 = s0.connect(i62);
115 boost::signals2::connection c42 = s0.connect(i42);
116
117 const boost::signals2::signal<int (), max_or_default<int> >& cs0 = s0;
118 BOOST_CHECK(cs0() == 72);
119 }
120
121 {
122 make_increasing_int<7> i7;
123 make_increasing_int<10> i10;
124
125 boost::signals2::signal<int (), max_or_default<int> > s0;
126 boost::signals2::connection c7 = s0.connect(i7);
127 boost::signals2::connection c10 = s0.connect(i10);
128
129 BOOST_CHECK(s0() == 10);
130 BOOST_CHECK(s0() == 11);
131 }
132 }
133
134 static void
test_one_arg()135 test_one_arg()
136 {
137 boost::signals2::signal<int (int value), max_or_default<int> > s1;
138
139 s1.connect(std::negate<int>());
140 s1.connect(boost::bind(std::multiplies<int>(), 2, _1));
141
142 BOOST_CHECK(s1(1) == 2);
143 BOOST_CHECK(s1(-1) == 1);
144 }
145
146 static void
test_signal_signal_connect()147 test_signal_signal_connect()
148 {
149 typedef boost::signals2::signal<int (int value), max_or_default<int> > signal_type;
150 signal_type s1;
151
152 s1.connect(std::negate<int>());
153
154 BOOST_CHECK(s1(3) == -3);
155
156 {
157 signal_type s2;
158 s1.connect(s2);
159 s2.connect(boost::bind(std::multiplies<int>(), 2, _1));
160 s2.connect(boost::bind(std::multiplies<int>(), -3, _1));
161
162 BOOST_CHECK(s2(-3) == 9);
163 BOOST_CHECK(s1(3) == 6);
164 } // s2 goes out of scope and disconnects
165 BOOST_CHECK(s1(3) == -3);
166 }
167
168 template<typename ResultType>
disconnecting_slot(const boost::signals2::connection & conn,int)169 ResultType disconnecting_slot(const boost::signals2::connection &conn, int)
170 {
171 conn.disconnect();
172 return ResultType();
173 }
174
175 #ifdef BOOST_NO_VOID_RETURNS
176 template<>
disconnecting_slot(const boost::signals2::connection & conn,int)177 void disconnecting_slot<void>(const boost::signals2::connection &conn, int)
178 {
179 conn.disconnect();
180 return;
181 }
182 #endif
183
184 template<typename ResultType>
test_extended_slot()185 void test_extended_slot()
186 {
187 {
188 typedef boost::signals2::signal<ResultType (int)> signal_type;
189 typedef typename signal_type::extended_slot_type slot_type;
190 signal_type sig;
191 // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
192 ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
193 slot_type myslot(fp);
194 sig.connect_extended(myslot);
195 BOOST_CHECK(sig.num_slots() == 1);
196 sig(0);
197 BOOST_CHECK(sig.num_slots() == 0);
198 }
199 { // test 0 arg signal
200 typedef boost::signals2::signal<ResultType ()> signal_type;
201 typedef typename signal_type::extended_slot_type slot_type;
202 signal_type sig;
203 // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
204 ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
205 slot_type myslot(fp, _1, 0);
206 sig.connect_extended(myslot);
207 BOOST_CHECK(sig.num_slots() == 1);
208 sig();
209 BOOST_CHECK(sig.num_slots() == 0);
210 }
211 // test disconnection by slot
212 {
213 typedef boost::signals2::signal<ResultType (int)> signal_type;
214 typedef typename signal_type::extended_slot_type slot_type;
215 signal_type sig;
216 // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
217 ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
218 slot_type myslot(fp);
219 sig.connect_extended(myslot);
220 BOOST_CHECK(sig.num_slots() == 1);
221 sig.disconnect(fp);
222 BOOST_CHECK(sig.num_slots() == 0);
223 }
224 }
225
increment_arg(int & value)226 void increment_arg(int &value)
227 {
228 ++value;
229 }
230
231 static void
test_reference_args()232 test_reference_args()
233 {
234 typedef boost::signals2::signal<void (int &)> signal_type;
235 signal_type s1;
236
237 s1.connect(&increment_arg);
238 int value = 0;
239 s1(value);
240 BOOST_CHECK(value == 1);
241 }
242
243 static void
test_typedefs_etc()244 test_typedefs_etc()
245 {
246 typedef boost::signals2::signal<int (double, long)> signal_type;
247 typedef signal_type::slot_type slot_type;
248
249 BOOST_CHECK(typeid(signal_type::slot_result_type) == typeid(int));
250 BOOST_CHECK(typeid(signal_type::result_type) == typeid(boost::optional<int>));
251 BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(double));
252 BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(long));
253 BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(signal_type::first_argument_type));
254 BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(signal_type::second_argument_type));
255 BOOST_CHECK(typeid(signal_type::signature_type) == typeid(int (double, long)));
256 BOOST_CHECK(signal_type::arity == 2);
257
258 BOOST_CHECK(typeid(slot_type::result_type) == typeid(signal_type::slot_result_type));
259 BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(signal_type::arg<0>::type));
260 BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(signal_type::arg<1>::type));
261 BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(slot_type::first_argument_type));
262 BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(slot_type::second_argument_type));
263 BOOST_CHECK(typeid(slot_type::signature_type) == typeid(signal_type::signature_type));
264 BOOST_CHECK(slot_type::arity == signal_type::arity);
265
266 typedef boost::signals2::signal<void (short)> unary_signal_type;
267 BOOST_CHECK(typeid(unary_signal_type::slot_result_type) == typeid(void));
268 BOOST_CHECK(typeid(unary_signal_type::argument_type) == typeid(short));
269 BOOST_CHECK(typeid(unary_signal_type::slot_type::argument_type) == typeid(short));
270 }
271
272 class dummy_combiner
273 {
274 public:
275 typedef int result_type;
276
dummy_combiner(result_type return_value)277 dummy_combiner(result_type return_value): _return_value(return_value)
278 {}
279 template<typename SlotIterator>
operator ()(SlotIterator,SlotIterator)280 result_type operator()(SlotIterator, SlotIterator)
281 {
282 return _return_value;
283 }
284 private:
285 result_type _return_value;
286 };
287
288 static void
test_set_combiner()289 test_set_combiner()
290 {
291 typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
292 signal_type sig(dummy_combiner(0));
293 BOOST_CHECK(sig() == 0);
294 BOOST_CHECK(sig.combiner()(0,0) == 0);
295 sig.set_combiner(dummy_combiner(1));
296 BOOST_CHECK(sig() == 1);
297 BOOST_CHECK(sig.combiner()(0,0) == 1);
298 }
299
300 static void
test_swap()301 test_swap()
302 {
303 typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
304 signal_type sig1(dummy_combiner(1));
305 BOOST_CHECK(sig1() == 1);
306 signal_type sig2(dummy_combiner(2));
307 BOOST_CHECK(sig2() == 2);
308
309 sig1.swap(sig2);
310 BOOST_CHECK(sig1() == 2);
311 BOOST_CHECK(sig2() == 1);
312
313 using std::swap;
314 swap(sig1, sig2);
315 BOOST_CHECK(sig1() == 1);
316 BOOST_CHECK(sig2() == 2);
317 }
318
test_move()319 void test_move()
320 {
321 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
322 typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
323 signal_type sig1(dummy_combiner(1));
324 BOOST_CHECK(sig1() == 1);
325 signal_type sig2(dummy_combiner(2));
326 BOOST_CHECK(sig2() == 2);
327
328 sig1 = std::move(sig2);
329 BOOST_CHECK(sig1() == 2);
330
331 signal_type sig3(std::move(sig1));
332 BOOST_CHECK(sig3() == 2);
333 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
334 }
335
BOOST_AUTO_TEST_CASE(test_main)336 BOOST_AUTO_TEST_CASE(test_main)
337 {
338 test_zero_args();
339 test_one_arg();
340 test_signal_signal_connect();
341 test_extended_slot<void>();
342 test_extended_slot<int>();
343 test_reference_args();
344 test_typedefs_etc();
345 test_set_combiner();
346 test_swap();
347 test_move();
348 }
349