llevents_tut.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:33k
- /**
- * @file llevents_tut.cpp
- * @author Nat Goodspeed
- * @date 2008-09-12
- * @brief Test of llevents.h
- *
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- *
- * Copyright (c) 2008-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #if LL_WINDOWS
- #pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
- #endif
- // Precompiled header
- #include "linden_common.h"
- // associated header
- // UGLY HACK! We want to verify state internal to the classes without
- // providing public accessors.
- #define testable public
- #include "llevents.h"
- #undef testable
- #include "lllistenerwrapper.h"
- // STL headers
- // std headers
- #include <iostream>
- #include <typeinfo>
- // external library headers
- #include <boost/bind.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/assign/list_of.hpp>
- // other Linden headers
- #include "lltut.h"
- #include "stringize.h"
- #include "tests/listener.h"
- using boost::assign::list_of;
- template<typename T>
- T make(const T& value) { return value; }
- /*****************************************************************************
- * tut test group
- *****************************************************************************/
- namespace tut
- {
- struct events_data
- {
- events_data():
- pumps(LLEventPumps::instance()),
- listener0("first"),
- listener1("second")
- {}
- LLEventPumps& pumps;
- Listener listener0;
- Listener listener1;
- void check_listener(const std::string& desc, const Listener& listener, LLSD::Integer got)
- {
- ensure_equals(STRINGIZE(listener << ' ' << desc),
- listener.getLastEvent().asInteger(), got);
- }
- };
- typedef test_group<events_data> events_group;
- typedef events_group::object events_object;
- tut::events_group evgr("events");
- template<> template<>
- void events_object::test<1>()
- {
- set_test_name("basic operations");
- // Now there's a static constructor in llevents.cpp that registers on
- // the "mainloop" pump to call LLEventPumps::flush().
- // Actually -- having to modify this to track the statically-
- // constructed pumps in other TUT modules in this giant monolithic test
- // executable isn't such a hot idea.
- // ensure_equals("initial pump", pumps.mPumpMap.size(), 1);
- size_t initial_pumps(pumps.mPumpMap.size());
- LLEventPump& per_frame(pumps.obtain("per-frame"));
- ensure_equals("first explicit pump", pumps.mPumpMap.size(), initial_pumps+1);
- // Verify that per_frame was instantiated as an LLEventStream.
- ensure("LLEventStream leaf class", dynamic_cast<LLEventStream*>(&per_frame));
- ensure("enabled", per_frame.enabled());
- // Trivial test, but posting an event to an EventPump with no
- // listeners should not blow up. The test is relevant because defining
- // a boost::signal with a non-void return signature, using the default
- // combiner, blows up if there are no listeners. This is because the
- // default combiner is defined to return the value returned by the
- // last listener, which is meaningless if there were no listeners.
- per_frame.post(0);
- LLBoundListener connection = listener0.listenTo(per_frame);
- ensure("connected", connection.connected());
- ensure("not blocked", ! connection.blocked());
- per_frame.post(1);
- check_listener("received", listener0, 1);
- { // block the connection
- LLEventPump::Blocker block(connection);
- ensure("blocked", connection.blocked());
- per_frame.post(2);
- check_listener("not updated", listener0, 1);
- } // unblock
- ensure("unblocked", ! connection.blocked());
- per_frame.post(3);
- check_listener("unblocked", listener0, 3);
- LLBoundListener sameConnection = per_frame.getListener(listener0.getName());
- ensure("still connected", sameConnection.connected());
- ensure("still not blocked", ! sameConnection.blocked());
- { // block it again
- LLEventPump::Blocker block(sameConnection);
- ensure("re-blocked", sameConnection.blocked());
- per_frame.post(4);
- check_listener("re-blocked", listener0, 3);
- } // unblock
- bool threw = false;
- try
- {
- // NOTE: boost::bind() saves its arguments by VALUE! If you pass
- // an object instance rather than a pointer, you'll end up binding
- // to an internal copy of that instance! Use boost::ref() to
- // capture a reference instead.
- per_frame.listen(listener0.getName(), // note bug, dup name
- boost::bind(&Listener::call, boost::ref(listener1), _1));
- }
- catch (const LLEventPump::DupListenerName& e)
- {
- threw = true;
- ensure_equals(e.what(),
- std::string("DupListenerName: "
- "Attempt to register duplicate listener name '") +
- listener0.getName() +
- "' on " + typeid(per_frame).name() + " '" + per_frame.getName() + "'");
- }
- ensure("threw DupListenerName", threw);
- // do it right this time
- listener1.listenTo(per_frame);
- per_frame.post(5);
- check_listener("got", listener0, 5);
- check_listener("got", listener1, 5);
- per_frame.enable(false);
- per_frame.post(6);
- check_listener("didn't get", listener0, 5);
- check_listener("didn't get", listener1, 5);
- per_frame.enable();
- per_frame.post(7);
- check_listener("got", listener0, 7);
- check_listener("got", listener1, 7);
- per_frame.stopListening(listener0.getName());
- ensure("disconnected 0", ! connection.connected());
- ensure("disconnected 1", ! sameConnection.connected());
- per_frame.post(8);
- check_listener("disconnected", listener0, 7);
- check_listener("still connected", listener1, 8);
- per_frame.stopListening(listener1.getName());
- per_frame.post(9);
- check_listener("disconnected", listener1, 8);
- }
- template<> template<>
- void events_object::test<2>()
- {
- set_test_name("callstop() returning true");
- LLEventPump& per_frame(pumps.obtain("per-frame"));
- listener0.reset(0);
- listener1.reset(0);
- LLBoundListener bound0 = listener0.listenTo(per_frame, &Listener::callstop);
- LLBoundListener bound1 = listener1.listenTo(per_frame, &Listener::call,
- // after listener0
- make<LLEventPump::NameList>(list_of(listener0.getName())));
- ensure("enabled", per_frame.enabled());
- ensure("connected 0", bound0.connected());
- ensure("unblocked 0", ! bound0.blocked());
- ensure("connected 1", bound1.connected());
- ensure("unblocked 1", ! bound1.blocked());
- per_frame.post(1);
- check_listener("got", listener0, 1);
- // Because listener0.callstop() returns true, control never reaches listener1.call().
- check_listener("got", listener1, 0);
- }
- bool chainEvents(Listener& someListener, const LLSD& event)
- {
- // Make this call so we can watch for side effects for test purposes.
- someListener.call(event);
- // This function represents a recursive event chain -- or some other
- // scenario in which an event handler raises additional events.
- int value = event.asInteger();
- if (value)
- {
- LLEventPumps::instance().obtain("login").post(value - 1);
- }
- return false;
- }
- template<> template<>
- void events_object::test<3>()
- {
- set_test_name("LLEventQueue delayed action");
- // This access is NOT legal usage: we can do it only because we're
- // hacking private for test purposes. Normally we'd either compile in
- // a particular name, or (later) edit a config file.
- pumps.mQueueNames.insert("login");
- LLEventPump& login(pumps.obtain("login"));
- // The "mainloop" pump is special: posting on that implicitly calls
- // LLEventPumps::flush(), which in turn should flush our "login"
- // LLEventQueue.
- LLEventPump& mainloop(pumps.obtain("mainloop"));
- ensure("LLEventQueue leaf class", dynamic_cast<LLEventQueue*>(&login));
- listener0.listenTo(login);
- listener0.reset(0);
- login.post(1);
- check_listener("waiting for queued event", listener0, 0);
- mainloop.post(LLSD());
- check_listener("got queued event", listener0, 1);
- login.stopListening(listener0.getName());
- // Verify that when an event handler posts a new event on the same
- // LLEventQueue, it doesn't get processed in the same flush() call --
- // it waits until the next flush() call.
- listener0.reset(17);
- login.listen("chainEvents", boost::bind(chainEvents, boost::ref(listener0), _1));
- login.post(1);
- check_listener("chainEvents(1) not yet called", listener0, 17);
- mainloop.post(LLSD());
- check_listener("chainEvents(1) called", listener0, 1);
- mainloop.post(LLSD());
- check_listener("chainEvents(0) called", listener0, 0);
- mainloop.post(LLSD());
- check_listener("chainEvents(-1) not called", listener0, 0);
- login.stopListening("chainEvents");
- }
- template<> template<>
- void events_object::test<4>()
- {
- set_test_name("explicitly-instantiated LLEventStream");
- // Explicitly instantiate an LLEventStream, and verify that it
- // self-registers with LLEventPumps
- size_t registered = pumps.mPumpMap.size();
- size_t owned = pumps.mOurPumps.size();
- LLEventPump* localInstance;
- {
- LLEventStream myEventStream("stream");
- localInstance = &myEventStream;
- LLEventPump& stream(pumps.obtain("stream"));
- ensure("found named LLEventStream instance", &stream == localInstance);
- ensure_equals("registered new instance", pumps.mPumpMap.size(), registered + 1);
- ensure_equals("explicit instance not owned", pumps.mOurPumps.size(), owned);
- } // destroy myEventStream -- should unregister
- ensure_equals("destroyed instance unregistered", pumps.mPumpMap.size(), registered);
- ensure_equals("destroyed instance not owned", pumps.mOurPumps.size(), owned);
- LLEventPump& stream(pumps.obtain("stream"));
- ensure("new LLEventStream instance", &stream != localInstance);
- ensure_equals("obtain()ed instance registered", pumps.mPumpMap.size(), registered + 1);
- ensure_equals("obtain()ed instance owned", pumps.mOurPumps.size(), owned + 1);
- }
- template<> template<>
- void events_object::test<5>()
- {
- set_test_name("stopListening()");
- LLEventPump& login(pumps.obtain("login"));
- listener0.listenTo(login);
- login.stopListening(listener0.getName());
- // should not throw because stopListening() should have removed name
- listener0.listenTo(login, &Listener::callstop);
- LLBoundListener wrong = login.getListener("bogus");
- ensure("bogus connection disconnected", ! wrong.connected());
- ensure("bogus connection blocked", wrong.blocked());
- }
- template<> template<>
- void events_object::test<6>()
- {
- set_test_name("chaining LLEventPump instances");
- LLEventPump& upstream(pumps.obtain("upstream"));
- // One potentially-useful construct is to chain LLEventPumps together.
- // Among other things, this allows you to turn subsets of listeners on
- // and off in groups.
- LLEventPump& filter0(pumps.obtain("filter0"));
- LLEventPump& filter1(pumps.obtain("filter1"));
- upstream.listen(filter0.getName(),
- boost::bind(&LLEventPump::post, boost::ref(filter0), _1));
- upstream.listen(filter1.getName(),
- boost::bind(&LLEventPump::post, boost::ref(filter1), _1));
- listener0.listenTo(filter0);
- listener1.listenTo(filter1);
- listener0.reset(0);
- listener1.reset(0);
- upstream.post(1);
- check_listener("got unfiltered", listener0, 1);
- check_listener("got unfiltered", listener1, 1);
- filter0.enable(false);
- upstream.post(2);
- check_listener("didn't get filtered", listener0, 1);
- check_listener("got filtered", listener1, 2);
- }
- template<> template<>
- void events_object::test<7>()
- {
- set_test_name("listener dependency order");
- typedef LLEventPump::NameList NameList;
- typedef Collect::StringList StringList;
- LLEventPump& button(pumps.obtain("button"));
- Collect collector;
- button.listen("Mary",
- boost::bind(&Collect::add, boost::ref(collector), "Mary", _1),
- // state that "Mary" must come after "checked"
- make<NameList>(list_of("checked")));
- button.listen("checked",
- boost::bind(&Collect::add, boost::ref(collector), "checked", _1),
- // "checked" must come after "spot"
- make<NameList>(list_of("spot")));
- button.listen("spot",
- boost::bind(&Collect::add, boost::ref(collector), "spot", _1));
- button.post(1);
- ensure_equals(collector.result, make<StringList>(list_of("spot")("checked")("Mary")));
- collector.clear();
- button.stopListening("Mary");
- button.listen("Mary",
- boost::bind(&Collect::add, boost::ref(collector), "Mary", _1),
- LLEventPump::empty, // no after dependencies
- // now "Mary" must come before "spot"
- make<NameList>(list_of("spot")));
- button.post(2);
- ensure_equals(collector.result, make<StringList>(list_of("Mary")("spot")("checked")));
- collector.clear();
- button.stopListening("spot");
- std::string threw;
- try
- {
- button.listen("spot",
- boost::bind(&Collect::add, boost::ref(collector), "spot", _1),
- // after "Mary" and "checked" -- whoops!
- make<NameList>(list_of("Mary")("checked")));
- }
- catch (const LLEventPump::Cycle& e)
- {
- threw = e.what();
- // std::cout << "Caught: " << e.what() << 'n';
- }
- // Obviously the specific wording of the exception text can
- // change; go ahead and change the test to match.
- // Establish that it contains:
- // - the name and runtime type of the LLEventPump
- ensure_contains("LLEventPump type", threw, typeid(button).name());
- ensure_contains("LLEventPump name", threw, "'button'");
- // - the name of the new listener that caused the problem
- ensure_contains("new listener name", threw, "'spot'");
- // - a synopsis of the problematic dependencies.
- ensure_contains("cyclic dependencies", threw,
- ""Mary" -> before ("spot")");
- ensure_contains("cyclic dependencies", threw,
- "after ("spot") -> "checked"");
- ensure_contains("cyclic dependencies", threw,
- "after ("Mary", "checked") -> "spot"");
- button.listen("yellow",
- boost::bind(&Collect::add, boost::ref(collector), "yellow", _1),
- make<NameList>(list_of("checked")));
- button.listen("shoelaces",
- boost::bind(&Collect::add, boost::ref(collector), "shoelaces", _1),
- make<NameList>(list_of("checked")));
- button.post(3);
- ensure_equals(collector.result, make<StringList>(list_of("Mary")("checked")("yellow")("shoelaces")));
- collector.clear();
- threw.clear();
- try
- {
- button.listen("of",
- boost::bind(&Collect::add, boost::ref(collector), "of", _1),
- make<NameList>(list_of("shoelaces")),
- make<NameList>(list_of("yellow")));
- }
- catch (const LLEventPump::OrderChange& e)
- {
- threw = e.what();
- // std::cout << "Caught: " << e.what() << 'n';
- }
- // Same remarks about the specific wording of the exception. Just
- // ensure that it contains enough information to clarify the
- // problem and what must be done to resolve it.
- ensure_contains("LLEventPump type", threw, typeid(button).name());
- ensure_contains("LLEventPump name", threw, "'button'");
- ensure_contains("new listener name", threw, "'of'");
- ensure_contains("prev listener name", threw, "'yellow'");
- ensure_contains("old order", threw, "was: Mary, checked, yellow, shoelaces");
- ensure_contains("new order", threw, "now: Mary, checked, shoelaces, of, yellow");
- button.post(4);
- ensure_equals(collector.result, make<StringList>(list_of("Mary")("checked")("yellow")("shoelaces")));
- }
- template<> template<>
- void events_object::test<8>()
- {
- set_test_name("tweaked and untweaked LLEventPump instance names");
- { // nested scope
- // Hand-instantiate an LLEventStream...
- LLEventStream bob("bob");
- bool threw = false;
- try
- {
- // then another with a duplicate name.
- LLEventStream bob2("bob");
- }
- catch (const LLEventPump::DupPumpName& /*e*/)
- {
- threw = true;
- // std::cout << "Caught: " << e.what() << 'n';
- }
- ensure("Caught DupPumpName", threw);
- } // delete first 'bob'
- LLEventStream bob("bob"); // should work, previous one unregistered
- LLEventStream bob1("bob", true); // allowed to tweak name
- ensure_equals("tweaked LLEventStream name", bob1.getName(), "bob1");
- std::vector< boost::shared_ptr<LLEventStream> > streams;
- for (int i = 2; i <= 10; ++i)
- {
- streams.push_back(boost::shared_ptr<LLEventStream>(new LLEventStream("bob", true)));
- }
- ensure_equals("last tweaked LLEventStream name", streams.back()->getName(), "bob10");
- }
- // Define a function that accepts an LLListenerOrPumpName
- void eventSource(const LLListenerOrPumpName& listener)
- {
- // Pretend that some time has elapsed. Call listener immediately.
- listener(17);
- }
- template<> template<>
- void events_object::test<9>()
- {
- set_test_name("LLListenerOrPumpName");
- // Passing a boost::bind() expression to LLListenerOrPumpName
- listener0.reset(0);
- eventSource(boost::bind(&Listener::call, boost::ref(listener0), _1));
- check_listener("got by listener", listener0, 17);
- // Passing a string LLEventPump name to LLListenerOrPumpName
- listener0.reset(0);
- LLEventStream random("random");
- listener0.listenTo(random);
- eventSource("random");
- check_listener("got by pump name", listener0, 17);
- bool threw = false;
- try
- {
- LLListenerOrPumpName empty;
- empty(17);
- }
- catch (const LLListenerOrPumpName::Empty&)
- {
- threw = true;
- }
- ensure("threw Empty", threw);
- }
- class TempListener: public Listener
- {
- public:
- TempListener(const std::string& name, bool& liveFlag):
- Listener(name),
- mLiveFlag(liveFlag)
- {
- mLiveFlag = true;
- }
- virtual ~TempListener()
- {
- mLiveFlag = false;
- }
- private:
- bool& mLiveFlag;
- };
- template<> template<>
- void events_object::test<10>()
- {
- set_test_name("listen(boost::bind(...TempListener...))");
- // listen() can't do anything about a plain TempListener instance:
- // it's not managed with shared_ptr, nor is it an LLEventTrackable subclass
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- TempListener tempListener("temp", live);
- ensure("TempListener constructed", live);
- connection = heaptest.listen(tempListener.getName(),
- boost::bind(&Listener::call,
- boost::ref(tempListener),
- _1));
- heaptest.post(1);
- check_listener("received", tempListener, 1);
- } // presumably this will make newListener go away?
- // verify that
- ensure("TempListener destroyed", ! live);
- // This is the case against which we can't defend. Don't even try to
- // post to heaptest -- that would engage Undefined Behavior.
- // Cautiously inspect connection...
- ensure("misleadingly connected", connection.connected());
- // then disconnect by hand.
- heaptest.stopListening("temp");
- }
- template<> template<>
- void events_object::test<11>()
- {
- set_test_name("listen(boost::bind(...weak_ptr...))");
- // listen() detecting weak_ptr<TempListener> in boost::bind() object
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- ensure("default state", ! connection.connected());
- {
- boost::shared_ptr<TempListener> newListener(new TempListener("heap", live));
- newListener->reset();
- ensure("TempListener constructed", live);
- connection = heaptest.listen(newListener->getName(),
- boost::bind(&Listener::call, weaken(newListener), _1));
- ensure("new connection", connection.connected());
- heaptest.post(1);
- check_listener("received", *newListener, 1);
- } // presumably this will make newListener go away?
- // verify that
- ensure("TempListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
- }
- template<> template<>
- void events_object::test<12>()
- {
- set_test_name("listen(boost::bind(...shared_ptr...))");
- /*==========================================================================*|
- // DISABLED because I've made this case produce a compile error.
- // Following the error leads the disappointed dev to a comment
- // instructing her to use the weaken() function to bind a weak_ptr<T>
- // instead of binding a shared_ptr<T>, and explaining why. I know of
- // no way to use TUT to code a repeatable test in which the expected
- // outcome is a compile error. The interested reader is invited to
- // uncomment this block and build to see for herself.
- // listen() detecting shared_ptr<TempListener> in boost::bind() object
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- std::string listenerName("heap");
- ensure("default state", ! connection.connected());
- {
- boost::shared_ptr<TempListener> newListener(new TempListener(listenerName, live));
- ensure_equals("use_count", newListener.use_count(), 1);
- newListener->reset();
- ensure("TempListener constructed", live);
- connection = heaptest.listen(newListener->getName(),
- boost::bind(&Listener::call, newListener, _1));
- ensure("new connection", connection.connected());
- ensure_equals("use_count", newListener.use_count(), 2);
- heaptest.post(1);
- check_listener("received", *newListener, 1);
- } // this should make newListener go away...
- // Unfortunately, the fact that we've bound a shared_ptr by value into
- // our LLEventPump means that copy will keep the referenced object alive.
- ensure("TempListener still alive", live);
- ensure("still connected", connection.connected());
- // disconnecting explicitly should delete the TempListener...
- heaptest.stopListening(listenerName);
- #if 0 // however, in my experience, it does not. I don't know why not.
- // Ah: on 2009-02-19, Frank Mori Hess, author of the Boost.Signals2
- // library, stated on the boost-users mailing list:
- // http://www.nabble.com/Re%3A--signals2--review--The-review-of-the-signals2-library-(formerly-thread_safe_signals)-begins-today%2C-Nov-1st-p22102367.html
- // "It will get destroyed eventually. The signal cleans up its slot
- // list little by little during connect/invoke. It doesn't immediately
- // remove disconnected slots from the slot list since other threads
- // might be using the same slot list concurrently. It might be
- // possible to make it immediately reset the shared_ptr owning the
- // slot though, leaving an empty shared_ptr in the slot list, since
- // that wouldn't invalidate any iterators."
- ensure("TempListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- #endif // 0
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
- |*==========================================================================*/
- }
- class TempTrackableListener: public TempListener, public LLEventTrackable
- {
- public:
- TempTrackableListener(const std::string& name, bool& liveFlag):
- TempListener(name, liveFlag)
- {}
- };
- template<> template<>
- void events_object::test<13>()
- {
- set_test_name("listen(boost::bind(...TempTrackableListener ref...))");
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- TempTrackableListener tempListener("temp", live);
- ensure("TempTrackableListener constructed", live);
- connection = heaptest.listen(tempListener.getName(),
- boost::bind(&TempTrackableListener::call,
- boost::ref(tempListener), _1));
- heaptest.post(1);
- check_listener("received", tempListener, 1);
- } // presumably this will make tempListener go away?
- // verify that
- ensure("TempTrackableListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
- }
- template<> template<>
- void events_object::test<14>()
- {
- set_test_name("listen(boost::bind(...TempTrackableListener pointer...))");
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- TempTrackableListener* newListener(new TempTrackableListener("temp", live));
- ensure("TempTrackableListener constructed", live);
- connection = heaptest.listen(newListener->getName(),
- boost::bind(&TempTrackableListener::call,
- newListener, _1));
- heaptest.post(1);
- check_listener("received", *newListener, 1);
- // explicitly destroy newListener
- delete newListener;
- }
- // verify that
- ensure("TempTrackableListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
- }
- template<> template<>
- void events_object::test<15>()
- {
- // This test ensures that using an LLListenerWrapper subclass doesn't
- // block Boost.Signals2 from recognizing a bound LLEventTrackable
- // subclass.
- set_test_name("listen(llwrap<LLLogListener>(boost::bind(...TempTrackableListener ref...)))");
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- TempTrackableListener tempListener("temp", live);
- ensure("TempTrackableListener constructed", live);
- connection = heaptest.listen(tempListener.getName(),
- llwrap<LLLogListener>(
- boost::bind(&TempTrackableListener::call,
- boost::ref(tempListener), _1)));
- heaptest.post(1);
- check_listener("received", tempListener, 1);
- } // presumably this will make tempListener go away?
- // verify that
- ensure("TempTrackableListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
- }
- class TempSharedListener: public TempListener,
- public boost::enable_shared_from_this<TempSharedListener>
- {
- public:
- TempSharedListener(const std::string& name, bool& liveFlag):
- TempListener(name, liveFlag)
- {}
- };
- template<> template<>
- void events_object::test<16>()
- {
- set_test_name("listen(boost::bind(...TempSharedListener ref...))");
- #if 0
- bool live = false;
- LLEventPump& heaptest(pumps.obtain("heaptest"));
- LLBoundListener connection;
- {
- // We MUST have at least one shared_ptr to an
- // enable_shared_from_this subclass object before
- // shared_from_this() can work.
- boost::shared_ptr<TempSharedListener>
- tempListener(new TempSharedListener("temp", live));
- ensure("TempSharedListener constructed", live);
- // However, we're not passing either the shared_ptr or its
- // corresponding weak_ptr -- instead, we're passing a reference to
- // the TempSharedListener.
- /*==========================================================================*|
- std::cout << "Capturing const ref" << std::endl;
- const boost::enable_shared_from_this<TempSharedListener>& cref(*tempListener);
- std::cout << "Capturing const ptr" << std::endl;
- const boost::enable_shared_from_this<TempSharedListener>* cp(&cref);
- std::cout << "Capturing non-const ptr" << std::endl;
- boost::enable_shared_from_this<TempSharedListener>* p(const_cast<boost::enable_shared_from_this<TempSharedListener>*>(cp));
- std::cout << "Capturing shared_from_this()" << std::endl;
- boost::shared_ptr<TempSharedListener> sp(p->shared_from_this());
- std::cout << "Capturing weak_ptr" << std::endl;
- boost::weak_ptr<TempSharedListener> wp(weaken(sp));
- std::cout << "Binding weak_ptr" << std::endl;
- |*==========================================================================*/
- connection = heaptest.listen(tempListener->getName(),
- boost::bind(&TempSharedListener::call, *tempListener, _1));
- heaptest.post(1);
- check_listener("received", *tempListener, 1);
- } // presumably this will make tempListener go away?
- // verify that
- ensure("TempSharedListener destroyed", ! live);
- ensure("implicit disconnect", ! connection.connected());
- // now just make sure we don't blow up trying to access a freed object!
- heaptest.post(2);
- #endif // 0
- }
- } // namespace tut