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 |
18 | BOOST_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 | |
28 | template<typename T> |
29 | struct 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 | |
51 | struct 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 | |
60 | template<int N> |
61 | struct make_increasing_int { |
62 | make_increasing_int() : n(N) {} |
63 | |
64 | int operator()() const { return n++; } |
65 | |
66 | mutable int n; |
67 | }; |
68 | |
69 | int get_37() { return 37; } |
70 | |
71 | static void |
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 |
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 |
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 | { |
191 | EventCounter() : count(0) {} |
192 | |
193 | void operator()() |
194 | { |
195 | ++count; |
196 | } |
197 | |
198 | int count; |
199 | }; |
200 | |
201 | static void |
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 | |
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> |
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<> |
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> |
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 | |
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 | } |
304 | private: |
305 | result_type _return_value; |
306 | }; |
307 | |
308 | static void |
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 |
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 | |
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 | |