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
15 using namespace boost::placeholders;
16
17 #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
BOOST_AUTO_TEST_CASE(test_main)18 BOOST_AUTO_TEST_CASE(test_main)
19 {
20 }
21 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
22
23 #include <boost/optional.hpp>
24 #include <boost/ref.hpp>
25 #include <boost/signals2.hpp>
26 #include <functional>
27
28 template<typename T>
29 struct max_or_default {
30 typedef T result_type;
31 template<typename InputIterator>
32 typename InputIterator::value_type
operator ()max_or_default33 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
51 struct make_int {
make_intmake_int52 make_int(int n, int cn) : N(n), CN(n) {}
operator ()make_int53 int operator()() { return N; }
operator ()make_int54 int operator()() const { return CN; }
55
56 int N;
57 int CN;
58 };
59
60 template<int N>
61 struct make_increasing_int {
make_increasing_intmake_increasing_int62 make_increasing_int() : n(N) {}
63
operator ()make_increasing_int64 int operator()() const { return n++; }
65
66 mutable int n;
67 };
68
get_37()69 int get_37() { return 37; }
70
71 static void
test_zero_args()72 test_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
141 static void
test_one_arg()142 test_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
153 static void
test_signal_signal_connect()154 test_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
189 struct EventCounter
190 {
EventCounterEventCounter191 EventCounter() : count(0) {}
192
operator ()EventCounter193 void operator()()
194 {
195 ++count;
196 }
197
198 int count;
199 };
200
201 static void
test_ref()202 test_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
test_default_combiner()217 static 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
235 template<typename ResultType>
disconnecting_slot(const boost::signals2::connection & conn,int)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
243 template<>
disconnecting_slot(const boost::signals2::connection & conn,int)244 void disconnecting_slot<void>(const boost::signals2::connection &conn, int)
245 {
246 conn.disconnect();
247 return;
248 }
249 #endif
250
251 template<typename ResultType>
test_extended_slot()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 }
292 class dummy_combiner
293 {
294 public:
295 typedef int result_type;
296
dummy_combiner(result_type return_value)297 dummy_combiner(result_type return_value): _return_value(return_value)
298 {}
299 template<typename SlotIterator>
operator ()(SlotIterator,SlotIterator)300 result_type operator()(SlotIterator, SlotIterator)
301 {
302 return _return_value;
303 }
304 private:
305 result_type _return_value;
306 };
307
308 static void
test_set_combiner()309 test_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
320 static void
test_swap()321 test_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
BOOST_AUTO_TEST_CASE(test_main)339 BOOST_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