Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / signals2 / test / signal_n_test.cpp
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