signal_n_test.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Boost.Signals library
  2. // Copyright Douglas Gregor 2001-2003. Use, modification and
  3. // distribution is subject to the Boost Software License, Version
  4. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // For more information, see http://www.boost.org
  7. #include <boost/bind.hpp>
  8. #include <boost/config.hpp>
  9. #include <boost/test/minimal.hpp>
  10. #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  11. int test_main(int, char* [])
  12. {
  13. return 0;
  14. }
  15. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  16. #include <boost/optional.hpp>
  17. #include <boost/ref.hpp>
  18. #include <boost/signals2.hpp>
  19. #include <functional>
  20. template<typename T>
  21. struct max_or_default {
  22. typedef T result_type;
  23. template<typename InputIterator>
  24. typename InputIterator::value_type
  25. 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. struct make_int {
  43. make_int(int n, int cn) : N(n), CN(n) {}
  44. int operator()() { return N; }
  45. int operator()() const { return CN; }
  46. int N;
  47. int CN;
  48. };
  49. template<int N>
  50. struct make_increasing_int {
  51. make_increasing_int() : n(N) {}
  52. int operator()() const { return n++; }
  53. mutable int n;
  54. };
  55. int get_37() { return 37; }
  56. static void
  57. test_zero_args()
  58. {
  59. make_int i42(42, 41);
  60. make_int i2(2, 1);
  61. make_int i72(72, 71);
  62. make_int i63(63, 63);
  63. make_int i62(62, 61);
  64. {
  65. boost::signals2::signal0<int, max_or_default<int>, std::string> s0;
  66. boost::signals2::connection c2 = s0.connect(i2);
  67. boost::signals2::connection c72 = s0.connect("72", i72);
  68. boost::signals2::connection c62 = s0.connect("6x", i62);
  69. boost::signals2::connection c42 = s0.connect(i42);
  70. boost::signals2::connection c37 = s0.connect(&get_37);
  71. BOOST_CHECK(s0() == 72);
  72. s0.disconnect("72");
  73. BOOST_CHECK(s0() == 62);
  74. c72.disconnect(); // Double-disconnect should be safe
  75. BOOST_CHECK(s0() == 62);
  76. s0.disconnect("72"); // Triple-disconect should be safe
  77. BOOST_CHECK(s0() == 62);
  78. // Also connect 63 in the same group as 62
  79. s0.connect("6x", i63);
  80. BOOST_CHECK(s0() == 63);
  81. // Disconnect all of the 60's
  82. s0.disconnect("6x");
  83. BOOST_CHECK(s0() == 42);
  84. c42.disconnect();
  85. BOOST_CHECK(s0() == 37);
  86. c37.disconnect();
  87. BOOST_CHECK(s0() == 2);
  88. c2.disconnect();
  89. BOOST_CHECK(s0() == 0);
  90. }
  91. {
  92. boost::signals2::signal0<int, max_or_default<int> > s0;
  93. boost::signals2::connection c2 = s0.connect(i2);
  94. boost::signals2::connection c72 = s0.connect(i72);
  95. boost::signals2::connection c62 = s0.connect(i62);
  96. boost::signals2::connection c42 = s0.connect(i42);
  97. const boost::signals2::signal0<int, max_or_default<int> >& cs0 = s0;
  98. BOOST_CHECK(cs0() == 72);
  99. }
  100. {
  101. make_increasing_int<7> i7;
  102. make_increasing_int<10> i10;
  103. boost::signals2::signal0<int, max_or_default<int> > s0;
  104. boost::signals2::connection c7 = s0.connect(i7);
  105. boost::signals2::connection c10 = s0.connect(i10);
  106. BOOST_CHECK(s0() == 10);
  107. BOOST_CHECK(s0() == 11);
  108. }
  109. }
  110. static void
  111. test_one_arg()
  112. {
  113. boost::signals2::signal1<int, int, max_or_default<int> > s1;
  114. s1.connect(std::negate<int>());
  115. s1.connect(boost::bind(std::multiplies<int>(), 2, _1));
  116. BOOST_CHECK(s1(1) == 2);
  117. BOOST_CHECK(s1(-1) == 1);
  118. }
  119. static void
  120. test_signal_signal_connect()
  121. {
  122. typedef boost::signals2::signal1<int, int, max_or_default<int> > signal_type;
  123. signal_type s1;
  124. s1.connect(std::negate<int>());
  125. BOOST_CHECK(s1(3) == -3);
  126. {
  127. signal_type s2;
  128. s1.connect(s2);
  129. s2.connect(boost::bind(std::multiplies<int>(), 2, _1));
  130. s2.connect(boost::bind(std::multiplies<int>(), -3, _1));
  131. BOOST_CHECK(s2(-3) == 9);
  132. BOOST_CHECK(s1(3) == 6);
  133. } // s2 goes out of scope and disconnects
  134. BOOST_CHECK(s1(3) == -3);
  135. // test auto-track of signal wrapped in a reference_wrapper
  136. {
  137. signal_type s2;
  138. s1.connect(boost::cref(s2));
  139. s2.connect(boost::bind(std::multiplies<int>(), 2, _1));
  140. s2.connect(boost::bind(std::multiplies<int>(), -3, _1));
  141. BOOST_CHECK(s2(-3) == 9);
  142. BOOST_CHECK(s1(3) == 6);
  143. } // s2 goes out of scope and disconnects
  144. BOOST_CHECK(s1(3) == -3);
  145. }
  146. struct EventCounter
  147. {
  148. EventCounter() : count(0) {}
  149. void operator()()
  150. {
  151. ++count;
  152. }
  153. int count;
  154. };
  155. static void
  156. test_ref()
  157. {
  158. EventCounter ec;
  159. boost::signals2::signal0<void> s;
  160. {
  161. boost::signals2::scoped_connection c(s.connect(boost::ref(ec)));
  162. BOOST_CHECK(ec.count == 0);
  163. s();
  164. BOOST_CHECK(ec.count == 1);
  165. }
  166. s();
  167. BOOST_CHECK(ec.count == 1);
  168. }
  169. static void test_default_combiner()
  170. {
  171. boost::signals2::signal0<int> sig;
  172. boost::optional<int> result;
  173. result = sig();
  174. BOOST_CHECK(!result);
  175. sig.connect(make_int(0, 0));
  176. result = sig();
  177. BOOST_CHECK(result);
  178. BOOST_CHECK(*result == 0);
  179. sig.connect(make_int(1, 1));
  180. result = sig();
  181. BOOST_CHECK(result);
  182. BOOST_CHECK(*result == 1);
  183. }
  184. template<typename ResultType>
  185. ResultType disconnecting_slot(const boost::signals2::connection &conn, int)
  186. {
  187. conn.disconnect();
  188. return ResultType();
  189. }
  190. #ifdef BOOST_NO_VOID_RETURNS
  191. template<>
  192. void disconnecting_slot<void>(const boost::signals2::connection &conn, int)
  193. {
  194. conn.disconnect();
  195. return;
  196. }
  197. #endif
  198. template<typename ResultType>
  199. void test_extended_slot()
  200. {
  201. {
  202. typedef boost::signals2::signal1<ResultType, int> signal_type;
  203. typedef typename signal_type::extended_slot_type slot_type;
  204. signal_type sig;
  205. // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
  206. ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
  207. slot_type myslot(fp);
  208. sig.connect_extended(myslot);
  209. BOOST_CHECK(sig.num_slots() == 1);
  210. sig(0);
  211. BOOST_CHECK(sig.num_slots() == 0);
  212. }
  213. { // test 0 arg signal
  214. typedef boost::signals2::signal0<ResultType> signal_type;
  215. typedef typename signal_type::extended_slot_type slot_type;
  216. signal_type sig;
  217. // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
  218. ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
  219. slot_type myslot(fp, _1, 0);
  220. sig.connect_extended(myslot);
  221. BOOST_CHECK(sig.num_slots() == 1);
  222. sig();
  223. BOOST_CHECK(sig.num_slots() == 0);
  224. }
  225. // test disconnection by slot
  226. {
  227. typedef boost::signals2::signal1<ResultType, int> signal_type;
  228. typedef typename signal_type::extended_slot_type slot_type;
  229. signal_type sig;
  230. // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer
  231. ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>;
  232. slot_type myslot(fp);
  233. sig.connect_extended(myslot);
  234. BOOST_CHECK(sig.num_slots() == 1);
  235. sig.disconnect(fp);
  236. BOOST_CHECK(sig.num_slots() == 0);
  237. }
  238. }
  239. class dummy_combiner
  240. {
  241. public:
  242. typedef int result_type;
  243. dummy_combiner(result_type return_value): _return_value(return_value)
  244. {}
  245. template<typename SlotIterator>
  246. result_type operator()(SlotIterator, SlotIterator)
  247. {
  248. return _return_value;
  249. }
  250. private:
  251. result_type _return_value;
  252. };
  253. static void
  254. test_set_combiner()
  255. {
  256. typedef boost::signals2::signal0<int, dummy_combiner> signal_type;
  257. signal_type sig(dummy_combiner(0));
  258. BOOST_CHECK(sig() == 0);
  259. BOOST_CHECK(sig.combiner()(0,0) == 0);
  260. sig.set_combiner(dummy_combiner(1));
  261. BOOST_CHECK(sig() == 1);
  262. BOOST_CHECK(sig.combiner()(0,0) == 1);
  263. }
  264. static void
  265. test_swap()
  266. {
  267. typedef boost::signals2::signal0<int, dummy_combiner> signal_type;
  268. signal_type sig1(dummy_combiner(1));
  269. BOOST_CHECK(sig1() == 1);
  270. signal_type sig2(dummy_combiner(2));
  271. BOOST_CHECK(sig2() == 2);
  272. sig1.swap(sig2);
  273. BOOST_CHECK(sig1() == 2);
  274. BOOST_CHECK(sig2() == 1);
  275. using std::swap;
  276. swap(sig1, sig2);
  277. BOOST_CHECK(sig1() == 1);
  278. BOOST_CHECK(sig2() == 2);
  279. }
  280. int
  281. test_main(int, char* [])
  282. {
  283. test_zero_args();
  284. test_one_arg();
  285. test_signal_signal_connect();
  286. test_ref();
  287. test_default_combiner();
  288. test_extended_slot<void>();
  289. test_extended_slot<int>();
  290. test_set_combiner();
  291. test_swap();
  292. return 0;
  293. }
  294. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES