diff options
Diffstat (limited to '')
18 files changed, 2644 insertions, 0 deletions
diff --git a/src/boost/libs/signals2/test/Jamfile.v2 b/src/boost/libs/signals2/test/Jamfile.v2 new file mode 100644 index 000000000..aacb3a4ce --- /dev/null +++ b/src/boost/libs/signals2/test/Jamfile.v2 @@ -0,0 +1,51 @@ +# Boost.Signals2 Library + +# Copyright Douglas Gregor 2001-2003. +# Copyright Frank Mori Hess 2009. +# Use, modification and +# distribution is subject to the Boost Software License, Version +# 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# For more information, see http://www.boost.org + +# bring in rules for testing +import testing ; + +project + : source-location . + : requirements + <hardcode-dll-paths>true +# <library>/boost/test//boost_unit_test_framework +# <link>static + ; + +rule thread-run ( sources ) +{ + return + [ run $(sources) : : : <library>/boost/thread//boost_thread/ + <threading>multi ] + ; +} + +{ + test-suite signals2 + : + [ run connection_test.cpp ] + [ run dead_slot_test.cpp ] + [ run deadlock_regression_test.cpp ] + [ run deconstruct_test.cpp ] + [ run deletion_test.cpp ] + [ thread-run mutex_test.cpp ] + [ run ordering_test.cpp ] + [ run regression_test.cpp ] + [ run shared_connection_block_test.cpp ] + [ run signal_n_test.cpp ] + [ run signal_test.cpp ] + [ run signal_type_test.cpp ] + [ run slot_compile_test.cpp ] + [ thread-run threading_models_test.cpp ] + [ run trackable_test.cpp ] + [ run track_test.cpp ] + ; +} diff --git a/src/boost/libs/signals2/test/connection_test.cpp b/src/boost/libs/signals2/test/connection_test.cpp new file mode 100644 index 000000000..bfe0894bc --- /dev/null +++ b/src/boost/libs/signals2/test/connection_test.cpp @@ -0,0 +1,130 @@ +// Signals2 library +// tests for connection class + +// Copyright Frank Mori Hess 2008 +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE connection_test +#include <boost/test/included/unit_test.hpp> + +namespace bs2 = boost::signals2; + +typedef bs2::signal<void ()> sig_type; + +void myslot() +{} + +void swap_test() +{ + sig_type sig; + + { + bs2::connection conn1 = sig.connect(&myslot); + BOOST_CHECK(conn1.connected()); + bs2::connection conn2; + BOOST_CHECK(conn2.connected() == false); + + conn1.swap(conn2); + BOOST_CHECK(conn2.connected()); + BOOST_CHECK(conn1.connected() == false); + + swap(conn1, conn2); + BOOST_CHECK(conn1.connected()); + BOOST_CHECK(conn2.connected() == false); + } + + { + bs2::scoped_connection conn1; + conn1 = sig.connect(&myslot); + BOOST_CHECK(conn1.connected()); + bs2::scoped_connection conn2; + BOOST_CHECK(conn2.connected() == false); + + conn1.swap(conn2); + BOOST_CHECK(conn2.connected()); + BOOST_CHECK(conn1.connected() == false); + + swap(conn1, conn2); + BOOST_CHECK(conn1.connected()); + BOOST_CHECK(conn2.connected() == false); + } +} + +void release_test() +{ + sig_type sig; + bs2::connection conn; + { + bs2::scoped_connection scoped(sig.connect(&myslot)); + BOOST_CHECK(scoped.connected()); + conn = scoped.release(); + } + BOOST_CHECK(conn.connected()); + + bs2::connection conn2; + { + bs2::scoped_connection scoped(conn); + BOOST_CHECK(scoped.connected()); + conn = scoped.release(); + BOOST_CHECK(conn.connected()); + BOOST_CHECK(scoped.connected() == false); + conn.disconnect(); + + // earlier release shouldn't affect new connection + conn2 = sig.connect(&myslot); + scoped = conn2; + } + BOOST_CHECK(conn2.connected() == false); +} + +void move_test() +{ +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + sig_type sig; + bs2::connection conn; + // test move assignment from scoped_connection to connection + { + bs2::scoped_connection scoped(sig.connect(&myslot)); + BOOST_CHECK(scoped.connected()); + conn = std::move(scoped); + BOOST_CHECK(scoped.connected() == false); + } + BOOST_CHECK(conn.connected()); + + // test move construction from scoped to scoped + { + bs2::scoped_connection scoped2(conn); + BOOST_CHECK(scoped2.connected()); + bs2::scoped_connection scoped3(std::move(scoped2)); + BOOST_CHECK(scoped2.connected() == false); + BOOST_CHECK(scoped3.connected() == true); + BOOST_CHECK(conn.connected() == true); + } + BOOST_CHECK(conn.connected() == false); + + // test move assignment from scoped to scoped + conn = sig.connect(&myslot); + { + bs2::scoped_connection scoped3; + bs2::scoped_connection scoped2(conn); + BOOST_CHECK(scoped2.connected()); + scoped3 = std::move(scoped2); + BOOST_CHECK(scoped2.connected() == false); + BOOST_CHECK(scoped3.connected() == true); + BOOST_CHECK(conn.connected() == true); + } + BOOST_CHECK(conn.connected() == false); +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + release_test(); + swap_test(); + move_test(); +} diff --git a/src/boost/libs/signals2/test/dead_slot_test.cpp b/src/boost/libs/signals2/test/dead_slot_test.cpp new file mode 100644 index 000000000..b1ec1d5a0 --- /dev/null +++ b/src/boost/libs/signals2/test/dead_slot_test.cpp @@ -0,0 +1,47 @@ +// Boost.Signals library + +// Copyright (C) Douglas Gregor 2001-2006. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE dead_slot_test +#include <boost/test/included/unit_test.hpp> + +using namespace boost::placeholders; + +typedef boost::signals2::signal<int (int)> sig_type; + +class with_constant { +public: + with_constant(int c) : constant(c) {} + + int add(int i) { return i + constant; } + +private: + int constant; +}; + +void do_delayed_connect(boost::shared_ptr<with_constant> &wc, + sig_type& sig, + sig_type::slot_type slot) +{ + // Should invalidate the slot, so that we cannot connect to it + wc.reset(); + + boost::signals2::connection c = sig.connect(slot); + BOOST_CHECK(!c.connected()); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + sig_type s1; + boost::shared_ptr<with_constant> wc1(new with_constant(7)); + + do_delayed_connect(wc1, s1, sig_type::slot_type(&with_constant::add, wc1.get(), _1).track(wc1)); +} diff --git a/src/boost/libs/signals2/test/deadlock_regression_test.cpp b/src/boost/libs/signals2/test/deadlock_regression_test.cpp new file mode 100644 index 000000000..ac9d89190 --- /dev/null +++ b/src/boost/libs/signals2/test/deadlock_regression_test.cpp @@ -0,0 +1,109 @@ +// Signals2 library +// +// Regression test based on bug report from Arian Alin Radu. +// The problem was that tracked objects could be released +// while holding the signal mutex during signal invocation. +// This could result in a recursive +// lock attempt if the tracked object manipulates the signal +// in its destructor. + +// Copyright Frank Mori Hess 2019 +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#define BOOST_TEST_MODULE signals2 deadlock regression test +#include <boost/test/included/unit_test.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> +#include <boost/signals2/signal.hpp> +#include <boost/signals2/signal_type.hpp> + +namespace bs2 = boost::signals2; + + +// dummy mutex that detects attempts to recursively lock +class test_mutex +{ +public: + test_mutex(): m_locked(false) {} + void lock() + { + BOOST_CHECK(m_locked == false); + m_locked = true; + } + bool try_lock() + { + if(m_locked) return false; + lock(); + return true; + } + void unlock() + { + m_locked = false; + } +private: + bool m_locked; +}; + +using namespace bs2::keywords; +typedef bs2::signal_type<void(), mutex_type<test_mutex> >::type Signal; + +class SelfReference: private boost::noncopyable +{ +public: + boost::shared_ptr<SelfReference> m_self; + boost::shared_ptr<Signal> m_signal; + + boost::signals2::connection m_conReleaseSelf; + boost::signals2::connection m_conDoNothing; + + SelfReference() + { + m_signal = boost::make_shared<Signal>(); + } + + ~SelfReference() + { + // the first slot (ReleaseSelf) has been called; now the trackable object (this) + // was released, while the second slot is locked + BOOST_CHECK(!m_conReleaseSelf.connected()); + // the second slot is locked, and we enter a recursive (pthread: dead) lock + BOOST_CHECK(m_conDoNothing.connected()); + m_conReleaseSelf.disconnect(); + m_conDoNothing.disconnect(); + // enter recursive (pthread: dead) lock again: + BOOST_CHECK(m_signal->empty()); + } + + void ReleaseSelf() + { + m_self.reset(); + } + + static void DoNothing() + { + } + + static void Run() + { + boost::shared_ptr<Signal> signal; + { + boost::shared_ptr<SelfReference> obj = boost::make_shared<SelfReference>(); + obj->m_self = obj; + signal = obj->m_signal; + + obj->m_conReleaseSelf = signal->connect(Signal::slot_type(&SelfReference::ReleaseSelf, obj.get()).track(obj)); + obj->m_conDoNothing = signal->connect(Signal::slot_type(&SelfReference::DoNothing)); + } + (*signal)(); + } +}; + +BOOST_AUTO_TEST_CASE(test_main) +{ + SelfReference::Run(); +} diff --git a/src/boost/libs/signals2/test/deconstruct_test.cpp b/src/boost/libs/signals2/test/deconstruct_test.cpp new file mode 100644 index 000000000..96d9949e4 --- /dev/null +++ b/src/boost/libs/signals2/test/deconstruct_test.cpp @@ -0,0 +1,174 @@ +// Tests for boost::signals2::deconstruct_ptr and friends + +// Copyright Frank Mori Hess 2007-2008. +// Distributed under the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/signals2 for library home page. + +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signals2/deconstruct.hpp> +#include <boost/signals2/deconstruct_ptr.hpp> +#define BOOST_TEST_MODULE deconstruct_test +#include <boost/test/included/unit_test.hpp> + +class X: public boost::signals2::postconstructible { +public: + X(): _postconstructed(false) + {} + ~X() + { + BOOST_CHECK(_postconstructed); + } +protected: + virtual void postconstruct() + { + BOOST_CHECK(!_postconstructed); + _postconstructed = true; + } + bool _postconstructed; +}; + +class Y: public boost::signals2::predestructible { +public: + Y(): _predestructed(false) + {} + ~Y() + { + BOOST_CHECK(_predestructed); + } +protected: + virtual void predestruct() + { + _predestructed = true; + } + bool _predestructed; +}; + +class Z: public X, public Y +{}; + +class by_deconstruct_only: public boost::signals2::postconstructible { +public: + ~by_deconstruct_only() + { + BOOST_CHECK(_postconstructed); + } + int value; +protected: + virtual void postconstruct() + { + BOOST_CHECK(!_postconstructed); + _postconstructed = true; + } + bool _postconstructed; +private: + friend class boost::signals2::deconstruct_access; + by_deconstruct_only(int value_in): + value(value_in), _postconstructed(false) + {} +}; + +namespace mytest +{ + class A + { + public: + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &sp, A *p) + { + BOOST_CHECK(!p->_postconstructed); + p->_postconstructed = true; + } + template<typename T> friend + void adl_postconstruct(const boost::shared_ptr<T> &sp, A *p, int val) + { + p->value = val; + BOOST_CHECK(!p->_postconstructed); + p->_postconstructed = true; + } + friend void adl_predestruct(A *p) + { + p->_predestructed = true; + } + ~A() + { + BOOST_CHECK(_postconstructed); + BOOST_CHECK(_predestructed); + } + int value; + private: + friend class boost::signals2::deconstruct_access; + A(int value_in = 0): + value(value_in), + _postconstructed(false), + _predestructed(false) + {} + bool _postconstructed; + bool _predestructed; + }; +} + +void deconstruct_ptr_test() +{ + { + boost::shared_ptr<X> x = boost::signals2::deconstruct_ptr(new X); + } + { + boost::shared_ptr<Y> x = boost::signals2::deconstruct_ptr(new Y); + } + { + boost::shared_ptr<Z> z = boost::signals2::deconstruct_ptr(new Z); + } +} + +class deconstructed_esft : public boost::enable_shared_from_this<deconstructed_esft> +{ +public: + deconstructed_esft() : x(0) {} + +private: + friend void adl_postconstruct(boost::shared_ptr<void>, deconstructed_esft *) {} + int x; +}; + +void deconstruct_test() +{ + { + boost::shared_ptr<X> x = boost::signals2::deconstruct<X>(); + } + { + boost::shared_ptr<Y> x = boost::signals2::deconstruct<Y>(); + } + { + boost::shared_ptr<Z> z = boost::signals2::deconstruct<Z>(); + } + { + boost::shared_ptr<by_deconstruct_only> a = boost::signals2::deconstruct<by_deconstruct_only>(1); + BOOST_CHECK(a->value == 1); + } + { + boost::shared_ptr<mytest::A> a = boost::signals2::deconstruct<mytest::A>(1); + BOOST_CHECK(a->value == 1); + } + {// deconstruct const type + boost::shared_ptr<const mytest::A> a = boost::signals2::deconstruct<const mytest::A>(3); + BOOST_CHECK(a->value == 3); + } + {// passing arguments to postconstructor + boost::shared_ptr<mytest::A> a = boost::signals2::deconstruct<mytest::A>().postconstruct(2); + BOOST_CHECK(a->value == 2); + } + {// enable_shared_from_this with deconstruct + boost::shared_ptr<deconstructed_esft> a = boost::signals2::deconstruct<deconstructed_esft>(); + BOOST_CHECK(!(a->shared_from_this() < a || a < a->shared_from_this())); + } +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + deconstruct_ptr_test(); + deconstruct_test(); +} diff --git a/src/boost/libs/signals2/test/deletion_test.cpp b/src/boost/libs/signals2/test/deletion_test.cpp new file mode 100644 index 000000000..577c8512a --- /dev/null +++ b/src/boost/libs/signals2/test/deletion_test.cpp @@ -0,0 +1,297 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2001-2003. +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE deletion_test +#include <boost/test/included/unit_test.hpp> +#include <iostream> +#include <string> + +static boost::signals2::connection connections[5]; + +static std::string test_output; + +struct remove_connection { + explicit remove_connection(int v = 0, int i = -1) : value(v), idx(i) {} + + void operator()() const { + if (idx >= 0) + connections[idx].disconnect(); + + //return value; + std::cout << value << " "; + + test_output += static_cast<char>(value + '0'); + } + + int value; + int idx; +}; + +bool operator==(const remove_connection& x, const remove_connection& y) +{ return x.value == y.value && x.idx == y.idx; } + +static void +test_remove_self() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2, 2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "Deleting 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "013"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3, 3)); + + std::cout << "Deleting 3" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "012"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.num_slots() == 0); + + connections[0] = s0.connect(remove_connection(0, 0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "Deleting 0" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "123"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0, 0)); + connections[1] = s0.connect(remove_connection(1, 1)); + connections[2] = s0.connect(remove_connection(2, 2)); + connections[3] = s0.connect(remove_connection(3, 3)); + + std::cout << "Mass suicide" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == ""); +} + +static void +test_remove_prior() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1, 0)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "1 removes 0" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "123"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3, 2)); + + std::cout << "3 removes 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "013"); +} + +static void +test_remove_after() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0, 1)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "0 removes 1" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "023"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "023"); + + s0.disconnect_all_slots(); + BOOST_CHECK(s0.empty()); + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1, 3)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "1 removes 3" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "012"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "012"); +} + +static void +test_bloodbath() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0, 1)); + connections[1] = s0.connect(remove_connection(1, 1)); + connections[2] = s0.connect(remove_connection(2, 0)); + connections[3] = s0.connect(remove_connection(3, 2)); + + std::cout << "0 removes 1, 2 removes 0, 3 removes 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "023"); + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "3"); +} + +static void +test_disconnect_equal() +{ + boost::signals2::signal<void ()> s0; + + connections[0] = s0.connect(remove_connection(0)); + connections[1] = s0.connect(remove_connection(1)); + connections[2] = s0.connect(remove_connection(2)); + connections[3] = s0.connect(remove_connection(3)); + + std::cout << "Deleting 2" << std::endl; + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "0123"); + +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + connections[2].disconnect(); +#else + s0.disconnect(remove_connection(2)); +#endif + + test_output = ""; + s0(); std::cout << std::endl; + BOOST_CHECK(test_output == "013"); +} + +struct signal_deletion_tester +{ +public: + signal_deletion_tester() { + b_has_run = false; + sig = new boost::signals2::signal<void(void)>(); + connection0 = sig->connect(0, boost::bind(&signal_deletion_tester::a, this)); + connection1 = sig->connect(1, boost::bind(&signal_deletion_tester::b, this)); + } + + ~signal_deletion_tester() + { + if(sig != 0) + delete sig; + } + + void a() + { + if(sig != 0) + delete sig; + sig = 0; + } + + void b() + { + b_has_run = true; + } + + boost::signals2::signal<void(void)> *sig; + bool b_has_run; + boost::signals2::connection connection0; + boost::signals2::connection connection1; +}; + +// If a signal is deleted mid-invocation, the invocation in progress +// should complete normally. Once all invocations complete, all +// slots which were connected to the deleted signal should be in the +// disconnected state. +static void test_signal_deletion() +{ + signal_deletion_tester tester; + (*tester.sig)(); + BOOST_CHECK(tester.b_has_run); + BOOST_CHECK(tester.connection0.connected() == false); + BOOST_CHECK(tester.connection1.connected() == false); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_remove_self(); + test_remove_prior(); + test_remove_after(); + test_bloodbath(); + test_disconnect_equal(); + test_signal_deletion(); +} diff --git a/src/boost/libs/signals2/test/invocation_benchmark.cpp b/src/boost/libs/signals2/test/invocation_benchmark.cpp new file mode 100644 index 000000000..6a464fc52 --- /dev/null +++ b/src/boost/libs/signals2/test/invocation_benchmark.cpp @@ -0,0 +1,60 @@ +/* multi-threaded signal invocation benchmark */ + +// Copyright Frank Mori Hess 2007-2008. +// Distributed under the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/signals2.hpp> +#include <boost/thread/thread.hpp> + +using namespace boost::placeholders; + +typedef boost::signals2::signal<void ()> signal_type; + +void myslot() +{ +/* std::cout << __FUNCTION__ << std::endl; + sleep(1);*/ +} + +void thread_initial(signal_type *signal, unsigned num_invocations) +{ + unsigned i; + for(i = 0; i < num_invocations; ++i) + { + (*signal)(); + } +} + +int main(int argc, const char **argv) +{ + if(argc < 3) + { + std::cerr << "usage: " << argv[0] << " <num threads> <num connections>" << std::endl; + return -1; + } + static const unsigned num_threads = std::strtol(argv[1], 0, 0); + static const unsigned num_connections = std::strtol(argv[2], 0, 0); + boost::thread_group threads; + signal_type sig; + + std::cout << "Connecting " << num_connections << " connections to signal.\n"; + unsigned i; + for(i = 0; i < num_connections; ++i) + { + sig.connect(&myslot); + } + const unsigned num_slot_invocations = 1000000; + const unsigned signal_invocations_per_thread = num_slot_invocations / (num_threads * num_connections); + std::cout << "Launching " << num_threads << " thread(s) to invoke signal " << signal_invocations_per_thread << " times per thread.\n"; + for(i = 0; i < num_threads; ++i) + { + threads.create_thread(boost::bind(&thread_initial, &sig, signal_invocations_per_thread)); + } + threads.join_all(); + return 0; +} diff --git a/src/boost/libs/signals2/test/mutex_test.cpp b/src/boost/libs/signals2/test/mutex_test.cpp new file mode 100644 index 000000000..8da2972a5 --- /dev/null +++ b/src/boost/libs/signals2/test/mutex_test.cpp @@ -0,0 +1,292 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// Copyright Frank Mori Hess 2009 +// +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This is a simplified/modified version of libs/thread/test/test_mutex.cpp +// added to test boost::signals2::mutex. +// For more information, see http://www.boost.org + +// Note boost/test/minimal.hpp can cause windows.h to get included, which +// can screw up our checks of _WIN32_WINNT if it is included +// after boost/signals2/mutex.hpp. Frank Hess 2009-03-07. +// We now use boost/test/included/unit_test.hpp, not sure if above still +// applies, but might as well leave the include where it is. +#define BOOST_TEST_MODULE mutex_test +#include <boost/test/included/unit_test.hpp> + +#include <boost/bind/bind.hpp> +#include <boost/signals2/dummy_mutex.hpp> +#include <boost/signals2/mutex.hpp> +#include <boost/thread/locks.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/condition.hpp> + +using namespace boost::placeholders; + +class execution_monitor +{ +public: + execution_monitor(int secs) + : done(false), m_secs(secs) { } + void start() + { + boost::mutex::scoped_lock lock(mutex); + done = false; + } + void finish() + { + boost::mutex::scoped_lock lock(mutex); + done = true; + cond.notify_one(); + } + bool wait() + { + boost::posix_time::time_duration timeout = boost::posix_time::seconds(m_secs); + boost::mutex::scoped_lock lock(mutex); + while (!done) { + if (!cond.timed_wait(lock, timeout)) + break; + } + return done; + } + +private: + boost::mutex mutex; + boost::condition cond; + bool done; + int m_secs; +}; + +template <typename F> +class indirect_adapter +{ +public: + indirect_adapter(F func, execution_monitor& monitor) + : m_func(func), m_monitor(monitor) { } + void operator()() const + { + try + { + boost::thread thrd(m_func); + thrd.join(); + } + catch (...) + { + m_monitor.finish(); + throw; + } + m_monitor.finish(); + } + +private: + F m_func; + execution_monitor& m_monitor; + void operator=(indirect_adapter&); +}; + +template <typename F> +void timed_test(F func, int secs) +{ + execution_monitor monitor(secs); + indirect_adapter<F> ifunc(func, monitor); + monitor.start(); + boost::thread thrd(ifunc); + BOOST_REQUIRE(monitor.wait()); // Timed test didn't complete in time, possible deadlock +} + +template <typename M> +struct test_lock +{ + typedef M mutex_type; + typedef typename boost::unique_lock<M> lock_type; + + void operator()() + { + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + lock_type lock(mutex); + BOOST_CHECK(lock ? true : false); + + // Construct a fast time out. + boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, timeout)); + BOOST_CHECK(lock ? true : false); + + // Test the lock and unlock methods. + lock.unlock(); + BOOST_CHECK(!lock); + lock.lock(); + BOOST_CHECK(lock ? true : false); + } +}; + +template <typename M> +struct test_trylock +{ + typedef M mutex_type; + typedef typename boost::unique_lock<M> lock_type; + + void operator()() + { + mutex_type mutex; + boost::condition condition; + + // Test the lock's constructors. + { + lock_type lock(mutex, boost::try_to_lock); + BOOST_CHECK(lock ? true : false); + } + { + lock_type lock(mutex, boost::defer_lock); + BOOST_CHECK(!lock); + } + lock_type lock(mutex, boost::try_to_lock); + BOOST_CHECK(lock ? true : false); + + // Construct a fast time out. + boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100); + + // Test the lock and the mutex with condition variables. + // No one is going to notify this condition variable. We expect to + // time out. + BOOST_CHECK(!condition.timed_wait(lock, timeout)); + BOOST_CHECK(lock ? true : false); + + // Test the lock, unlock and trylock methods. + lock.unlock(); + BOOST_CHECK(!lock); + lock.lock(); + BOOST_CHECK(lock ? true : false); + lock.unlock(); + BOOST_CHECK(!lock); + BOOST_CHECK(lock.try_lock()); + BOOST_CHECK(lock ? true : false); + } +}; + +template<typename Mutex> +struct test_lock_exclusion +{ + typedef boost::unique_lock<Mutex> Lock; + + Mutex m; + boost::mutex done_mutex; + bool done; + bool locked; + boost::condition_variable done_cond; + + test_lock_exclusion(): + done(false),locked(false) + {} + + void locking_thread() + { + Lock lock(m); + + boost::lock_guard<boost::mutex> lk(done_mutex); + locked=lock.owns_lock(); + done=true; + done_cond.notify_one(); + } + + bool is_done() const + { + return done; + } + + typedef test_lock_exclusion<Mutex> this_type; + + void do_test(void (this_type::*test_func)()) + { + Lock lock(m); + + { + boost::lock_guard<boost::mutex> lk(done_mutex); + locked=false; + } + + done=false; + + boost::thread t(test_func,this); + + try + { + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(!done_cond.timed_wait(lk, boost::posix_time::seconds(1), + boost::bind(&this_type::is_done,this))); + } + lock.unlock(); + { + boost::mutex::scoped_lock lk(done_mutex); + BOOST_CHECK(done_cond.timed_wait(lk, boost::posix_time::seconds(1), + boost::bind(&this_type::is_done,this))); + } + t.join(); + BOOST_CHECK(locked); + } + catch(...) + { + lock.unlock(); + t.join(); + throw; + } + } + + + void operator()() + { + do_test(&this_type::locking_thread); + } +}; + + +void do_test_mutex() +{ + test_lock<boost::signals2::mutex>()(); +// try_lock not supported on old versions of windows +#if !defined(BOOST_HAS_WINTHREADS) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)) + test_trylock<boost::signals2::mutex>()(); +#endif + test_lock_exclusion<boost::signals2::mutex>()(); +} + +void test_mutex() +{ + timed_test(&do_test_mutex, 3); +} + +void do_test_dummy_mutex() +{ + test_lock<boost::signals2::dummy_mutex>()(); + test_trylock<boost::signals2::dummy_mutex>()(); +} + +void test_dummy_mutex() +{ + timed_test(&do_test_dummy_mutex, 2); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_mutex(); + test_dummy_mutex(); +} diff --git a/src/boost/libs/signals2/test/ordering_test.cpp b/src/boost/libs/signals2/test/ordering_test.cpp new file mode 100644 index 000000000..9636fb016 --- /dev/null +++ b/src/boost/libs/signals2/test/ordering_test.cpp @@ -0,0 +1,128 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2002-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE ordering_test +#include <boost/test/included/unit_test.hpp> +#include <iostream> +#include <vector> +#include <algorithm> +#include <cstdlib> +#include <ctime> +#include <functional> + +std::vector<int> valuesOutput; +bool ungrouped1 = false; +bool ungrouped2 = false; +bool ungrouped3 = false; + +struct emit_int { + emit_int(int v) : value(v) {} + + void operator()() const + { + BOOST_CHECK(value == 42 || (!ungrouped1 && !ungrouped2 && !ungrouped3)); + valuesOutput.push_back(value); + std::cout << value << ' '; + } + +private: + int value; +}; + +struct write_ungrouped1 { + void operator()() const + { + BOOST_CHECK(!ungrouped1); + ungrouped1 = true; + std::cout << "(Ungrouped #1)" << ' '; + } +}; + +struct write_ungrouped2 { + void operator()() const + { + BOOST_CHECK(!ungrouped2); + ungrouped2 = true; + std::cout << "(Ungrouped #2)" << ' '; + } +}; + +struct write_ungrouped3 { + void operator()() const + { + BOOST_CHECK(!ungrouped3); + ungrouped3 = true; + std::cout << "(Ungrouped #3)" << ' '; + } +}; + +int return_argument(int x) +{ + return x; +} + +void test_group_compare() +{ + boost::signals2::signal + < + int (), + boost::signals2::last_value<int>, + int, + std::greater< int > + > sig; + + sig.connect( 1, boost::bind( &return_argument, 1) ); + sig.connect( 2, boost::bind( &return_argument, 2) ); + + BOOST_CHECK(sig() == 1); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + using namespace std; + srand(time(0)); + + std::vector<int> sortedValues; + + boost::signals2::signal<void ()> sig; + sig.connect(write_ungrouped1()); + for (int i = 0; i < 100; ++i) { +#ifdef BOOST_NO_STDC_NAMESPACE + int v = rand() % 100; +#else + int v = std::rand() % 100; +#endif + sortedValues.push_back(v); + sig.connect(v, emit_int(v)); + + if (i == 50) { + sig.connect(write_ungrouped2()); + } + } + sig.connect(write_ungrouped3()); + + std::sort(sortedValues.begin(), sortedValues.end()); + + // 17 at beginning, 42 at end + sortedValues.insert(sortedValues.begin(), 17); + sig.connect(emit_int(17), boost::signals2::at_front); + sortedValues.push_back(42); + sig.connect(emit_int(42)); + + sig(); + std::cout << std::endl; + + BOOST_CHECK(valuesOutput == sortedValues); + BOOST_CHECK(ungrouped1); + BOOST_CHECK(ungrouped2); + BOOST_CHECK(ungrouped3); + + test_group_compare(); +} diff --git a/src/boost/libs/signals2/test/regression_test.cpp b/src/boost/libs/signals2/test/regression_test.cpp new file mode 100644 index 000000000..59187353c --- /dev/null +++ b/src/boost/libs/signals2/test/regression_test.cpp @@ -0,0 +1,109 @@ +// thread_safe_signals library +// Some assorted tests to expose various bugs that existed at some point, +// to make sure they stay fixed + +// Copyright Frank Mori Hess 2008 +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE regression_test +#include <boost/test/included/unit_test.hpp> + +typedef boost::signals2::signal<void ()> sig0_type; + +// combiner that returns the number of slots invoked +struct slot_counter { + typedef unsigned result_type; + template<typename InputIterator> + unsigned operator()(InputIterator first, InputIterator last) const + { + unsigned count = 0; + for (; first != last; ++first) + { + try + { + *first; + ++count; + } + catch(const boost::bad_weak_ptr &) + {} + } + return count; + } +}; + +void my_slot() +{ +} + +void my_connecting_slot(sig0_type &sig) +{ + sig.connect(&my_slot); +} + +void slot_connect_test() +{ + sig0_type sig; + sig.connect(sig0_type::slot_type(&my_connecting_slot, boost::ref(sig)).track(sig)); + /* 2008-02-28: the following signal invocation triggered a (bogus) failed assertion of _shared_state.unique() + at detail/signal_template.hpp:285 */ + sig(); + BOOST_CHECK(sig.num_slots() == 2); + sig.disconnect(&my_slot); + BOOST_CHECK(sig.num_slots() == 1); + /* 2008-03-11: checked iterator barfed on next line, due to bad semantics of copy construction + for boost::signals2::detail::grouped_list */ + sig(); + BOOST_CHECK(sig.num_slots() == 2); +} + +/* 2008-03-10: we weren't disconnecting old connection in scoped_connection assignment operator */ +void scoped_connection_test() +{ + typedef boost::signals2::signal<void (), slot_counter> signal_type; + signal_type sig; + { + boost::signals2::scoped_connection conn(sig.connect(&my_slot)); + BOOST_CHECK(sig() == 1); + conn = sig.connect(&my_slot); + BOOST_CHECK(sig() == 1); + } + BOOST_CHECK(sig() == 0); +} + +// testsignal that returns a reference type + +struct ref_returner +{ + static int i; + + int& ref_return_slot() + { + return i; + } +}; + +int ref_returner::i = 0; + +void reference_return_test() +{ + boost::signals2::signal<int& ()> rTest; + ref_returner rr; + rTest.connect(boost::bind(&ref_returner::ref_return_slot, &rr)); + int& r = *rTest(); + BOOST_CHECK(ref_returner::i == 0); + r = 1; + BOOST_CHECK(ref_returner::i == 1); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + slot_connect_test(); + scoped_connection_test(); + reference_return_test(); +} diff --git a/src/boost/libs/signals2/test/shared_connection_block_test.cpp b/src/boost/libs/signals2/test/shared_connection_block_test.cpp new file mode 100644 index 000000000..4ad5bdf33 --- /dev/null +++ b/src/boost/libs/signals2/test/shared_connection_block_test.cpp @@ -0,0 +1,112 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2001-2003. +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/array.hpp> +#include <boost/signals2/shared_connection_block.hpp> +#include <boost/signals2/signal.hpp> +#define BOOST_TEST_MODULE shared_connection_block_test +#include <boost/test/included/unit_test.hpp> +#include <iostream> +#include <sstream> +#include <string> + +static boost::array<boost::signals2::connection, 4> connections; + +static std::ostringstream test_output; + +struct test_slot { + explicit test_slot(int v = 0) : value(v) + {} + + void operator()() const { + test_output << value; + } + + int value; +}; + +BOOST_AUTO_TEST_CASE(test_main) +{ + boost::signals2::signal<void ()> s0; + + for(unsigned i = 0; i < connections.size(); ++i) + { + connections.at(i) = s0.connect(test_slot(i)); + } + + + { + // Blocking 2 + boost::signals2::shared_connection_block block(connections.at(2)); + BOOST_CHECK(block.blocking()); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "013"); + } + + // Unblocking 2 + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "0123"); + + { + // Blocking 1 through const connection + const boost::signals2::connection conn = connections.at(1); + boost::signals2::shared_connection_block block(conn); + test_output.str(""); + s0(); + std::cout << test_output.str() << std::endl; + BOOST_CHECK(test_output.str() == "023"); + // Unblocking 1 + block.unblock(); + BOOST_CHECK(block.blocking() == false); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "0123"); + } + + { + // initially unblocked + boost::signals2::shared_connection_block block(connections.at(3), false); + BOOST_CHECK(block.blocking() == false); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "0123"); + // block + block.block(); + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "012"); + } + + { + // test default constructed block + boost::signals2::shared_connection_block block; + BOOST_CHECK(block.blocking() == true); + block.unblock(); + BOOST_CHECK(block.blocking() == false); + block.block(); + BOOST_CHECK(block.blocking() == true); + + // test assignment + { + block.unblock(); + boost::signals2::shared_connection_block block2(connections.at(0)); + BOOST_CHECK(block.connection() != block2.connection()); + BOOST_CHECK(block.blocking() != block2.blocking()); + block = block2; + BOOST_CHECK(block.connection() == block2.connection()); + BOOST_CHECK(block.blocking() == block2.blocking()); + } + test_output.str(""); + s0(); + BOOST_CHECK(test_output.str() == "123"); + } +} diff --git a/src/boost/libs/signals2/test/signal_n_test.cpp b/src/boost/libs/signals2/test/signal_n_test.cpp new file mode 100644 index 000000000..c1c2b4027 --- /dev/null +++ b/src/boost/libs/signals2/test/signal_n_test.cpp @@ -0,0 +1,352 @@ +// Boost.Signals library + +// Copyright Douglas Gregor 2001-2003. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/bind/bind.hpp> +#include <boost/config.hpp> +#define BOOST_TEST_MODULE signal_n_test +#include <boost/test/included/unit_test.hpp> + +using namespace boost::placeholders; + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES +BOOST_AUTO_TEST_CASE(test_main) +{ +} +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#include <boost/optional.hpp> +#include <boost/ref.hpp> +#include <boost/signals2.hpp> +#include <functional> + +template<typename T> +struct max_or_default { + typedef T result_type; + template<typename InputIterator> + typename InputIterator::value_type + operator()(InputIterator first, InputIterator last) const + { + boost::optional<T> max; + for (; first != last; ++first) + { + try + { + if(!max) max = *first; + else max = (*first > max.get())? *first : max; + } + catch(const boost::bad_weak_ptr &) + {} + } + if(max) return max.get(); + return T(); + } +}; + +struct make_int { + make_int(int n, int cn) : N(n), CN(n) {} + int operator()() { return N; } + int operator()() const { return CN; } + + int N; + int CN; +}; + +template<int N> +struct make_increasing_int { + make_increasing_int() : n(N) {} + + int operator()() const { return n++; } + + mutable int n; +}; + +int get_37() { return 37; } + +static void +test_zero_args() +{ + make_int i42(42, 41); + make_int i2(2, 1); + make_int i72(72, 71); + make_int i63(63, 63); + make_int i62(62, 61); + + { + boost::signals2::signal0<int, max_or_default<int>, std::string> s0; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect("72", i72); + boost::signals2::connection c62 = s0.connect("6x", i62); + boost::signals2::connection c42 = s0.connect(i42); + boost::signals2::connection c37 = s0.connect(&get_37); + + BOOST_CHECK(s0() == 72); + + s0.disconnect("72"); + BOOST_CHECK(s0() == 62); + + c72.disconnect(); // Double-disconnect should be safe + BOOST_CHECK(s0() == 62); + + s0.disconnect("72"); // Triple-disconect should be safe + BOOST_CHECK(s0() == 62); + + // Also connect 63 in the same group as 62 + s0.connect("6x", i63); + BOOST_CHECK(s0() == 63); + + // Disconnect all of the 60's + s0.disconnect("6x"); + BOOST_CHECK(s0() == 42); + + c42.disconnect(); + BOOST_CHECK(s0() == 37); + + c37.disconnect(); + BOOST_CHECK(s0() == 2); + + c2.disconnect(); + BOOST_CHECK(s0() == 0); + } + + { + boost::signals2::signal0<int, max_or_default<int> > s0; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect(i72); + boost::signals2::connection c62 = s0.connect(i62); + boost::signals2::connection c42 = s0.connect(i42); + + const boost::signals2::signal0<int, max_or_default<int> >& cs0 = s0; + BOOST_CHECK(cs0() == 72); + } + + { + make_increasing_int<7> i7; + make_increasing_int<10> i10; + + boost::signals2::signal0<int, max_or_default<int> > s0; + boost::signals2::connection c7 = s0.connect(i7); + boost::signals2::connection c10 = s0.connect(i10); + + BOOST_CHECK(s0() == 10); + BOOST_CHECK(s0() == 11); + } +} + +static void +test_one_arg() +{ + boost::signals2::signal1<int, int, max_or_default<int> > s1; + + s1.connect(std::negate<int>()); + s1.connect(boost::bind(std::multiplies<int>(), 2, _1)); + + BOOST_CHECK(s1(1) == 2); + BOOST_CHECK(s1(-1) == 1); +} + +static void +test_signal_signal_connect() +{ + typedef boost::signals2::signal1<int, int, max_or_default<int> > signal_type; + signal_type s1; + + s1.connect(std::negate<int>()); + + BOOST_CHECK(s1(3) == -3); + + { + signal_type s2; + s1.connect(s2); + s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); + s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); + + BOOST_CHECK(s2(-3) == 9); + BOOST_CHECK(s1(3) == 6); + } // s2 goes out of scope and disconnects + + BOOST_CHECK(s1(3) == -3); + + // test auto-track of signal wrapped in a reference_wrapper + { + signal_type s2; + s1.connect(boost::cref(s2)); + s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); + s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); + + BOOST_CHECK(s2(-3) == 9); + BOOST_CHECK(s1(3) == 6); + } // s2 goes out of scope and disconnects + + BOOST_CHECK(s1(3) == -3); +} + +struct EventCounter +{ + EventCounter() : count(0) {} + + void operator()() + { + ++count; + } + + int count; +}; + +static void +test_ref() +{ + EventCounter ec; + boost::signals2::signal0<void> s; + + { + boost::signals2::scoped_connection c(s.connect(boost::ref(ec))); + BOOST_CHECK(ec.count == 0); + s(); + BOOST_CHECK(ec.count == 1); + } + s(); + BOOST_CHECK(ec.count == 1); +} + +static void test_default_combiner() +{ + boost::signals2::signal0<int> sig; + boost::optional<int> result; + result = sig(); + BOOST_CHECK(!result); + + sig.connect(make_int(0, 0)); + result = sig(); + BOOST_CHECK(result); + BOOST_CHECK(*result == 0); + + sig.connect(make_int(1, 1)); + result = sig(); + BOOST_CHECK(result); + BOOST_CHECK(*result == 1); +} + +template<typename ResultType> + ResultType disconnecting_slot(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return ResultType(); +} + +#ifdef BOOST_NO_VOID_RETURNS +template<> + void disconnecting_slot<void>(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return; +} +#endif + +template<typename ResultType> + void test_extended_slot() +{ + { + typedef boost::signals2::signal1<ResultType, int> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(0); + BOOST_CHECK(sig.num_slots() == 0); + } + { // test 0 arg signal + typedef boost::signals2::signal0<ResultType> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp, _1, 0); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(); + BOOST_CHECK(sig.num_slots() == 0); + } + // test disconnection by slot + { + typedef boost::signals2::signal1<ResultType, int> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig.disconnect(fp); + BOOST_CHECK(sig.num_slots() == 0); + } +} +class dummy_combiner +{ +public: + typedef int result_type; + + dummy_combiner(result_type return_value): _return_value(return_value) + {} + template<typename SlotIterator> + result_type operator()(SlotIterator, SlotIterator) + { + return _return_value; + } +private: + result_type _return_value; +}; + +static void +test_set_combiner() +{ + typedef boost::signals2::signal0<int, dummy_combiner> signal_type; + signal_type sig(dummy_combiner(0)); + BOOST_CHECK(sig() == 0); + BOOST_CHECK(sig.combiner()(0,0) == 0); + sig.set_combiner(dummy_combiner(1)); + BOOST_CHECK(sig() == 1); + BOOST_CHECK(sig.combiner()(0,0) == 1); +} + +static void +test_swap() +{ + typedef boost::signals2::signal0<int, dummy_combiner> signal_type; + signal_type sig1(dummy_combiner(1)); + BOOST_CHECK(sig1() == 1); + signal_type sig2(dummy_combiner(2)); + BOOST_CHECK(sig2() == 2); + + sig1.swap(sig2); + BOOST_CHECK(sig1() == 2); + BOOST_CHECK(sig2() == 1); + + using std::swap; + swap(sig1, sig2); + BOOST_CHECK(sig1() == 1); + BOOST_CHECK(sig2() == 2); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_zero_args(); + test_one_arg(); + test_signal_signal_connect(); + test_ref(); + test_default_combiner(); + test_extended_slot<void>(); + test_extended_slot<int>(); + test_set_combiner(); + test_swap(); +} + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES diff --git a/src/boost/libs/signals2/test/signal_test.cpp b/src/boost/libs/signals2/test/signal_test.cpp new file mode 100644 index 000000000..3ae2817f7 --- /dev/null +++ b/src/boost/libs/signals2/test/signal_test.cpp @@ -0,0 +1,348 @@ +// Boost.Signals library + +// Copyright Frank Mori Hess 2008-2009. +// Copyright Douglas Gregor 2001-2003. +// +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/bind/bind.hpp> +#include <boost/optional.hpp> +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE signal_test +#include <boost/test/included/unit_test.hpp> +#include <functional> +#include <iostream> +#include <typeinfo> + +using namespace boost::placeholders; + +template<typename T> +struct max_or_default { + typedef T result_type; + template<typename InputIterator> + typename InputIterator::value_type + operator()(InputIterator first, InputIterator last) const + { + boost::optional<T> max; + for (; first != last; ++first) + { + try + { + if(!max) max = *first; + else max = (*first > max.get())? *first : max; + } + catch(const boost::bad_weak_ptr &) + {} + } + if(max) return max.get(); + return T(); + } +}; + +struct make_int { + make_int(int n, int cn) : N(n), CN(cn) {} + + int operator()() { return N; } + int operator()() const { return CN; } + + int N; + int CN; +}; + +template<int N> +struct make_increasing_int { + make_increasing_int() : n(N) {} + + int operator()() const { return n++; } + + mutable int n; +}; + +static void +test_zero_args() +{ + make_int i42(42, 41); + make_int i2(2, 1); + make_int i72(72, 71); + make_int i63(63, 63); + make_int i62(62, 61); + + { + boost::signals2::signal<int (), max_or_default<int> > s0; + + std::cout << "sizeof(signal) = " << sizeof(s0) << std::endl; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect(72, i72); + boost::signals2::connection c62 = s0.connect(60, i62); + boost::signals2::connection c42 = s0.connect(i42); + + BOOST_CHECK(s0() == 72); + + s0.disconnect(72); + BOOST_CHECK(s0() == 62); + + c72.disconnect(); // Double-disconnect should be safe + BOOST_CHECK(s0() == 62); + + s0.disconnect(72); // Triple-disconect should be safe + BOOST_CHECK(s0() == 62); + + // Also connect 63 in the same group as 62 + s0.connect(60, i63); + BOOST_CHECK(s0() == 63); + + // Disconnect all of the 60's + s0.disconnect(60); + BOOST_CHECK(s0() == 42); + + c42.disconnect(); + BOOST_CHECK(s0() == 2); + + c2.disconnect(); + BOOST_CHECK(s0() == 0); + } + + { + boost::signals2::signal<int (), max_or_default<int> > s0; + boost::signals2::connection c2 = s0.connect(i2); + boost::signals2::connection c72 = s0.connect(i72); + boost::signals2::connection c62 = s0.connect(i62); + boost::signals2::connection c42 = s0.connect(i42); + + const boost::signals2::signal<int (), max_or_default<int> >& cs0 = s0; + BOOST_CHECK(cs0() == 72); + } + + { + make_increasing_int<7> i7; + make_increasing_int<10> i10; + + boost::signals2::signal<int (), max_or_default<int> > s0; + boost::signals2::connection c7 = s0.connect(i7); + boost::signals2::connection c10 = s0.connect(i10); + + BOOST_CHECK(s0() == 10); + BOOST_CHECK(s0() == 11); + } +} + +static void +test_one_arg() +{ + boost::signals2::signal<int (int value), max_or_default<int> > s1; + + s1.connect(std::negate<int>()); + s1.connect(boost::bind(std::multiplies<int>(), 2, _1)); + + BOOST_CHECK(s1(1) == 2); + BOOST_CHECK(s1(-1) == 1); +} + +static void +test_signal_signal_connect() +{ + typedef boost::signals2::signal<int (int value), max_or_default<int> > signal_type; + signal_type s1; + + s1.connect(std::negate<int>()); + + BOOST_CHECK(s1(3) == -3); + + { + signal_type s2; + s1.connect(s2); + s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); + s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); + + BOOST_CHECK(s2(-3) == 9); + BOOST_CHECK(s1(3) == 6); + } // s2 goes out of scope and disconnects + BOOST_CHECK(s1(3) == -3); +} + +template<typename ResultType> + ResultType disconnecting_slot(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return ResultType(); +} + +#ifdef BOOST_NO_VOID_RETURNS +template<> + void disconnecting_slot<void>(const boost::signals2::connection &conn, int) +{ + conn.disconnect(); + return; +} +#endif + +template<typename ResultType> + void test_extended_slot() +{ + { + typedef boost::signals2::signal<ResultType (int)> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(0); + BOOST_CHECK(sig.num_slots() == 0); + } + { // test 0 arg signal + typedef boost::signals2::signal<ResultType ()> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp, _1, 0); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig(); + BOOST_CHECK(sig.num_slots() == 0); + } + // test disconnection by slot + { + typedef boost::signals2::signal<ResultType (int)> signal_type; + typedef typename signal_type::extended_slot_type slot_type; + signal_type sig; + // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer + ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; + slot_type myslot(fp); + sig.connect_extended(myslot); + BOOST_CHECK(sig.num_slots() == 1); + sig.disconnect(fp); + BOOST_CHECK(sig.num_slots() == 0); + } +} + +void increment_arg(int &value) +{ + ++value; +} + +static void +test_reference_args() +{ + typedef boost::signals2::signal<void (int &)> signal_type; + signal_type s1; + + s1.connect(&increment_arg); + int value = 0; + s1(value); + BOOST_CHECK(value == 1); +} + +static void +test_typedefs_etc() +{ + typedef boost::signals2::signal<int (double, long)> signal_type; + typedef signal_type::slot_type slot_type; + + BOOST_CHECK(typeid(signal_type::slot_result_type) == typeid(int)); + BOOST_CHECK(typeid(signal_type::result_type) == typeid(boost::optional<int>)); + BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(double)); + BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(long)); + BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(signal_type::first_argument_type)); + BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(signal_type::second_argument_type)); + BOOST_CHECK(typeid(signal_type::signature_type) == typeid(int (double, long))); + BOOST_CHECK(signal_type::arity == 2); + + BOOST_CHECK(typeid(slot_type::result_type) == typeid(signal_type::slot_result_type)); + BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(signal_type::arg<0>::type)); + BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(signal_type::arg<1>::type)); + BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(slot_type::first_argument_type)); + BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(slot_type::second_argument_type)); + BOOST_CHECK(typeid(slot_type::signature_type) == typeid(signal_type::signature_type)); + BOOST_CHECK(slot_type::arity == signal_type::arity); + + typedef boost::signals2::signal<void (short)> unary_signal_type; + BOOST_CHECK(typeid(unary_signal_type::slot_result_type) == typeid(void)); + BOOST_CHECK(typeid(unary_signal_type::argument_type) == typeid(short)); + BOOST_CHECK(typeid(unary_signal_type::slot_type::argument_type) == typeid(short)); +} + +class dummy_combiner +{ +public: + typedef int result_type; + + dummy_combiner(result_type return_value): _return_value(return_value) + {} + template<typename SlotIterator> + result_type operator()(SlotIterator, SlotIterator) + { + return _return_value; + } +private: + result_type _return_value; +}; + +static void +test_set_combiner() +{ + typedef boost::signals2::signal<int (), dummy_combiner> signal_type; + signal_type sig(dummy_combiner(0)); + BOOST_CHECK(sig() == 0); + BOOST_CHECK(sig.combiner()(0,0) == 0); + sig.set_combiner(dummy_combiner(1)); + BOOST_CHECK(sig() == 1); + BOOST_CHECK(sig.combiner()(0,0) == 1); +} + +static void +test_swap() +{ + typedef boost::signals2::signal<int (), dummy_combiner> signal_type; + signal_type sig1(dummy_combiner(1)); + BOOST_CHECK(sig1() == 1); + signal_type sig2(dummy_combiner(2)); + BOOST_CHECK(sig2() == 2); + + sig1.swap(sig2); + BOOST_CHECK(sig1() == 2); + BOOST_CHECK(sig2() == 1); + + using std::swap; + swap(sig1, sig2); + BOOST_CHECK(sig1() == 1); + BOOST_CHECK(sig2() == 2); +} + +void test_move() +{ +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + typedef boost::signals2::signal<int (), dummy_combiner> signal_type; + signal_type sig1(dummy_combiner(1)); + BOOST_CHECK(sig1() == 1); + signal_type sig2(dummy_combiner(2)); + BOOST_CHECK(sig2() == 2); + + sig1 = std::move(sig2); + BOOST_CHECK(sig1() == 2); + + signal_type sig3(std::move(sig1)); + BOOST_CHECK(sig3() == 2); +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_zero_args(); + test_one_arg(); + test_signal_signal_connect(); + test_extended_slot<void>(); + test_extended_slot<int>(); + test_reference_args(); + test_typedefs_etc(); + test_set_combiner(); + test_swap(); + test_move(); +} diff --git a/src/boost/libs/signals2/test/signal_type_test.cpp b/src/boost/libs/signals2/test/signal_type_test.cpp new file mode 100644 index 000000000..94c746429 --- /dev/null +++ b/src/boost/libs/signals2/test/signal_type_test.cpp @@ -0,0 +1,43 @@ +// Tests for boost::signals2::signal_type + +// Copyright Frank Mori Hess 2009. +// Distributed under the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/signals2 for library home page. + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE signal_type_test +#include <boost/test/included/unit_test.hpp> + +namespace bs2 = boost::signals2; + +BOOST_AUTO_TEST_CASE(test_main) +{ + { + bs2::signal_type<void ()>::type mysig; + bs2::signal<void ()> mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } + + { + bs2::signal_type<double (int), bs2::last_value<double> >::type mysig; + bs2::signal<double (int), bs2::last_value<double> > mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } + + { + using namespace bs2::keywords; + bs2::signal_type<double (int), group_compare_type<std::less<float> >, group_type<float> >::type mysig; + bs2::signal<double (int), bs2::optional_last_value<double>, float, std::less<float> > mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } + + { + using namespace bs2::keywords; + bs2::signal_type<signature_type<float (long*)> >::type mysig; + bs2::signal<float (long*)> mysig2; + BOOST_CHECK(typeid(mysig) == typeid(mysig2)); + } +} diff --git a/src/boost/libs/signals2/test/slot_compile_test.cpp b/src/boost/libs/signals2/test/slot_compile_test.cpp new file mode 100644 index 000000000..6ce6c3715 --- /dev/null +++ b/src/boost/libs/signals2/test/slot_compile_test.cpp @@ -0,0 +1,27 @@ +// Signals2 library +// test for compilation of boost/signals2/slot.hpp + +// Copyright Frank Mori Hess 2008 +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/signals2/slot.hpp> +#define BOOST_TEST_MODULE slot_compile_test +#include <boost/test/included/unit_test.hpp> + +void myslot() +{} + +int myslot2(int) +{ + return 0; +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + boost::signals2::slot<void (void)> sl0(&myslot); +} diff --git a/src/boost/libs/signals2/test/threading_models_test.cpp b/src/boost/libs/signals2/test/threading_models_test.cpp new file mode 100644 index 000000000..bddae17c0 --- /dev/null +++ b/src/boost/libs/signals2/test/threading_models_test.cpp @@ -0,0 +1,86 @@ +// thread_safe_signals library +// basic test for alternate threading models + +// Copyright Frank Mori Hess 2008 +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE threading_models_test +#include <boost/test/included/unit_test.hpp> +#include <boost/thread/mutex.hpp> + +// combiner that returns the number of slots invoked +struct slot_counter { + typedef unsigned result_type; + template<typename InputIterator> + unsigned operator()(InputIterator first, InputIterator last) const + { + unsigned count = 0; + for (; first != last; ++first) + { + try + { + *first; + ++count; + } + catch(const boost::bad_weak_ptr &) + {} + } + return count; + } +}; + +void myslot() +{ +} + +template<typename signal_type> +void simple_test() +{ + signal_type sig; + sig.connect(typename signal_type::slot_type(&myslot)); + BOOST_CHECK(sig() == 1); + sig.disconnect(&myslot); + BOOST_CHECK(sig() == 0); +} + +class recursion_checking_dummy_mutex +{ + int recursion_count; +public: + recursion_checking_dummy_mutex(): recursion_count(0) + {} + void lock() + { + BOOST_REQUIRE(recursion_count == 0); + ++recursion_count; + } + bool try_lock() + { + lock(); + return true; + } + void unlock() + { + --recursion_count; + BOOST_REQUIRE(recursion_count == 0); + } +}; + +BOOST_AUTO_TEST_CASE(test_main) +{ + typedef boost::signals2::signal<void (), slot_counter, int, std::less<int>, boost::function<void ()>, + boost::function<void (const boost::signals2::connection &)>, recursion_checking_dummy_mutex> sig0_rc_type; + simple_test<sig0_rc_type>(); + typedef boost::signals2::signal<void (), slot_counter, int, std::less<int>, boost::function<void ()>, + boost::function<void (const boost::signals2::connection &)>, boost::mutex> sig0_mt_type; + simple_test<sig0_mt_type>(); + typedef boost::signals2::signal<void (), slot_counter, int, std::less<int>, boost::function<void ()>, + boost::function<void (const boost::signals2::connection &)>, boost::signals2::dummy_mutex> sig0_st_type; + simple_test<sig0_st_type>(); +} diff --git a/src/boost/libs/signals2/test/track_test.cpp b/src/boost/libs/signals2/test/track_test.cpp new file mode 100644 index 000000000..405aa11b6 --- /dev/null +++ b/src/boost/libs/signals2/test/track_test.cpp @@ -0,0 +1,167 @@ +// Boost.Signals library + +// Copyright Douglas Gregor 2001-2006 +// Copyright Frank Mori Hess 2007 +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <memory> +#include <boost/optional.hpp> +#include <boost/ref.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/signals2.hpp> +#define BOOST_TEST_MODULE track_test +#include <boost/test/included/unit_test.hpp> +#include <boost/bind/bind.hpp> + +using namespace boost::placeholders; + +struct swallow { + typedef int result_type; + template<typename T> result_type operator()(const T*, int i) { return i; } +}; + +template<typename T> +struct max_or_default { + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + boost::optional<T> max; + for(; first != last; ++first) + { + T value = *first; + if(!max) + { + max = value; + }else if(value > *max) + { + max = value; + } + } + if(max) return *max; + else return T(); + } +}; + +static int myfunc(int i, double z) +{ + return i; +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + typedef boost::signals2::signal<int (int), max_or_default<int> > sig_type; + sig_type s1; + boost::signals2::connection connection; + + // Test auto-disconnection + BOOST_CHECK(s1(5) == 0); + { + boost::shared_ptr<int> shorty(new int()); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track(shorty)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + + // Test auto-disconnection of slot before signal connection + { + boost::shared_ptr<int> shorty(new int(1)); +// doesn't work on gcc 3.3.5, it says: error: type specifier omitted for parameter `shorty' +// does work on gcc 4.1.2 +// sig_type::slot_type slot(swallow(), shorty.get(), _1); + swallow myswallow; + sig_type::slot_type slot(myswallow, shorty.get(), _1); + + slot.track(shorty); + shorty.reset(); + s1.connect(slot); + BOOST_CHECK(s1(5) == 0); + } + + // Test binding of a slot to another slot + { + boost::shared_ptr<int> shorty(new int(2)); + boost::signals2::slot<int (double)> other_slot(&myfunc, boost::cref(*shorty.get()), _1); + other_slot.track(shorty); + connection = s1.connect(sig_type::slot_type(other_slot, 0.5).track(other_slot)); + BOOST_CHECK(s1(3) == 2); + } + BOOST_CHECK(connection.connected() == false); + BOOST_CHECK(s1(3) == 0); + + // Test binding of a signal as a slot + { + sig_type s2; + s1.connect(s2); + s2.connect(sig_type::slot_type(&myfunc, _1, 0.7)); + BOOST_CHECK(s1(4) == 4); + } + BOOST_CHECK(s1(4) == 0); + + // Test tracking of null but not empty shared_ptr + BOOST_CHECK(s1(2) == 0); + { + boost::shared_ptr<int> shorty((int*)(0)); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track(shorty)); + BOOST_CHECK(s1(2) == 2); + } + BOOST_CHECK(s1(2) == 0); + +#ifndef BOOST_NO_CXX11_SMART_PTR + // Test tracking through std::shared_ptr/weak_ptr + BOOST_CHECK(s1(5) == 0); + { + std::shared_ptr<int> shorty(new int()); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track_foreign(shorty)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + { + std::shared_ptr<int> shorty(new int()); + s1.connect + ( + sig_type::slot_type + ( + swallow(), + shorty.get(), + _1 + ).track_foreign + ( + std::weak_ptr<int>(shorty) + ) + ); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + // make sure tracking foreign shared_ptr<const void> works + { + std::shared_ptr<const void> shorty(new int()); + s1.connect(sig_type::slot_type(swallow(), shorty.get(), _1).track_foreign(shorty)); + BOOST_CHECK(s1(5) == 5); + } + { + std::shared_ptr<int> shorty(new int()); + s1.connect + ( + sig_type::slot_type + ( + swallow(), + shorty.get(), + _1 + ).track_foreign + ( + std::weak_ptr<const void>(shorty) + ) + ); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + BOOST_CHECK(s1(5) == 0); +#endif +} diff --git a/src/boost/libs/signals2/test/trackable_test.cpp b/src/boost/libs/signals2/test/trackable_test.cpp new file mode 100644 index 000000000..b3049cdfd --- /dev/null +++ b/src/boost/libs/signals2/test/trackable_test.cpp @@ -0,0 +1,112 @@ +// Boost.Signals2 library + +// Copyright Douglas Gregor 2001-2006. +// Copyright Frank Mori Hess 2009. +// Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include <boost/signals2/signal.hpp> +#include <boost/signals2/trackable.hpp> +#define BOOST_TEST_MODULE trackable_test +#include <boost/test/included/unit_test.hpp> +#include <boost/bind/bind.hpp> +#include <boost/ref.hpp> +#include <boost/weak_ptr.hpp> + +using namespace boost::placeholders; + +struct short_lived : public boost::signals2::trackable { + ~short_lived() {} +}; + +struct swallow { + typedef int result_type; + template<typename T> int operator()(const T*, int i) { return i; } + template<typename T> int operator()(T &, int i) { return i; } + template<typename T> int operator()(boost::weak_ptr<T>, int i) { return i; } +}; + +template<typename T> +struct max_or_default { + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + if (first == last) + return T(); + + T max = *first++; + for (; first != last; ++first) + max = (*first > max)? *first : max; + + return max; + } +}; + +struct self_deleting : public boost::signals2::trackable { + void delete_myself(boost::signals2::connection connection) + { + BOOST_CHECK(connection.connected()); + delete this; + BOOST_CHECK(connection.connected() == false); + } +}; + +// test that slot assocated with signals2::trackable +// gets disconnected immediately upon deletion of the +// signals2::trackable, even when a signal invocation +// is in progress. +void test_immediate_disconnect_on_delete() +{ + boost::signals2::signal<void () > sig; + self_deleting *obj = new self_deleting(); + sig.connect_extended(boost::bind(&self_deleting::delete_myself, obj, _1)); + sig(); +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + typedef boost::signals2::signal<int (int), max_or_default<int> > sig_type; + sig_type s1; + + // Test auto-disconnection + BOOST_CHECK(s1(5) == 0); + { + short_lived shorty; + s1.connect(boost::bind<int>(swallow(), &shorty, _1)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + // Test auto-disconnection of trackable inside reference_wrapper + { + short_lived shorty; + s1.connect(boost::bind<int>(swallow(), boost::ref(shorty), _1)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + + // Test multiple arg slot constructor + { + short_lived shorty; + s1.connect(sig_type::slot_type(swallow(), &shorty, _1)); + BOOST_CHECK(s1(5) == 5); + } + BOOST_CHECK(s1(5) == 0); + + // Test auto-disconnection of slot before signal connection + { + short_lived* shorty = new short_lived(); + + sig_type::slot_type slot(boost::bind<int>(swallow(), shorty, _1)); + delete shorty; + + BOOST_CHECK(s1(5) == 0); + } + + test_immediate_disconnect_on_delete(); +} |