signal_test.cpp 9.2 KB

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