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
22using namespace boost::placeholders;
23
24template<typename T>
25struct max_or_default {
26 typedef T result_type;
27 template<typename InputIterator>
28 typename InputIterator::value_type
29 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
47struct make_int {
48 make_int(int n, int cn) : N(n), CN(cn) {}
49
50 int operator()() { return N; }
51 int operator()() const { return CN; }
52
53 int N;
54 int CN;
55};
56
57template<int N>
58struct make_increasing_int {
59 make_increasing_int() : n(N) {}
60
61 int operator()() const { return n++; }
62
63 mutable int n;
64};
65
66static void
67test_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(slot: i2);
80 boost::signals2::connection c72 = s0.connect(group: 72, slot: i72);
81 boost::signals2::connection c62 = s0.connect(group: 60, slot: i62);
82 boost::signals2::connection c42 = s0.connect(slot: i42);
83
84 BOOST_CHECK(s0() == 72);
85
86 s0.disconnect(group: 72);
87 BOOST_CHECK(s0() == 62);
88
89 c72.disconnect(); // Double-disconnect should be safe
90 BOOST_CHECK(s0() == 62);
91
92 s0.disconnect(group: 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(group: 60, slot: i63);
97 BOOST_CHECK(s0() == 63);
98
99 // Disconnect all of the 60's
100 s0.disconnect(group: 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(slot: i2);
113 boost::signals2::connection c72 = s0.connect(slot: i72);
114 boost::signals2::connection c62 = s0.connect(slot: i62);
115 boost::signals2::connection c42 = s0.connect(slot: 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(slot: i7);
127 boost::signals2::connection c10 = s0.connect(slot: i10);
128
129 BOOST_CHECK(s0() == 10);
130 BOOST_CHECK(s0() == 11);
131 }
132}
133
134static void
135test_one_arg()
136{
137 boost::signals2::signal<int (int value), max_or_default<int> > s1;
138
139 s1.connect(slot: std::negate<int>());
140 s1.connect(slot: boost::bind(f: std::multiplies<int>(), a: 2, a: _1));
141
142 BOOST_CHECK(s1(1) == 2);
143 BOOST_CHECK(s1(-1) == 1);
144}
145
146static void
147test_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(slot: std::negate<int>());
153
154 BOOST_CHECK(s1(3) == -3);
155
156 {
157 signal_type s2;
158 s1.connect(slot: s2);
159 s2.connect(slot: boost::bind(f: std::multiplies<int>(), a: 2, a: _1));
160 s2.connect(slot: boost::bind(f: std::multiplies<int>(), a: -3, a: _1));
161
162 BOOST_CHECK(s2(-3) == 9);
163 BOOST_CHECK(s1(3) == 6);
164
165 // disconnect by slot
166 s1.disconnect(slot: s2);
167 BOOST_CHECK(s1(3) == -3);
168
169 // disconnect by reference wrapped slot
170 s1.connect(slot: s2);
171 BOOST_CHECK(s1(3) == 6);
172 s1.disconnect(slot: boost::ref(t&: s2));
173 BOOST_CHECK(s1(3) == -3);
174
175 // reconnect s2 to test auto-disconnect on destruction
176 s1.connect(slot: s2);
177 BOOST_CHECK(s1(3) == 6);
178 } // s2 goes out of scope and disconnects
179 BOOST_CHECK(s1(3) == -3);
180}
181
182template<typename ResultType>
183 ResultType disconnecting_slot(const boost::signals2::connection &conn, int)
184{
185 conn.disconnect();
186 return ResultType();
187}
188
189#ifdef BOOST_NO_VOID_RETURNS
190template<>
191 void disconnecting_slot<void>(const boost::signals2::connection &conn, int)
192{
193 conn.disconnect();
194 return;
195}
196#endif
197
198template<typename ResultType>
199 void test_extended_slot()
200{
201 {
202 typedef boost::signals2::signal<ResultType (int)> signal_type;
203 typedef typename signal_type::extended_slot_type slot_type;
204 signal_type sig;
205 // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
206 ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
207 slot_type myslot(fp);
208 sig.connect_extended(myslot);
209 BOOST_CHECK(sig.num_slots() == 1);
210 sig(0);
211 BOOST_CHECK(sig.num_slots() == 0);
212 }
213 { // test 0 arg signal
214 typedef boost::signals2::signal<ResultType ()> signal_type;
215 typedef typename signal_type::extended_slot_type slot_type;
216 signal_type sig;
217 // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
218 ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
219 slot_type myslot(fp, _1, 0);
220 sig.connect_extended(myslot);
221 BOOST_CHECK(sig.num_slots() == 1);
222 sig();
223 BOOST_CHECK(sig.num_slots() == 0);
224 }
225 // test disconnection by slot
226 {
227 typedef boost::signals2::signal<ResultType (int)> signal_type;
228 typedef typename signal_type::extended_slot_type slot_type;
229 signal_type sig;
230 // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
231 ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
232 slot_type myslot(fp);
233 sig.connect_extended(myslot);
234 BOOST_CHECK(sig.num_slots() == 1);
235 sig.disconnect(fp);
236 BOOST_CHECK(sig.num_slots() == 0);
237 }
238}
239
240void increment_arg(int &value)
241{
242 ++value;
243}
244
245static void
246test_reference_args()
247{
248 typedef boost::signals2::signal<void (int &)> signal_type;
249 signal_type s1;
250
251 s1.connect(slot: &increment_arg);
252 int value = 0;
253 s1(value);
254 BOOST_CHECK(value == 1);
255}
256
257static void
258test_typedefs_etc()
259{
260 typedef boost::signals2::signal<int (double, long)> signal_type;
261 typedef signal_type::slot_type slot_type;
262
263 BOOST_CHECK(typeid(signal_type::slot_result_type) == typeid(int));
264 BOOST_CHECK(typeid(signal_type::result_type) == typeid(boost::optional<int>));
265 BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(double));
266 BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(long));
267 BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(signal_type::first_argument_type));
268 BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(signal_type::second_argument_type));
269 BOOST_CHECK(typeid(signal_type::signature_type) == typeid(int (double, long)));
270 BOOST_CHECK(signal_type::arity == 2);
271
272 BOOST_CHECK(typeid(slot_type::result_type) == typeid(signal_type::slot_result_type));
273 BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(signal_type::arg<0>::type));
274 BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(signal_type::arg<1>::type));
275 BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(slot_type::first_argument_type));
276 BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(slot_type::second_argument_type));
277 BOOST_CHECK(typeid(slot_type::signature_type) == typeid(signal_type::signature_type));
278 BOOST_CHECK(slot_type::arity == signal_type::arity);
279
280 typedef boost::signals2::signal<void (short)> unary_signal_type;
281 BOOST_CHECK(typeid(unary_signal_type::slot_result_type) == typeid(void));
282 BOOST_CHECK(typeid(unary_signal_type::argument_type) == typeid(short));
283 BOOST_CHECK(typeid(unary_signal_type::slot_type::argument_type) == typeid(short));
284}
285
286class dummy_combiner
287{
288public:
289 typedef int result_type;
290
291 dummy_combiner(result_type return_value): _return_value(return_value)
292 {}
293 template<typename SlotIterator>
294 result_type operator()(SlotIterator, SlotIterator)
295 {
296 return _return_value;
297 }
298private:
299 result_type _return_value;
300};
301
302static void
303test_set_combiner()
304{
305 typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
306 signal_type sig(dummy_combiner(0));
307 BOOST_CHECK(sig() == 0);
308 BOOST_CHECK(sig.combiner()(0,0) == 0);
309 sig.set_combiner(dummy_combiner(1));
310 BOOST_CHECK(sig() == 1);
311 BOOST_CHECK(sig.combiner()(0,0) == 1);
312}
313
314static void
315test_swap()
316{
317 typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
318 signal_type sig1(dummy_combiner(1));
319 BOOST_CHECK(sig1() == 1);
320 signal_type sig2(dummy_combiner(2));
321 BOOST_CHECK(sig2() == 2);
322
323 sig1.swap(other&: sig2);
324 BOOST_CHECK(sig1() == 2);
325 BOOST_CHECK(sig2() == 1);
326
327 using std::swap;
328 swap(sig1, sig2);
329 BOOST_CHECK(sig1() == 1);
330 BOOST_CHECK(sig2() == 2);
331}
332
333void test_move()
334{
335#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
336 typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
337 signal_type sig1(dummy_combiner(1));
338 BOOST_CHECK(sig1() == 1);
339 signal_type sig2(dummy_combiner(2));
340 BOOST_CHECK(sig2() == 2);
341
342 sig1 = std::move(sig2);
343 BOOST_CHECK(sig1() == 2);
344
345 signal_type sig3(std::move(sig1));
346 BOOST_CHECK(sig3() == 2);
347#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
348}
349
350BOOST_AUTO_TEST_CASE(test_main)
351{
352 test_zero_args();
353 test_one_arg();
354 test_signal_signal_connect();
355 test_extended_slot<void>();
356 test_extended_slot<int>();
357 test_reference_args();
358 test_typedefs_etc();
359 test_set_combiner();
360 test_swap();
361 test_move();
362}
363

source code of boost/libs/signals2/test/signal_test.cpp