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
test_main(int,char * [])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
operator ()max_or_default30   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 {
make_intmake_int49   make_int(int n, int cn) : N(n), CN(n) {}
operator ()make_int50   int operator()() { return N; }
operator ()make_int51   int operator()() const { return CN; }
52 
53   int N;
54   int CN;
55 };
56 
57 template<int N>
58 struct make_increasing_int {
make_increasing_intmake_increasing_int59   make_increasing_int() : n(N) {}
60 
operator ()make_increasing_int61   int operator()() const { return n++; }
62 
63   mutable int n;
64 };
65 
get_37()66 int get_37() { return 37; }
67 
68 static void
test_zero_args()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
test_one_arg()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
test_signal_signal_connect()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 {
EventCounterEventCounter188   EventCounter() : count(0) {}
189 
operator ()EventCounter190   void operator()()
191   {
192     ++count;
193   }
194 
195   int count;
196 };
197 
198 static void
test_ref()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 
test_default_combiner()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>
disconnecting_slot(const boost::signals2::connection & conn,int)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<>
disconnecting_slot(const boost::signals2::connection & conn,int)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>
test_extended_slot()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 
dummy_combiner(result_type return_value)294   dummy_combiner(result_type return_value): _return_value(return_value)
295   {}
296   template<typename SlotIterator>
operator ()(SlotIterator,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
test_set_combiner()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
test_swap()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
test_main(int,char * [])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
352