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