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

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