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