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