• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Signals library
2 
3 // Copyright Frank Mori Hess 2008-2009.
4 // Copyright Douglas Gregor 2001-2003.
5 //
6 // Use, modification and
7 // distribution is subject to the Boost Software License, Version
8 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 
11 // For more information, see http://www.boost.org
12 
13 #include <boost/bind/bind.hpp>
14 #include <boost/optional.hpp>
15 #include <boost/signals2.hpp>
16 #define BOOST_TEST_MODULE signal_test
17 #include <boost/test/included/unit_test.hpp>
18 #include <functional>
19 #include <iostream>
20 #include <typeinfo>
21 
22 using namespace boost::placeholders;
23 
24 template<typename T>
25 struct max_or_default {
26   typedef T result_type;
27   template<typename InputIterator>
28   typename InputIterator::value_type
operator ()max_or_default29   operator()(InputIterator first, InputIterator last) const
30   {
31     boost::optional<T> max;
32     for (; first != last; ++first)
33     {
34       try
35       {
36         if(!max) max = *first;
37         else max = (*first > max.get())? *first : max;
38       }
39       catch(const boost::bad_weak_ptr &)
40       {}
41     }
42     if(max) return max.get();
43     return T();
44   }
45 };
46 
47 struct make_int {
make_intmake_int48   make_int(int n, int cn) : N(n), CN(cn) {}
49 
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 
66 static void
test_zero_args()67 test_zero_args()
68 {
69   make_int i42(42, 41);
70   make_int i2(2, 1);
71   make_int i72(72, 71);
72   make_int i63(63, 63);
73   make_int i62(62, 61);
74 
75   {
76     boost::signals2::signal<int (), max_or_default<int> > s0;
77 
78     std::cout << "sizeof(signal) = " << sizeof(s0) << std::endl;
79     boost::signals2::connection c2 = s0.connect(i2);
80     boost::signals2::connection c72 = s0.connect(72, i72);
81     boost::signals2::connection c62 = s0.connect(60, i62);
82     boost::signals2::connection c42 = s0.connect(i42);
83 
84     BOOST_CHECK(s0() == 72);
85 
86     s0.disconnect(72);
87     BOOST_CHECK(s0() == 62);
88 
89     c72.disconnect(); // Double-disconnect should be safe
90     BOOST_CHECK(s0() == 62);
91 
92     s0.disconnect(72); // Triple-disconect should be safe
93     BOOST_CHECK(s0() == 62);
94 
95     // Also connect 63 in the same group as 62
96     s0.connect(60, i63);
97     BOOST_CHECK(s0() == 63);
98 
99     // Disconnect all of the 60's
100     s0.disconnect(60);
101     BOOST_CHECK(s0() == 42);
102 
103     c42.disconnect();
104     BOOST_CHECK(s0() == 2);
105 
106     c2.disconnect();
107     BOOST_CHECK(s0() == 0);
108   }
109 
110   {
111     boost::signals2::signal<int (), max_or_default<int> > s0;
112     boost::signals2::connection c2 = s0.connect(i2);
113     boost::signals2::connection c72 = s0.connect(i72);
114     boost::signals2::connection c62 = s0.connect(i62);
115     boost::signals2::connection c42 = s0.connect(i42);
116 
117     const boost::signals2::signal<int (), max_or_default<int> >& cs0 = s0;
118     BOOST_CHECK(cs0() == 72);
119   }
120 
121   {
122     make_increasing_int<7> i7;
123     make_increasing_int<10> i10;
124 
125     boost::signals2::signal<int (), max_or_default<int> > s0;
126     boost::signals2::connection c7 = s0.connect(i7);
127     boost::signals2::connection c10 = s0.connect(i10);
128 
129     BOOST_CHECK(s0() == 10);
130     BOOST_CHECK(s0() == 11);
131   }
132 }
133 
134 static void
test_one_arg()135 test_one_arg()
136 {
137   boost::signals2::signal<int (int value), max_or_default<int> > s1;
138 
139   s1.connect(std::negate<int>());
140   s1.connect(boost::bind(std::multiplies<int>(), 2, _1));
141 
142   BOOST_CHECK(s1(1) == 2);
143   BOOST_CHECK(s1(-1) == 1);
144 }
145 
146 static void
test_signal_signal_connect()147 test_signal_signal_connect()
148 {
149   typedef boost::signals2::signal<int (int value), max_or_default<int> > signal_type;
150   signal_type s1;
151 
152   s1.connect(std::negate<int>());
153 
154   BOOST_CHECK(s1(3) == -3);
155 
156   {
157     signal_type s2;
158     s1.connect(s2);
159     s2.connect(boost::bind(std::multiplies<int>(), 2, _1));
160     s2.connect(boost::bind(std::multiplies<int>(), -3, _1));
161 
162     BOOST_CHECK(s2(-3) == 9);
163     BOOST_CHECK(s1(3) == 6);
164   } // s2 goes out of scope and disconnects
165   BOOST_CHECK(s1(3) == -3);
166 }
167 
168 template<typename ResultType>
disconnecting_slot(const boost::signals2::connection & conn,int)169   ResultType disconnecting_slot(const boost::signals2::connection &conn, int)
170 {
171   conn.disconnect();
172   return ResultType();
173 }
174 
175 #ifdef BOOST_NO_VOID_RETURNS
176 template<>
disconnecting_slot(const boost::signals2::connection & conn,int)177   void disconnecting_slot<void>(const boost::signals2::connection &conn, int)
178 {
179   conn.disconnect();
180   return;
181 }
182 #endif
183 
184 template<typename ResultType>
test_extended_slot()185   void test_extended_slot()
186 {
187   {
188     typedef boost::signals2::signal<ResultType (int)> signal_type;
189     typedef typename signal_type::extended_slot_type slot_type;
190     signal_type sig;
191     // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
192     ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
193     slot_type myslot(fp);
194     sig.connect_extended(myslot);
195     BOOST_CHECK(sig.num_slots() == 1);
196     sig(0);
197     BOOST_CHECK(sig.num_slots() == 0);
198   }
199   { // test 0 arg signal
200     typedef boost::signals2::signal<ResultType ()> signal_type;
201     typedef typename signal_type::extended_slot_type slot_type;
202     signal_type sig;
203     // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
204     ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
205     slot_type myslot(fp, _1, 0);
206     sig.connect_extended(myslot);
207     BOOST_CHECK(sig.num_slots() == 1);
208     sig();
209     BOOST_CHECK(sig.num_slots() == 0);
210   }
211   // test disconnection by slot
212   {
213     typedef boost::signals2::signal<ResultType (int)> signal_type;
214     typedef typename signal_type::extended_slot_type slot_type;
215     signal_type sig;
216     // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
217     ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
218     slot_type myslot(fp);
219     sig.connect_extended(myslot);
220     BOOST_CHECK(sig.num_slots() == 1);
221     sig.disconnect(fp);
222     BOOST_CHECK(sig.num_slots() == 0);
223   }
224 }
225 
increment_arg(int & value)226 void increment_arg(int &value)
227 {
228   ++value;
229 }
230 
231 static void
test_reference_args()232 test_reference_args()
233 {
234   typedef boost::signals2::signal<void (int &)> signal_type;
235   signal_type s1;
236 
237   s1.connect(&increment_arg);
238   int value = 0;
239   s1(value);
240   BOOST_CHECK(value == 1);
241 }
242 
243 static void
test_typedefs_etc()244 test_typedefs_etc()
245 {
246   typedef boost::signals2::signal<int (double, long)> signal_type;
247   typedef signal_type::slot_type slot_type;
248 
249   BOOST_CHECK(typeid(signal_type::slot_result_type) == typeid(int));
250   BOOST_CHECK(typeid(signal_type::result_type) == typeid(boost::optional<int>));
251   BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(double));
252   BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(long));
253   BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(signal_type::first_argument_type));
254   BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(signal_type::second_argument_type));
255   BOOST_CHECK(typeid(signal_type::signature_type) == typeid(int (double, long)));
256   BOOST_CHECK(signal_type::arity == 2);
257 
258   BOOST_CHECK(typeid(slot_type::result_type) == typeid(signal_type::slot_result_type));
259   BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(signal_type::arg<0>::type));
260   BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(signal_type::arg<1>::type));
261   BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(slot_type::first_argument_type));
262   BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(slot_type::second_argument_type));
263   BOOST_CHECK(typeid(slot_type::signature_type) == typeid(signal_type::signature_type));
264   BOOST_CHECK(slot_type::arity == signal_type::arity);
265 
266   typedef boost::signals2::signal<void (short)> unary_signal_type;
267   BOOST_CHECK(typeid(unary_signal_type::slot_result_type) == typeid(void));
268   BOOST_CHECK(typeid(unary_signal_type::argument_type) == typeid(short));
269   BOOST_CHECK(typeid(unary_signal_type::slot_type::argument_type) == typeid(short));
270 }
271 
272 class dummy_combiner
273 {
274 public:
275   typedef int result_type;
276 
dummy_combiner(result_type return_value)277   dummy_combiner(result_type return_value): _return_value(return_value)
278   {}
279   template<typename SlotIterator>
operator ()(SlotIterator,SlotIterator)280   result_type operator()(SlotIterator, SlotIterator)
281   {
282     return _return_value;
283   }
284 private:
285   result_type _return_value;
286 };
287 
288 static void
test_set_combiner()289 test_set_combiner()
290 {
291   typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
292   signal_type sig(dummy_combiner(0));
293   BOOST_CHECK(sig() == 0);
294   BOOST_CHECK(sig.combiner()(0,0) == 0);
295   sig.set_combiner(dummy_combiner(1));
296   BOOST_CHECK(sig() == 1);
297   BOOST_CHECK(sig.combiner()(0,0) == 1);
298 }
299 
300 static void
test_swap()301 test_swap()
302 {
303   typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
304   signal_type sig1(dummy_combiner(1));
305   BOOST_CHECK(sig1() == 1);
306   signal_type sig2(dummy_combiner(2));
307   BOOST_CHECK(sig2() == 2);
308 
309   sig1.swap(sig2);
310   BOOST_CHECK(sig1() == 2);
311   BOOST_CHECK(sig2() == 1);
312 
313   using std::swap;
314   swap(sig1, sig2);
315   BOOST_CHECK(sig1() == 1);
316   BOOST_CHECK(sig2() == 2);
317 }
318 
test_move()319 void test_move()
320 {
321 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
322   typedef boost::signals2::signal<int (), dummy_combiner> signal_type;
323   signal_type sig1(dummy_combiner(1));
324   BOOST_CHECK(sig1() == 1);
325   signal_type sig2(dummy_combiner(2));
326   BOOST_CHECK(sig2() == 2);
327 
328   sig1 = std::move(sig2);
329   BOOST_CHECK(sig1() == 2);
330 
331   signal_type sig3(std::move(sig1));
332   BOOST_CHECK(sig3() == 2);
333 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
334 }
335 
BOOST_AUTO_TEST_CASE(test_main)336 BOOST_AUTO_TEST_CASE(test_main)
337 {
338   test_zero_args();
339   test_one_arg();
340   test_signal_signal_connect();
341   test_extended_slot<void>();
342   test_extended_slot<int>();
343   test_reference_args();
344   test_typedefs_etc();
345   test_set_combiner();
346   test_swap();
347   test_move();
348 }
349