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.hpp>
11 #include <boost/config.hpp>
12 #include <boost/test/minimal.hpp>
13 
14 #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
test_main(int,char * [])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
operator ()max_or_default31   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 {
make_intmake_int50   make_int(int n, int cn) : N(n), CN(n) {}
operator ()make_int51   int operator()() { return N; }
operator ()make_int52   int operator()() const { return CN; }
53 
54   int N;
55   int CN;
56 };
57 
58 template<int N>
59 struct make_increasing_int {
make_increasing_intmake_increasing_int60   make_increasing_int() : n(N) {}
61 
operator ()make_increasing_int62   int operator()() const { return n++; }
63 
64   mutable int n;
65 };
66 
get_37()67 int get_37() { return 37; }
68 
69 static void
test_zero_args()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
test_one_arg()140 test_one_arg()
141 {
142   boost::signals2::signal1<int, int, max_or_default<int> > s1;
143 
144   s1.connect(std::negate<int>());
145   s1.connect(boost::bind(std::multiplies<int>(), 2, _1));
146 
147   BOOST_CHECK(s1(1) == 2);
148   BOOST_CHECK(s1(-1) == 1);
149 }
150 
151 static void
test_signal_signal_connect()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);
164     s2.connect(boost::bind(std::multiplies<int>(), 2, _1));
165     s2.connect(boost::bind(std::multiplies<int>(), -3, _1));
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));
177     s2.connect(boost::bind(std::multiplies<int>(), 2, _1));
178     s2.connect(boost::bind(std::multiplies<int>(), -3, _1));
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 {
EventCounterEventCounter189   EventCounter() : count(0) {}
190 
operator ()EventCounter191   void operator()()
192   {
193     ++count;
194   }
195 
196   int count;
197 };
198 
199 static void
test_ref()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 
test_default_combiner()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>
disconnecting_slot(const boost::signals2::connection & conn,int)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<>
disconnecting_slot(const boost::signals2::connection & conn,int)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>
test_extended_slot()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 
dummy_combiner(result_type return_value)295   dummy_combiner(result_type return_value): _return_value(return_value)
296   {}
297   template<typename SlotIterator>
operator ()(SlotIterator,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
test_set_combiner()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
test_swap()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
test_main(int,char * [])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
353