diff options
| author | Oz Linden <oz@lindenlab.com> | 2011-11-21 13:35:29 -0500 | 
|---|---|---|
| committer | Oz Linden <oz@lindenlab.com> | 2011-11-21 13:35:29 -0500 | 
| commit | 2f533950fccbbc37fbff65020201897999aaca04 (patch) | |
| tree | 1cca108a57f4c315c45bfb9afc7b0bc8df29cf1a | |
| parent | 82057f29720ec5daf95bfd915a75b4dfbc046422 (diff) | |
| parent | 182566800a834df8cb12fb03a869b216ad13cd84 (diff) | |
merge changes for storm-1634
| -rw-r--r-- | indra/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | indra/test/CMakeLists.txt | 54 | ||||
| -rw-r--r-- | indra/test/io.cpp | 2 | ||||
| -rw-r--r-- | indra/test/llapp_tut.cpp | 162 | ||||
| -rw-r--r-- | indra/test/llevents_tut.cpp | 1384 | ||||
| -rw-r--r-- | indra/test/llhttpclient_tut.cpp | 5 | ||||
| -rw-r--r-- | indra/test/llsd_new_tut.cpp | 71 | ||||
| -rw-r--r-- | indra/test/llsdmessagebuilder_tut.cpp | 7 | ||||
| -rw-r--r-- | indra/test/lltemplatemessagebuilder_tut.cpp | 55 | 
9 files changed, 991 insertions, 753 deletions
| diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index d1042d6e86..4b1bf49d07 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -1,4 +1,3 @@ -  # -*- cmake -*-  # cmake_minimum_required should appear before any @@ -70,6 +69,9 @@ if (VIEWER)    add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml)    add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components) +  # Legacy C++ tests. Build always, run if LL_TESTS is true. +  add_subdirectory(${VIEWER_PREFIX}test) +    # viewer media plugins    add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index e9eb3c1884..328ab4ca51 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -4,7 +4,6 @@ project (test)  include(00-Common)  include(LLCommon) -include(LLDatabase)  include(LLInventory)  include(LLMath)  include(LLMessage) @@ -32,7 +31,7 @@ include_directories(  set(test_SOURCE_FILES      io.cpp -#    llapp_tut.cpp                      # Temporarily removed until thread issues can be solved +    llapp_tut.cpp      llblowfish_tut.cpp      llbuffer_tut.cpp      lldoubledispatch_tut.cpp @@ -53,8 +52,6 @@ set(test_SOURCE_FILES      llservicebuilder_tut.cpp      llstreamtools_tut.cpp      lltemplatemessagebuilder_tut.cpp -    lltimestampcache_tut.cpp -    lltranscode_tut.cpp      lltut.cpp      lluuidhashmap_tut.cpp      message_tut.cpp @@ -76,12 +73,6 @@ if (NOT WINDOWS)         )  endif (NOT WINDOWS) -if (NOT DARWIN) -  list(APPEND test_SOURCE_FILES -    lldatabase_tut.cpp -    ) -endif (NOT DARWIN) -  set_source_files_properties(${test_HEADER_FILES}                              PROPERTIES HEADER_FILE_ONLY TRUE) @@ -100,7 +91,6 @@ target_link_libraries(test      ${LLCOMMON_LIBRARIES}      ${EXPAT_LIBRARIES}      ${GOOGLEMOCK_LIBRARIES} -    ${APRICONV_LIBRARIES}      ${PTHREAD_LIBRARY}      ${WINDOWS_LIBRARIES}      ${BOOST_PROGRAM_OPTIONS_LIBRARY} @@ -119,38 +109,28 @@ endif (WINDOWS)  get_target_property(TEST_EXE test LOCATION) -SET_TEST_PATH(LD_LIBRARY_PATH) -LL_TEST_COMMAND(command "${LD_LIBRARY_PATH}" -  "${TEST_EXE}" "--output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt" "--touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt") +SET_TEST_PATH(DYLD_LIBRARY_PATH) + +LL_TEST_COMMAND(command  +  "${DYLD_LIBRARY_PATH}" +  "${TEST_EXE}" +  "--output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt"  +  "--touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt") +  ADD_CUSTOM_COMMAND(    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt    COMMAND ${command}    DEPENDS test    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}    COMMENT "C++ unit tests" - ) +  )  set(test_results ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt) -if (EXISTS /etc/debian_version_FAIL) -  # The Python tests have all kinds of wacky non-portable assumptions -  # built in. - -  add_custom_command( -    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/py_tests_ok.txt -    COMMAND ${PYTHON_EXECUTABLE} -    ARGS -      ${CMAKE_CURRENT_SOURCE_DIR}/test.py -      --mode=static -      --output=${CMAKE_CURRENT_BINARY_DIR}/py_test_results.txt -      --touch=${CMAKE_CURRENT_BINARY_DIR}/py_tests_ok.txt -      --mode=static -    DEPENDS test.py -    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -    COMMENT "Python unit tests" -    ) - -  list(APPEND test_results ${CMAKE_CURRENT_BINARY_DIR}/py_tests_ok.txt) -endif (EXISTS /etc/debian_version_FAIL) -     -add_custom_target(tests_ok ALL DEPENDS ${test_results}) +# This should cause the test executable to be built, but not  +# run if LL_TESTS is disabled. This will hopefully keep the +# tests up to date with any code changes changes even if  +# developers choose to disable LL_TESTS. +if (LL_TESTS)   +    add_custom_target(tests_ok ALL DEPENDS ${test_results}) +endif (LL_TESTS) diff --git a/indra/test/io.cpp b/indra/test/io.cpp index c06c1b153b..ce747f667d 100644 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -909,7 +909,7 @@ namespace tut  		pipe_and_pump_fitness()  		{ -			LLFrameTimer::updateFrameTime();			 +			LLFrameTimer::updateFrameTime();  			apr_pool_create(&mPool, NULL);  			mPump = new LLPumpIO(mPool);  			mSocket = LLSocket::create( diff --git a/indra/test/llapp_tut.cpp b/indra/test/llapp_tut.cpp new file mode 100644 index 0000000000..aa5c0672e6 --- /dev/null +++ b/indra/test/llapp_tut.cpp @@ -0,0 +1,162 @@ +/**  + * @file llapp_tut.cpp + * @author Phoenix + * @date 2006-09-12 + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2006-2011, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include <tut/tut.hpp> + +#include "linden_common.h" +#include "llapp.h" +#include "lltut.h" + + +namespace tut +{ +	struct application +	{ +		class LLTestApp : public LLApp +		{ +		public: +			virtual bool init() { return true; } +			virtual bool cleanup() { return true; } +			virtual bool mainLoop() { return true; } +		}; +		LLTestApp* mApp; +		application() +		{ +			mApp = new LLTestApp; +		} +		~application() +		{ +			delete mApp; +		} +	}; + +	typedef test_group<application> application_t; +	typedef application_t::object application_object_t; +	tut::application_t tut_application("application"); + +	template<> template<> +	void application_object_t::test<1>() +	{ +		LLSD defaults; +		defaults["template"] = "../../../scripts/messages/message_template.msg"; +		defaults["configdir"] = "."; +		defaults["datadir"] = "data"; +		mApp->setOptionData(LLApp::PRIORITY_DEFAULT, defaults); + +		LLSD datadir_sd = mApp->getOption("datadir"); +		ensure_equals("data type", datadir_sd.type(), LLSD::TypeString); +		ensure_equals( +			"data value", datadir_sd.asString(), std::string("data")); +	} + +	template<> template<> +	void application_object_t::test<2>() +	{ +		const int ARGC = 13; +		const char* ARGV[ARGC] = +		{ +			"", // argv[0] is usually the application name +			"-crashcount", +			"2", +			"-space", +			"spaceserver.grid.lindenlab.com", +			"-db_host", +			"localhost", +			"--allowlslhttprequests", +			"-asset-uri", +			"http://test.lindenlab.com/assets", +			"-data", +			"127.0.0.1", +			"--smtp" +		}; +		bool ok = mApp->parseCommandOptions(ARGC, const_cast<char**>(ARGV)); +		ensure("command line parsed", ok); +		ensure_equals( +			"crashcount", mApp->getOption("crashcount").asInteger(), 2); +		ensure_equals( +			"space", +			mApp->getOption("space").asString(), +			std::string("spaceserver.grid.lindenlab.com")); +		ensure_equals( +			"db_host", +			mApp->getOption("db_host").asString(), +			std::string("localhost")); +		ensure("allowlshlttprequests", mApp->getOption("smtp")); +		ensure_equals( +			"asset-uri", +			mApp->getOption("asset-uri").asString(), +			std::string("http://test.lindenlab.com/assets")); +		ensure_equals( +			"data", +			mApp->getOption("data").asString(), +			std::string("127.0.0.1")); +		ensure("smtp", mApp->getOption("smtp")); +	} + +	template<> template<> +	void application_object_t::test<3>() +	{ +		const int ARGC = 4; +		const char* ARGV[ARGC] = +		{ +			"", // argv[0] is usually the application name +			"crashcount", +			"2", +			"--space" +		}; +		bool ok = mApp->parseCommandOptions(ARGC, const_cast<char**>(ARGV)); +		ensure("command line parse failure", !ok); +	} + +	template<> template<> +	void application_object_t::test<4>() +	{ +		const int ARGC = 4; +		const char* ARGV[ARGC] = +		{ +			"", // argv[0] is usually the application name +			"--crashcount", +			"2", +			"space" +		}; +		bool ok = mApp->parseCommandOptions(ARGC, const_cast<char**>(ARGV)); +		ensure("command line parse failure", !ok); +	} + + +	template<> template<> +	void application_object_t::test<5>() +	{ +		LLSD options; +		options["boolean-test"] = true; +		mApp->setOptionData(LLApp::PRIORITY_GENERAL_CONFIGURATION, options); +		ensure("bool set", mApp->getOption("boolean-test").asBoolean()); +		options["boolean-test"] = false; +		mApp->setOptionData(LLApp::PRIORITY_RUNTIME_OVERRIDE, options); +		ensure("bool unset", !mApp->getOption("boolean-test").asBoolean()); +	} +} diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp index 57e22bbb56..4699bb1827 100644 --- a/indra/test/llevents_tut.cpp +++ b/indra/test/llevents_tut.cpp @@ -54,686 +54,730 @@  using boost::assign::list_of; +#ifdef LL_LINUX +#define CATCH_MISSED_LINUX_EXCEPTION(exception, threw)										\ +catch (const std::runtime_error& ex)														\ +{																							\ +	/* This clause is needed on Linux, on the viewer side, because the	*/					\ +	/* exception isn't caught by the clause above. Warn the user...		*/					\ +	std::cerr << "Failed to catch " << typeid(ex).name() << std::endl;						\ +	/* But if the expected exception was thrown, allow the test to		*/					\ +	/* succeed anyway. Not sure how else to handle this odd case.		*/					\ +	/* This approach is also used in llsdmessage_test.cpp. 				*/					\ +	if (std::string(typeid(ex).name()) == typeid(exception).name())							\ +	{																						\ +		threw = ex.what();																	\ +		/*std::cout << ex.what() << std::endl;*/											\ +	}																						\ +	else																					\ +	{																						\ +		/* We don't even recognize this exception. Let it propagate		*/					\ +		/* out to TUT to fail the test.									*/					\ +		throw;																				\ +	}																						\ +}																							\ +catch (...)																					\ +{																							\ +	std::cerr << "Utterly failed to catch expected exception " << #exception << "!" <<		\ +	std::endl;																				\ +	/* This indicates a problem in the test that should be addressed.   */					\ +	throw;																					\ +} + +#else // LL_LINUX +#define CATCH_MISSED_LINUX_EXCEPTION(exception, threw)										\ +	/* Not needed on other platforms */ +#endif // LL_LINUX +  template<typename T> -T make(const T& value) { return value; } +T make(const T& value) +{ +	return value; +}  /***************************************************************************** -*   tut test group -*****************************************************************************/ + *   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); +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 +	std::string threw; +	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 = e.what(); +	} +	CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::DupListenerName, threw) +	ensure_equals(threw, +				  std::string("DupListenerName: " +							  "Attempt to register duplicate listener name '") + +							  listener0.getName() + "' on " + typeid(per_frame).name() + +							  " '" + per_frame.getName() + "'"); +	// 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'; +	} +	CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::Cycle, threw) +	// 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'; +	} +	CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::OrderChange, threw) +	// 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'"); +	// std::cout << "Thrown Exception: " << threw << std::endl; +	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"); +		std::string threw; +		try +		{ +			// then another with a duplicate name. +			LLEventStream bob2("bob"); +		} +		catch (const LLEventPump::DupPumpName& e) +		{ +			threw = e.what(); +			// std::cout << "Caught: " << e.what() << '\n'; +		} +		CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::DupPumpName, threw) +		ensure("Caught DupPumpName", !threw.empty()); +	} 	// 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); +	std::string threw; +	try +	{ +		LLListenerOrPumpName empty; +		empty(17); +	} +	catch (const LLListenerOrPumpName::Empty& e) +	{ +		threw = e.what(); +	} +	CATCH_MISSED_LINUX_EXCEPTION(LLListenerOrPumpName::Empty, threw) + +	ensure("threw Empty", !threw.empty()); +} + +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()); +	// 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); +	// 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...))"); +} + +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. +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; +	 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); +	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 diff --git a/indra/test/llhttpclient_tut.cpp b/indra/test/llhttpclient_tut.cpp index 03759001ae..4b4046632c 100644 --- a/indra/test/llhttpclient_tut.cpp +++ b/indra/test/llhttpclient_tut.cpp @@ -40,6 +40,7 @@  #include "llhttpclient.h"  #include "llformat.h"  #include "llpipeutil.h" +#include "llproxy.h"  #include "llpumpio.h"  #include "llsdhttpserver.h" @@ -85,9 +86,10 @@ namespace tut  		HTTPClientTestData()  		{  			apr_pool_create(&mPool, NULL); +			LLCurl::initClass(false);  			mServerPump = new LLPumpIO(mPool);  			mClientPump = new LLPumpIO(mPool); -			 +  			LLHTTPClient::setPump(*mClientPump);  		} @@ -95,6 +97,7 @@ namespace tut  		{  			delete mServerPump;  			delete mClientPump; +			LLProxy::cleanupClass();  			apr_pool_destroy(mPool);  		} diff --git a/indra/test/llsd_new_tut.cpp b/indra/test/llsd_new_tut.cpp index dd93b36f04..b2fa54a688 100644 --- a/indra/test/llsd_new_tut.cpp +++ b/indra/test/llsd_new_tut.cpp @@ -5,7 +5,7 @@   *   * $LicenseInfo:firstyear=2006&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2006-2011, Linden Research, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -32,6 +32,19 @@  #include "llsdtraits.h"  #include "llstring.h" +#if LL_WINDOWS +#include <float.h> +namespace +{ +	int fpclassify(double x) +	{ +		return _fpclass(x); +	} +} +#else +using std::fpclassify; +#endif +  namespace tut  {  	class SDCleanupCheck @@ -218,19 +231,16 @@ namespace tut  		}  		else  		{ -// TODO: Fix on windows.... -#ifndef LL_WINDOWS -# if !defined(fpclassify) && __GNUC__ >= 3 -#   define FPCLASSIFY_NAMESPACE std:: -# else -#   define FPCLASSIFY_NAMESPACE -# endif -			int left  = FPCLASSIFY_NAMESPACE fpclassify(v.asReal()); -			int right = FPCLASSIFY_NAMESPACE fpclassify(eReal); +			int left  = fpclassify(v.asReal()); +			int right = fpclassify(eReal);  			ensure_equals(s+" to real", 	left, 			right); -			ensure_equals(s+" to string",	v.asString(),	eString); -#endif +			// ensure_equals(s+" to string", v.asString(), eString); +			// I've commented this check out, since there doesn't +			// seem to be uniform string representation for NaN on +			// all platforms. For example, on my Ubuntu 8.10 laptop +			// with libc 2.11.1, sqrt(-1.0) will return '-nan', not +			// 'nan'.  		}  	} @@ -742,6 +752,42 @@ namespace tut  			LLSD w = v;  			w = "nice day";  		} + +		{ +			SDAllocationCheck check("shared values test for threaded work", 9); + +			//U32 start_llsd_count = LLSD::outstandingCount(); + +			LLSD m = LLSD::emptyMap(); + +			m["one"] = 1; +			m["two"] = 2; +			m["one_copy"] = m["one"];			// 3 (m, "one" and "two") + +			m["undef_one"] = LLSD(); +			m["undef_two"] = LLSD(); +			m["undef_one_copy"] = m["undef_one"]; + +			{	// Ensure first_array gets freed to avoid counting it +				LLSD first_array = LLSD::emptyArray(); +				first_array.append(1.0f); +				first_array.append(2.0f);			 +				first_array.append(3.0f);			// 7 + +				m["array"] = first_array; +				m["array_clone"] = first_array; +				m["array_copy"] = m["array"];		// 7 +			} + +			m["string_one"] = "string one value"; +			m["string_two"] = "string two value"; +			m["string_one_copy"] = m["string_one"];		// 9 + +			//U32 llsd_object_count = LLSD::outstandingCount(); +			//std::cout << "Using " << (llsd_object_count - start_llsd_count) << " LLSD objects" << std::endl; + +			//m.dumpStats(); +		}  	}  	template<> template<> @@ -769,4 +815,3 @@ namespace tut  		test serializations  	*/  } - diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp index cc6f78decd..be0692557a 100644 --- a/indra/test/llsdmessagebuilder_tut.cpp +++ b/indra/test/llsdmessagebuilder_tut.cpp @@ -33,6 +33,7 @@  #include "llsdmessagebuilder.h"  #include "llsdmessagereader.h"  #include "llsdtraits.h" +#include "llmath.h"  #include "llquaternion.h"  #include "u64.h"  #include "v3dmath.h" @@ -86,17 +87,17 @@ namespace tut  			return createTemplateBlock(_PREHASH_Test0, type, size, block);  		} -		static LLMessageBlock* createTemplateBlock(char* name, const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE) +		static LLMessageBlock* createTemplateBlock(const char* name, const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE)  		{  			LLMessageBlock* result = new LLMessageBlock(name, block);  			if(type != MVT_NULL)  			{ -				result->addVariable(_PREHASH_Test0, type, size); +				result->addVariable(const_cast<char*>(_PREHASH_Test0), type, size);  			}  			return result;  		} -		static LLTemplateMessageBuilder* defaultTemplateBuilder(LLMessageTemplate& messageTemplate, char* name = _PREHASH_Test0) +		static LLTemplateMessageBuilder* defaultTemplateBuilder(LLMessageTemplate& messageTemplate, char* name = const_cast<char*>(_PREHASH_Test0))  		{  			templateNameMap[_PREHASH_TestMessage] = &messageTemplate;  			LLTemplateMessageBuilder* builder = new LLTemplateMessageBuilder(templateNameMap); diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp index 09beb53869..6e1c82bb24 100644 --- a/indra/test/lltemplatemessagebuilder_tut.cpp +++ b/indra/test/lltemplatemessagebuilder_tut.cpp @@ -31,6 +31,7 @@  #include "llapr.h"  #include "llmessagetemplate.h" +#include "llmath.h"  #include "llquaternion.h"  #include "lltemplatemessagebuilder.h"  #include "lltemplatemessagereader.h" @@ -75,7 +76,7 @@ namespace tut  		static LLMessageBlock* defaultBlock(const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE)  		{ -			return createBlock(_PREHASH_Test0, type, size, block); +			return createBlock(const_cast<char*>(_PREHASH_Test0), type, size, block);  		}  		static LLMessageBlock* createBlock(char* name, const EMsgVariableType type = MVT_NULL, const S32 size = 0, EMsgBlockType block = MBT_VARIABLE) @@ -83,12 +84,12 @@ namespace tut  			LLMessageBlock* result = new LLMessageBlock(name, block);  			if(type != MVT_NULL)  			{ -				result->addVariable(_PREHASH_Test0, type, size); +				result->addVariable(const_cast<char*>(_PREHASH_Test0), type, size);  			}  			return result;  		} -		static LLTemplateMessageBuilder* defaultBuilder(LLMessageTemplate& messageTemplate, char* name = _PREHASH_Test0) +		static LLTemplateMessageBuilder* defaultBuilder(LLMessageTemplate& messageTemplate, char* name = const_cast<char*>(_PREHASH_Test0))  		{  			nameMap[_PREHASH_TestMessage] = &messageTemplate;  			LLTemplateMessageBuilder* builder = new LLTemplateMessageBuilder(nameMap); @@ -403,11 +404,11 @@ namespace tut  		// build template: Test0 before Test1  		LLMessageTemplate messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4, MBT_SINGLE)); -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));  		// build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb -		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, _PREHASH_Test0); +		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));  		builder->addU32(_PREHASH_Test0, 0xaaaa);  		builder->nextBlock(_PREHASH_Test1);  		builder->addU32(_PREHASH_Test0, 0xbbbb); @@ -416,11 +417,11 @@ namespace tut  		// build template: Test1 before Test0  		messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4, MBT_SINGLE)); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));  		// build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb -		builder = defaultBuilder(messageTemplate, _PREHASH_Test1); +		builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test1));  		builder->addU32(_PREHASH_Test0, 0xaaaa);  		builder->nextBlock(_PREHASH_Test0);  		builder->addU32(_PREHASH_Test0, 0xbbbb); @@ -443,11 +444,11 @@ namespace tut  		// build template: Test0 before Test1  		LLMessageTemplate messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4, MBT_SINGLE)); -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));  		// build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb -		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, _PREHASH_Test0); +		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));  		builder->addU32(_PREHASH_Test0, 0xaaaa);  		builder->nextBlock(_PREHASH_Test1);  		builder->addU32(_PREHASH_Test0, 0xbbbb); @@ -455,7 +456,7 @@ namespace tut  		delete builder;  		// build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb -		builder = defaultBuilder(messageTemplate, _PREHASH_Test1); +		builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test1));  		builder->addU32(_PREHASH_Test0, 0xbbbb);  		builder->nextBlock(_PREHASH_Test0);  		builder->addU32(_PREHASH_Test0, 0xaaaa); @@ -478,21 +479,21 @@ namespace tut  		// Build template: Test0 only  		LLMessageTemplate messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));  		// Build message -		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, _PREHASH_Test0); +		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));  		builder->addU32(_PREHASH_Test0, 0xaaaa);  		bufferSize1 = builder->buildMessage(buffer1, MAX_BUFFER_SIZE, 0);  		delete builder;  		// Build template: Test0 before Test1  		messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4, MBT_SINGLE)); -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));  		// Build message -		builder = defaultBuilder(messageTemplate, _PREHASH_Test0); +		builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));  		builder->addU32(_PREHASH_Test0, 0xaaaa);  		builder->nextBlock(_PREHASH_Test1);  		builder->addU32(_PREHASH_Test0, 0xbbbb); @@ -511,8 +512,8 @@ namespace tut  		U32 inTest00 = 0, inTest01 = 1, inTest1 = 2;  		U32 outTest00, outTest01, outTest1;  		LLMessageTemplate messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4)); -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4));  		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);  		builder->addU32(_PREHASH_Test0, inTest00);  		builder->nextBlock(_PREHASH_Test0); @@ -536,15 +537,15 @@ namespace tut  		U32 inTest = 1, outTest;  		LLMessageTemplate messageTemplate = defaultTemplate();  		messageTemplate.addBlock( -			createBlock(_PREHASH_Test0, MVT_U32, 4, MBT_SINGLE)); -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4)); +			createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4));  		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);  		builder->addU32(_PREHASH_Test0, inTest);  		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);  		reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest); -		S32 blockCount = reader->getNumberOfBlocks(_PREHASH_Test1); +		S32 blockCount = reader->getNumberOfBlocks(const_cast<char*>(_PREHASH_Test1));  		ensure_equals("Ensure block count", blockCount, 0);  		ensure_equals("Ensure Test0", inTest, outTest);  		delete reader; @@ -556,7 +557,7 @@ namespace tut  	{  		// build template  		LLMessageTemplate messageTemplate = defaultTemplate(); -		messageTemplate.addBlock(createBlock(_PREHASH_Test0, MVT_U32, 4)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4));  		// build message  		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate); @@ -881,7 +882,7 @@ namespace tut  		delete builder;  		// add block to reader template -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4, MBT_SINGLE)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));  		// read message value and default value  		numberMap[1] = &messageTemplate; @@ -914,7 +915,7 @@ namespace tut  		delete builder;  		// add variable block to reader template -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_U32, 4)); +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4));  		// read message value and check block repeat count  		numberMap[1] = &messageTemplate; @@ -947,7 +948,7 @@ namespace tut  		delete builder;  		// add variable block to reader template -		messageTemplate.addBlock(createBlock(_PREHASH_Test1, MVT_VARIABLE, 4,  +		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_VARIABLE, 4,  											 MBT_SINGLE));  		// read message value and default string | 
