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