diff options
Diffstat (limited to 'indra/test')
-rw-r--r-- | indra/test/CMakeLists.txt | 59 | ||||
-rw-r--r-- | indra/test/debug.h | 68 | ||||
-rwxr-xr-x | indra/test/lldoubledispatch_tut.cpp | 245 | ||||
-rw-r--r-- | indra/test/llevents_tut.cpp | 722 | ||||
-rw-r--r-- | indra/test/llhttpclient_tut.cpp | 4 | ||||
-rw-r--r-- | indra/test/llhttpdate_tut.cpp | 72 | ||||
-rw-r--r-- | indra/test/llpermissions_tut.cpp | 11 | ||||
-rw-r--r-- | indra/test/llsaleinfo_tut.cpp | 15 | ||||
-rw-r--r-- | indra/test/llscriptresource_tut.cpp | 7 | ||||
-rwxr-xr-x | indra/test/llsdmessagebuilder_tut.cpp | 52 | ||||
-rwxr-xr-x | indra/test/llsdmessagereader_tut.cpp | 1 | ||||
-rw-r--r-- | indra/test/llsdutil_tut.cpp | 235 | ||||
-rw-r--r-- | indra/test/lltimestampcache_tut.cpp | 7 | ||||
-rw-r--r-- | indra/test/lltranscode_tut.cpp | 7 | ||||
-rw-r--r-- | indra/test/lltut.cpp | 12 | ||||
-rw-r--r-- | indra/test/lltut.h | 5 | ||||
-rw-r--r-- | indra/test/test.cpp | 43 | ||||
-rw-r--r-- | indra/test/test.h | 5 |
18 files changed, 1454 insertions, 116 deletions
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index c8682c8ea7..c1360987a5 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -14,6 +14,8 @@ include(LScript) include(Linking) include(Tut) +include(GoogleMock) + include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLDATABASE_INCLUDE_DIRS} @@ -23,67 +25,44 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} + ${GOOGLEMOCK_INCLUDE_DIRS} ) set(test_SOURCE_FILES - common.cpp - inventory.cpp io.cpp # llapp_tut.cpp # Temporarily removed until thread issues can be solved - llbase64_tut.cpp llblowfish_tut.cpp llbuffer_tut.cpp - lldate_tut.cpp - llerror_tut.cpp - llhost_tut.cpp + lldoubledispatch_tut.cpp + llevents_tut.cpp llhttpdate_tut.cpp llhttpclient_tut.cpp llhttpnode_tut.cpp - llinventoryparcel_tut.cpp lliohttpserver_tut.cpp - lljoint_tut.cpp - llmime_tut.cpp llmessageconfig_tut.cpp - llmodularmath_tut.cpp - llnamevalue_tut.cpp llpermissions_tut.cpp llpipeutil.cpp - llquaternion_tut.cpp - llrandom_tut.cpp llsaleinfo_tut.cpp llscriptresource_tut.cpp llsdmessagebuilder_tut.cpp llsdmessagereader_tut.cpp llsd_new_tut.cpp - llsdserialize_tut.cpp llsdutil_tut.cpp llservicebuilder_tut.cpp llstreamtools_tut.cpp - llstring_tut.cpp lltemplatemessagebuilder_tut.cpp lltimestampcache_tut.cpp - lltiming_tut.cpp lltranscode_tut.cpp lltut.cpp - lluri_tut.cpp lluuidhashmap_tut.cpp - llxfer_tut.cpp - math.cpp message_tut.cpp - reflection_tut.cpp test.cpp - v2math_tut.cpp - v3color_tut.cpp - v3dmath_tut.cpp - v3math_tut.cpp - v4color_tut.cpp - v4coloru_tut.cpp - v4math_tut.cpp ) set(test_HEADER_FILES CMakeLists.txt + debug.h llpipeutil.h llsdtraits.h lltut.h @@ -104,7 +83,7 @@ endif (NOT DARWIN) set_source_files_properties(${test_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) -list(APPEND test_SOURC_FILES ${test_HEADER_FILES}) +list(APPEND test_SOURCE_FILES ${test_HEADER_FILES}) add_executable(test ${test_SOURCE_FILES}) @@ -117,10 +96,15 @@ target_link_libraries(test ${LLXML_LIBRARIES} ${LSCRIPT_LIBRARIES} ${LLCOMMON_LIBRARIES} + ${EXPAT_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} ${APRICONV_LIBRARIES} ${PTHREAD_LIBRARY} ${WINDOWS_LIBRARIES} + ${BOOST_PROGRAM_OPTIONS_LIBRARY} + ${BOOST_REGEX_LIBRARY} ${DL_LIBRARY} + ${GOOGLE_PERFTOOLS_LIBRARIES} ) if (WINDOWS) @@ -133,16 +117,23 @@ endif (WINDOWS) get_target_property(TEST_EXE test LOCATION) -add_custom_command( +IF(WINDOWS) + set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}) +ELSEIF(DARWIN) + set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources:/usr/lib) +ELSE(WINDOWS) + set(LD_LIBRARY_PATH ${SHARED_LIB_STAGING_DIR}:/usr/lib) +ENDIF(WINDOWS) + +LL_TEST_COMMAND("${LD_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 ${TEST_EXE} - ARGS - --output=${CMAKE_CURRENT_BINARY_DIR}/cpp_test_results.txt - --touch=${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt + COMMAND ${LL_TEST_COMMAND_value} DEPENDS test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "C++ unit tests" - ) + ) set(test_results ${CMAKE_CURRENT_BINARY_DIR}/cpp_tests_ok.txt) diff --git a/indra/test/debug.h b/indra/test/debug.h new file mode 100644 index 0000000000..a00659d880 --- /dev/null +++ b/indra/test/debug.h @@ -0,0 +1,68 @@ +/** + * @file debug.h + * @author Nat Goodspeed + * @date 2009-05-28 + * @brief Debug output for unit test code + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_DEBUG_H) +#define LL_DEBUG_H + +#include <iostream> + +/***************************************************************************** +* Debugging stuff +*****************************************************************************/ +// This class is intended to illuminate entry to a given block, exit from the +// same block and checkpoints along the way. It also provides a convenient +// place to turn std::cout output on and off. +class Debug +{ +public: + Debug(const std::string& block): + mBlock(block) + { + (*this)("entry"); + } + + ~Debug() + { + (*this)("exit"); + } + + void operator()(const std::string& status) + { +#if defined(DEBUG_ON) + std::cout << mBlock << ' ' << status << std::endl; +#endif + } + +private: + const std::string mBlock; +}; + +// It's often convenient to use the name of the enclosing function as the name +// of the Debug block. +#define DEBUG Debug debug(__FUNCTION__) + +// These BEGIN/END macros are specifically for debugging output -- please +// don't assume you must use such for coroutines in general! They only help to +// make control flow (as well as exception exits) explicit. +#define BEGIN \ +{ \ + DEBUG; \ + try + +#define END \ + catch (...) \ + { \ + debug("*** exceptional "); \ + throw; \ + } \ +} + +#endif /* ! defined(LL_DEBUG_H) */ diff --git a/indra/test/lldoubledispatch_tut.cpp b/indra/test/lldoubledispatch_tut.cpp new file mode 100755 index 0000000000..63ef4d4497 --- /dev/null +++ b/indra/test/lldoubledispatch_tut.cpp @@ -0,0 +1,245 @@ +/** + * @file lldoubledispatch_tut.cpp + * @author Nat Goodspeed + * @date 2008-11-13 + * @brief Test for lldoubledispatch.h + * + * This program tests the DoubleDispatch class, using a variation on the example + * from Scott Meyers' "More Effective C++", Item 31. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, 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$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lldoubledispatch.h" +// STL headers +// std headers +#include <string> +#include <iostream> +#include <typeinfo> +// external library headers +// other Linden headers +#include "lltut.h" + + +/*---------------------------- Class hierarchy -----------------------------*/ +// All objects are GameObjects. +class GameObject +{ +public: + GameObject(const std::string& name): mName(name) {} + virtual ~GameObject() {} + virtual std::string stringize() { return std::string(typeid(*this).name()) + " " + mName; } + +protected: + std::string mName; +}; + +// SpaceStation, Asteroid and SpaceShip are peer GameObjects. +struct SpaceStation: public GameObject +{ + SpaceStation(const std::string& name): GameObject(name) {} + // Only a dummy SpaceStation is constructed without a name + SpaceStation(): GameObject("dummy") {} +}; + +struct Asteroid: public GameObject +{ + Asteroid(const std::string& name): GameObject(name) {} + Asteroid(): GameObject("dummy") {} +}; + +struct SpaceShip: public GameObject +{ + SpaceShip(const std::string& name): GameObject(name) {} + SpaceShip(): GameObject("dummy") {} +}; + +// SpaceShip is specialized further into CommercialShip and MilitaryShip. +struct CommercialShip: public SpaceShip +{ + CommercialShip(const std::string& name): SpaceShip(name) {} + CommercialShip(): SpaceShip("dummy") {} +}; + +struct MilitaryShip: public SpaceShip +{ + MilitaryShip(const std::string& name): SpaceShip(name) {} + MilitaryShip(): SpaceShip("dummy") {} +}; + +/*-------------------------- Collision functions ---------------------------*/ +// This mechanism permits us to overcome a limitation of Meyers' approach: we +// can declare the parameter types exactly as we want, rather than having to +// make them all GameObject& parameters. +std::string shipAsteroid(SpaceShip& ship, Asteroid& rock) +{ +// std::cout << rock.stringize() << " has pulverized " << ship.stringize() << std::endl; + return "shipAsteroid"; +} + +std::string militaryShipAsteroid(MilitaryShip& ship, Asteroid& rock) +{ +// std::cout << rock.stringize() << " has severely damaged " << ship.stringize() << std::endl; + return "militaryShipAsteroid"; +} + +std::string shipStation(SpaceShip& ship, SpaceStation& dock) +{ +// std::cout << ship.stringize() << " has docked at " << dock.stringize() << std::endl; + return "shipStation"; +} + +std::string asteroidStation(Asteroid& rock, SpaceStation& dock) +{ +// std::cout << rock.stringize() << " has damaged " << dock.stringize() << std::endl; + return "asteroidStation"; +} + +/*------------------------------- Test code --------------------------------*/ +namespace tut +{ + struct dispatch_data + { + dispatch_data(): + home(new SpaceStation("Terra Station")), + obstacle(new Asteroid("Ganymede")), + tug(new CommercialShip("Pilotfish")), + patrol(new MilitaryShip("Enterprise")) + {} + + // Instantiate and populate the DoubleDispatch object. + typedef LLDoubleDispatch<std::string, GameObject> DD; + DD dispatcher; + + // Instantiate a few GameObjects. Make sure we refer to them + // polymorphically, and don't let them leak. + std::auto_ptr<GameObject> home; + std::auto_ptr<GameObject> obstacle; + std::auto_ptr<GameObject> tug; + std::auto_ptr<GameObject> patrol; + + // prototype objects + Asteroid dummyAsteroid; + SpaceShip dummyShip; + MilitaryShip dummyMilitary; + CommercialShip dummyCommercial; + SpaceStation dummyStation; + }; + typedef test_group<dispatch_data> dispatch_group; + typedef dispatch_group::object dispatch_object; + tut::dispatch_group ddgr("double dispatch"); + + template<> template<> + void dispatch_object::test<1>() + { + // Describe param types using explicit DD::Type objects + // (order-sensitive add() variant) + dispatcher.add(DD::Type<SpaceShip>(), DD::Type<Asteroid>(), shipAsteroid, true); + // naive adding, won't work + dispatcher.add(DD::Type<MilitaryShip>(), DD::Type<Asteroid>(), militaryShipAsteroid, true); + dispatcher.add(DD::Type<SpaceShip>(), DD::Type<SpaceStation>(), shipStation, true); + dispatcher.add(DD::Type<Asteroid>(), DD::Type<SpaceStation>(), asteroidStation, true); + + // Try colliding them. + ensure_equals(dispatcher(*home, *tug), // reverse params, SpaceShip subclass + "shipStation"); + ensure_equals(dispatcher(*patrol, *home), // forward params, SpaceShip subclass + "shipStation"); + ensure_equals(dispatcher(*obstacle, *home), // forward params + "asteroidStation"); + ensure_equals(dispatcher(*home, *obstacle), // reverse params + "asteroidStation"); + ensure_equals(dispatcher(*tug, *obstacle), // forward params, SpaceShip subclass + "shipAsteroid"); + ensure_equals(dispatcher(*obstacle, *patrol), // reverse params, SpaceShip subclass + // won't use militaryShipAsteroid() because it was added + // in wrong order + "shipAsteroid"); + } + + template<> template<> + void dispatch_object::test<2>() + { + // Describe param types using explicit DD::Type objects + // (order-sensitive add() variant) + // adding in correct order + dispatcher.add(DD::Type<MilitaryShip>(), DD::Type<Asteroid>(), militaryShipAsteroid, true); + dispatcher.add(DD::Type<SpaceShip>(), DD::Type<Asteroid>(), shipAsteroid, true); + dispatcher.add(DD::Type<SpaceShip>(), DD::Type<SpaceStation>(), shipStation, true); + dispatcher.add(DD::Type<Asteroid>(), DD::Type<SpaceStation>(), asteroidStation, true); + + ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid"); + ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid"); + } + + template<> template<> + void dispatch_object::test<3>() + { + // Describe param types with actual prototype instances + // (order-insensitive add() variant) + dispatcher.add(dummyMilitary, dummyAsteroid, militaryShipAsteroid); + dispatcher.add(dummyShip, dummyAsteroid, shipAsteroid); + dispatcher.add(dummyShip, dummyStation, shipStation); + dispatcher.add(dummyAsteroid, dummyStation, asteroidStation); + + ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid"); + ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid"); + ensure_equals(dispatcher(*obstacle, *patrol), ""); + } + + template<> template<> + void dispatch_object::test<4>() + { + // Describe param types with actual prototype instances + // (order-insensitive add() variant) + dispatcher.add(dummyShip, dummyAsteroid, shipAsteroid); + // Even if we add the militaryShipAsteroid in the wrong order, it + // should still work. + dispatcher.add(dummyMilitary, dummyAsteroid, militaryShipAsteroid); + dispatcher.add(dummyShip, dummyStation, shipStation); + dispatcher.add(dummyAsteroid, dummyStation, asteroidStation); + + ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid"); + ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid"); + } + + template<> template<> + void dispatch_object::test<5>() + { + dispatcher.add<SpaceShip, Asteroid>(shipAsteroid); + dispatcher.add<MilitaryShip, Asteroid>(militaryShipAsteroid); + dispatcher.add<SpaceShip, SpaceStation>(shipStation); + dispatcher.add<Asteroid, SpaceStation>(asteroidStation); + + ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid"); + ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid"); + } +} // namespace tut diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp new file mode 100644 index 0000000000..e58b10ce07 --- /dev/null +++ b/indra/test/llevents_tut.cpp @@ -0,0 +1,722 @@ +/** + * @file llevents_tut.cpp + * @author Nat Goodspeed + * @date 2008-09-12 + * @brief Test of llevents.h + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * Copyright (c) 2008, Linden Research, Inc. + * $/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 diff --git a/indra/test/llhttpclient_tut.cpp b/indra/test/llhttpclient_tut.cpp index d1bf8ae5a9..c541997e89 100644 --- a/indra/test/llhttpclient_tut.cpp +++ b/indra/test/llhttpclient_tut.cpp @@ -59,8 +59,8 @@ namespace tut class LLSDStorageNode : public LLHTTPNode { public: - LLSD get() const { return storage; } - LLSD put(const LLSD& value) const { storage = value; return LLSD(); } + LLSD simpleGet() const { return storage; } + LLSD simplePut(const LLSD& value) const { storage = value; return LLSD(); } }; class ErrorNode : public LLHTTPNode diff --git a/indra/test/llhttpdate_tut.cpp b/indra/test/llhttpdate_tut.cpp index b764696dae..8762938186 100644 --- a/indra/test/llhttpdate_tut.cpp +++ b/indra/test/llhttpdate_tut.cpp @@ -37,6 +37,9 @@ #include "lldate.h" #include "llframetimer.h" +#include <time.h> +#include <locale.h> + namespace tut { struct httpdate_data @@ -50,6 +53,7 @@ namespace tut template<> template<> void httpdate_object::test<1>() { + static std::string epoch_expected = "Thursday, 01 Jan 1970 00:00:00 GMT" ; ensure("Check Epoch in RFC 1123", ( epoch_expected == some_date.asRFC1123())); } @@ -57,6 +61,7 @@ namespace tut template<> template<> void httpdate_object::test<2>() { + static std::string expected = "Wednesday, 18 Jul 2007 22:17:24 GMT" ; some_date = LLDate(1184797044.037586); ensure("Check some timestamp in RFC 1123", ( expected == some_date.asRFC1123())); @@ -66,6 +71,7 @@ namespace tut template<> template<> void httpdate_object::test<3>() { + //F64 sometime = LLFrameTimer::getTotalSeconds(); time_t sometime; time(&sometime); @@ -91,4 +97,70 @@ namespace tut // probably not a good idea to use strcmp but this is just a unit test ensure("Current time in RFC 1123", (strcmp(expected, actual.c_str()) == 0)); } + + void test_date_string(const std::string &locale, struct tm *t, + const std::string &fmt, const std::string &expected) + { + std::string result = LLDate::toHTTPDateString(t, fmt); + LLStringUtil::toLower(result); + std::string label = std::string("toHTTPDateString - ") + locale; + ensure_equals(label.c_str(), result, expected); + } + + template<> template<> + void httpdate_object::test<4>() + { + // test localization of http dates +#if LL_WINDOWS + const char *en_locale = "english"; + const char *fr_locale = "french"; +#else + const char *en_locale = "en_GB.UTF-8"; + const char *fr_locale = "fr_FR.UTF-8"; +#endif + + std::string prev_locale = LLStringUtil::getLocale(); + std::string prev_clocale = std::string(setlocale(LC_TIME, NULL)); + time_t test_time = 1252374030; // 8 Sep 2009 01:40:01 + struct tm *t = gmtime(&test_time); + + setlocale(LC_TIME, en_locale); + if (strcmp(setlocale(LC_TIME, NULL), en_locale) != 0) + { + setlocale(LC_TIME, prev_clocale.c_str()); + skip("Cannot set English locale"); + } + + LLStringUtil::setLocale(en_locale); + test_date_string(en_locale, t, "%d %B %Y - %H:%M", "08 september 2009 - 01:40"); + test_date_string(en_locale, t, "%H", "01"); + test_date_string(en_locale, t, "%M", "40"); + test_date_string(en_locale, t, "%I", "01"); + test_date_string(en_locale, t, "%d", "08"); + test_date_string(en_locale, t, "%Y", "2009"); + test_date_string(en_locale, t, "%p", "am"); + test_date_string(en_locale, t, "%A", "tuesday"); + test_date_string(en_locale, t, "%B", "september"); + + setlocale(LC_TIME, fr_locale); + if (strcmp(setlocale(LC_TIME, NULL), fr_locale) != 0) + { + LLStringUtil::setLocale(prev_locale); + setlocale(LC_TIME, prev_clocale.c_str()); + skip("Cannot set French locale"); + } + + LLStringUtil::setLocale(fr_locale); + test_date_string(fr_locale, t, "%d %B %Y - %H:%M", "08 septembre 2009 - 01:40"); + test_date_string(fr_locale, t, "%H", "01"); + test_date_string(fr_locale, t, "%M", "40"); + test_date_string(fr_locale, t, "%I", "01"); + test_date_string(fr_locale, t, "%d", "08"); + test_date_string(fr_locale, t, "%Y", "2009"); + test_date_string(fr_locale, t, "%A", "mardi"); + test_date_string(fr_locale, t, "%B", "septembre"); + + LLStringUtil::setLocale(prev_locale); + setlocale(LC_TIME, prev_clocale.c_str()); + } } diff --git a/indra/test/llpermissions_tut.cpp b/indra/test/llpermissions_tut.cpp index 9dbb9642dd..4eadc64b5a 100644 --- a/indra/test/llpermissions_tut.cpp +++ b/indra/test/llpermissions_tut.cpp @@ -485,15 +485,8 @@ namespace tut template<> template<> void permission_object_t::test<22>() { - LLPermissions perm,perm1; - LLUUID creator("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); - LLUUID owner("68edcf47-ccd7-45b8-9f90-1649d7f12806"); - LLUUID lastOwner("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); - LLUUID group("9c8eca51-53d5-42a7-bb58-cef070395db8"); - perm.init(creator,owner,lastOwner,group); - LLXMLNode* xml_node = perm.exportFileXML(); - perm1.importXML(xml_node); - ensure("exportFileXML()/importXML():failed to export and import the data ", perm1 == perm); + // Deleted LLPermissions::exportFileXML() and LLPermissions::importXML() + // because I can't find any non-test code references to it. 2009-05-04 JC } template<> template<> diff --git a/indra/test/llsaleinfo_tut.cpp b/indra/test/llsaleinfo_tut.cpp index 7f8219cdc8..fa5e047513 100644 --- a/indra/test/llsaleinfo_tut.cpp +++ b/indra/test/llsaleinfo_tut.cpp @@ -167,19 +167,8 @@ namespace tut template<> template<> void llsaleinfo_test_t::test<4>() { -// LLXMLNode is teh suck. -#if 0 - S32 sale_price = 23445; - LLSaleInfo saleinfo(LLSaleInfo::FS_CONTENTS, sale_price); - - LLXMLNode* x_node = saleinfo.exportFileXML(); - - LLSaleInfo saleinfo1(LLSaleInfo::FS_NOT, 0); - - saleinfo1.importXML(x_node); - ensure_equals("1.importXML() fn failed", saleinfo.getSalePrice(), saleinfo1.getSalePrice()); - ensure_equals("2.importXML() fn failed", saleinfo.getSaleType(), saleinfo1.getSaleType()); -#endif + // Deleted LLSaleInfo::exportFileXML() and LLSaleInfo::importXML() + // because I can't find any non-test code references to it. 2009-05-04 JC } template<> template<> diff --git a/indra/test/llscriptresource_tut.cpp b/indra/test/llscriptresource_tut.cpp index e384c275a3..705fdd16ae 100644 --- a/indra/test/llscriptresource_tut.cpp +++ b/indra/test/llscriptresource_tut.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2006-2007, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp index 27ab127772..ca15314e69 100755 --- a/indra/test/llsdmessagebuilder_tut.cpp +++ b/indra/test/llsdmessagebuilder_tut.cpp @@ -44,6 +44,8 @@ #include "v3dmath.h" #include "v3math.h" #include "v4math.h" +#include "llsdutil.h" +//#include "llsdutil.cpp" #include "llsdutil_math.cpp" #include "lltemplatemessagebuilder.h" @@ -353,7 +355,7 @@ namespace tut { char binData[] = "abcdefghijklmnop"; - addValue(messageBlockData, "testBinData", &binData, MVT_FIXED, sizeof(binData)); + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_FIXED, sizeof(binData)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -393,7 +395,7 @@ namespace tut { U16 binData[] = {1,2,3,4,5,6,7,8,9}; //9 shorts - addValue(messageBlockData, "testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 1, 2); + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 1, 2); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -413,7 +415,7 @@ namespace tut { U32 binData[] = {9,8,7,6,5,4,3,2,1}; - addValue(messageBlockData, "testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 2, 4); + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 2, 4); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -433,7 +435,7 @@ namespace tut { U8 data = 0xa5; - addValue(messageBlockData, "testBinData", &data, MVT_U8, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U8, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -450,7 +452,7 @@ namespace tut { U16 data = 0xa55a; - addValue(messageBlockData, "testBinData", &data, MVT_U16, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -467,7 +469,7 @@ namespace tut { U32 data = 0xa55a7117; - addValue(messageBlockData, "testBinData", &data, MVT_U32, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U32, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -483,7 +485,7 @@ namespace tut void LLSDMessageBuilderTestObject::test<27>() { U64 data = U64L(0xa55a711711223344); - addValue(messageBlockData, "testBinData", &data, MVT_U64, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U64, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -500,7 +502,7 @@ namespace tut { S8 data = -31; - addValue(messageBlockData, "testBinData", &data, MVT_S8, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S8, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -517,7 +519,7 @@ namespace tut { S16 data = -31; - addValue(messageBlockData, "testBinData", &data, MVT_S16, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S16, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -534,7 +536,7 @@ namespace tut { S32 data = -3100; - addValue(messageBlockData, "testBinData", &data, MVT_S32, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S32, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -551,7 +553,7 @@ namespace tut { S64 data = -31003100; - addValue(messageBlockData, "testBinData", &data, MVT_S64, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S64, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -568,7 +570,7 @@ namespace tut { F32 data = 1234.1234f; - addValue(messageBlockData, "testBinData", &data, MVT_F32, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_F32, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -585,7 +587,7 @@ namespace tut { F64 data = 1234.1234; - addValue(messageBlockData, "testBinData", &data, MVT_F64, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_F64, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -602,7 +604,7 @@ namespace tut { LLVector3 data(1,2,3); - addValue(messageBlockData, "testBinData", &data, MVT_LLVector3, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector3, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -619,7 +621,7 @@ namespace tut { LLVector3d data(1,2,3); - addValue(messageBlockData, "testBinData", &data, MVT_LLVector3d, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector3d, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -637,7 +639,7 @@ namespace tut LLVector4 data(1,2,3,4); LLSD v = ll_sd_from_vector4(data); - addValue(messageBlockData, "testBinData", &data, MVT_LLVector4, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector4, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -657,7 +659,7 @@ namespace tut //we send a quaternion packed into a vec3 (w is infered) - so sizeof(vec) == 12 bytes not 16. LLVector3 vec = data.packToVector3(); - addValue(messageBlockData, "testBinData", &vec, MVT_LLQuaternion, sizeof(vec)); + addValue(messageBlockData, (char *)"testBinData", &vec, MVT_LLQuaternion, sizeof(vec)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -674,7 +676,7 @@ namespace tut { LLUUID data("01234567-0123-0123-0123-234567abcdef"); - addValue(messageBlockData, "testBinData", &data, MVT_LLUUID, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLUUID, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -696,8 +698,8 @@ namespace tut LLMsgData* md = new LLMsgData("testMessage"); LLMsgBlkData* mbd = new LLMsgBlkData("testBlock", 0); - addValue(mbd, "testBoolFalse", &valueFalse, MVT_BOOL, sizeof(BOOL)); - addValue(mbd, "testBoolTrue", &valueTrue, MVT_BOOL, sizeof(BOOL)); + addValue(mbd, (char *)"testBoolFalse", &valueFalse, MVT_BOOL, sizeof(BOOL)); + addValue(mbd, (char *)"testBoolTrue", &valueTrue, MVT_BOOL, sizeof(BOOL)); md->addBlock(mbd); LLSDMessageBuilder builder = defaultBuilder(); @@ -715,7 +717,7 @@ namespace tut U32 data(0xff887766); LLSD v = ll_sd_from_ipaddr(data); - addValue(messageBlockData, "testBinData", &data, MVT_IP_ADDR, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_IP_ADDR, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -732,7 +734,7 @@ namespace tut { U16 data = 0xff88; - addValue(messageBlockData, "testBinData", &data, MVT_IP_PORT, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_IP_PORT, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -749,7 +751,7 @@ namespace tut { U16 data[3] = {0,1,2}; - addValue(messageBlockData, "testBinData", &data, MVT_U16Vec3, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16Vec3, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -769,7 +771,7 @@ namespace tut { U16 data[4] = {0,1,2,4}; - addValue(messageBlockData, "testBinData", &data, MVT_U16Quat, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16Quat, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -789,7 +791,7 @@ namespace tut { S16 data[19] = {0,-1,2,-4,5,-6,7,-8,9,-10,11,-12,13,-14,15,16,17,18}; - addValue(messageBlockData, "testBinData", &data, MVT_S16Array, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S16Array, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); diff --git a/indra/test/llsdmessagereader_tut.cpp b/indra/test/llsdmessagereader_tut.cpp index 36cfe5ebfc..f11e148cca 100755 --- a/indra/test/llsdmessagereader_tut.cpp +++ b/indra/test/llsdmessagereader_tut.cpp @@ -42,6 +42,7 @@ #include "message.h" #include "llsdmessagereader.h" #include "llsdutil.h" +#include "llsdutil_math.h" namespace tut { diff --git a/indra/test/llsdutil_tut.cpp b/indra/test/llsdutil_tut.cpp index 0c4bbc2e62..aebb1f9770 100644 --- a/indra/test/llsdutil_tut.cpp +++ b/indra/test/llsdutil_tut.cpp @@ -44,12 +44,42 @@ #include "v4math.h" #include "llquaternion.h" #include "llsdutil.h" - +#include "llsdutil_math.h" +#include "stringize.h" +#include <set> +#include <boost/range.hpp> namespace tut { struct llsdutil_data { + void test_matches(const std::string& proto_key, const LLSD& possibles, + const char** begin, const char** end) + { + std::set<std::string> succeed(begin, end); + LLSD prototype(possibles[proto_key]); + for (LLSD::map_const_iterator pi(possibles.beginMap()), pend(possibles.endMap()); + pi != pend; ++pi) + { + std::string match(llsd_matches(prototype, pi->second)); + std::set<std::string>::const_iterator found = succeed.find(pi->first); + if (found != succeed.end()) + { + // This test is supposed to succeed. Comparing to the + // empty string ensures that if the test fails, it will + // display the string received so we can tell what failed. + ensure_equals("match", match, ""); + } + else + { + // This test is supposed to fail. If we get a false match, + // the string 'match' will be empty, which doesn't tell us + // much about which case went awry. So construct a more + // detailed description string. + ensure(proto_key + " shouldn't match " + pi->first, ! match.empty()); + } + } + } }; typedef test_group<llsdutil_data> llsdutil_test;; typedef llsdutil_test::object llsdutil_object; @@ -159,4 +189,207 @@ namespace tut LLSD sd1 = ll_sd_from_color4(c1); ensure_equals("sd -> LLColor4 -> sd", sd, sd1); } + + template<> template<> + void llsdutil_object::test<9>() + { + set_test_name("llsd_matches"); + + // for this test, construct a map of all possible LLSD types + LLSD map; + map.insert("empty", LLSD()); + map.insert("Boolean", LLSD::Boolean()); + map.insert("Integer", LLSD::Integer(0)); + map.insert("Real", LLSD::Real(0.0)); + map.insert("String", LLSD::String("bah")); + map.insert("NumString", LLSD::String("1")); + map.insert("UUID", LLSD::UUID()); + map.insert("Date", LLSD::Date()); + map.insert("URI", LLSD::URI()); + map.insert("Binary", LLSD::Binary()); + map.insert("Map", LLSD().with("foo", LLSD())); + // Only an empty array can be constructed on the fly + LLSD array; + array.append(LLSD()); + map.insert("Array", array); + + // These iterators are declared outside our various for loops to avoid + // fatal MSVC warning: "I used to be broken, but I'm all better now!" + LLSD::map_const_iterator mi, mend(map.endMap()); + + /*-------------------------- llsd_matches --------------------------*/ + + // empty prototype matches anything + for (mi = map.beginMap(); mi != mend; ++mi) + { + ensure_equals(std::string("empty matches ") + mi->first, llsd_matches(LLSD(), mi->second), ""); + } + + LLSD proto_array, data_array; + for (int i = 0; i < 3; ++i) + { + proto_array.append(LLSD()); + data_array.append(LLSD()); + } + + // prototype array matches only array + for (mi = map.beginMap(); mi != mend; ++mi) + { + ensure(std::string("array doesn't match ") + mi->first, + ! llsd_matches(proto_array, mi->second).empty()); + } + + // data array must be at least as long as prototype array + proto_array.append(LLSD()); + ensure_equals("data array too short", llsd_matches(proto_array, data_array), + "Array size 4 required instead of Array size 3"); + data_array.append(LLSD()); + ensure_equals("data array just right", llsd_matches(proto_array, data_array), ""); + data_array.append(LLSD()); + ensure_equals("data array longer", llsd_matches(proto_array, data_array), ""); + + // array element matching + data_array[0] = LLSD::String(); + ensure_equals("undefined prototype array entry", llsd_matches(proto_array, data_array), ""); + proto_array[0] = LLSD::Binary(); + ensure_equals("scalar prototype array entry", llsd_matches(proto_array, data_array), + "[0]: Binary required instead of String"); + data_array[0] = LLSD::Binary(); + ensure_equals("matching prototype array entry", llsd_matches(proto_array, data_array), ""); + + // build a coupla maps + LLSD proto_map, data_map; + data_map["got"] = LLSD(); + data_map["found"] = LLSD(); + for (LLSD::map_const_iterator dmi(data_map.beginMap()), dmend(data_map.endMap()); + dmi != dmend; ++dmi) + { + proto_map[dmi->first] = dmi->second; + } + proto_map["foo"] = LLSD(); + proto_map["bar"] = LLSD(); + + // prototype map matches only map + for (mi = map.beginMap(); mi != mend; ++mi) + { + ensure(std::string("map doesn't match ") + mi->first, + ! llsd_matches(proto_map, mi->second).empty()); + } + + // data map must contain all keys in prototype map + std::string error(llsd_matches(proto_map, data_map)); + ensure_contains("missing keys", error, "missing keys"); + ensure_contains("missing foo", error, "foo"); + ensure_contains("missing bar", error, "bar"); + ensure_does_not_contain("found found", error, "found"); + ensure_does_not_contain("got got", error, "got"); + data_map["bar"] = LLSD(); + error = llsd_matches(proto_map, data_map); + ensure_contains("missing foo", error, "foo"); + ensure_does_not_contain("got bar", error, "bar"); + data_map["foo"] = LLSD(); + ensure_equals("data map just right", llsd_matches(proto_map, data_map), ""); + data_map["extra"] = LLSD(); + ensure_equals("data map with extra", llsd_matches(proto_map, data_map), ""); + + // map element matching + data_map["foo"] = LLSD::String(); + ensure_equals("undefined prototype map entry", llsd_matches(proto_map, data_map), ""); + proto_map["foo"] = LLSD::Binary(); + ensure_equals("scalar prototype map entry", llsd_matches(proto_map, data_map), + "['foo']: Binary required instead of String"); + data_map["foo"] = LLSD::Binary(); + ensure_equals("matching prototype map entry", llsd_matches(proto_map, data_map), ""); + + // String + { + static const char* matches[] = { "String", "NumString", "Boolean", "Integer", + "Real", "UUID", "Date", "URI" }; + test_matches("String", map, boost::begin(matches), boost::end(matches)); + } + + // Boolean, Integer, Real + static const char* numerics[] = { "Boolean", "Integer", "Real" }; + for (const char **ni = boost::begin(numerics), **nend = boost::end(numerics); + ni != nend; ++ni) + { + static const char* matches[] = { "Boolean", "Integer", "Real", "String", "NumString" }; + test_matches(*ni, map, boost::begin(matches), boost::end(matches)); + } + + // UUID + { + static const char* matches[] = { "UUID", "String", "NumString" }; + test_matches("UUID", map, boost::begin(matches), boost::end(matches)); + } + + // Date + { + static const char* matches[] = { "Date", "String", "NumString" }; + test_matches("Date", map, boost::begin(matches), boost::end(matches)); + } + + // URI + { + static const char* matches[] = { "URI", "String", "NumString" }; + test_matches("URI", map, boost::begin(matches), boost::end(matches)); + } + + // Binary + { + static const char* matches[] = { "Binary" }; + test_matches("Binary", map, boost::begin(matches), boost::end(matches)); + } + + /*-------------------------- llsd_equals ---------------------------*/ + + // Cross-product of each LLSD type with every other + for (LLSD::map_const_iterator lmi(map.beginMap()), lmend(map.endMap()); + lmi != lmend; ++lmi) + { + for (LLSD::map_const_iterator rmi(map.beginMap()), rmend(map.endMap()); + rmi != rmend; ++rmi) + { + // Name this test based on the map keys naming the types of + // interest, e.g "String::Integer". + // We expect the values (xmi->second) to be equal if and only + // if the type names (xmi->first) are equal. + ensure(STRINGIZE(lmi->first << "::" << rmi->first), + bool(lmi->first == rmi->first) == + bool(llsd_equals(lmi->second, rmi->second))); + } + } + + // Array cases + LLSD rarray; + rarray.append(1.0); + rarray.append(2); + rarray.append("3"); + LLSD larray(rarray); + ensure("llsd_equals(equal arrays)", llsd_equals(larray, rarray)); + rarray[2] = "4"; + ensure("llsd_equals(different [2])", ! llsd_equals(larray, rarray)); + rarray = larray; + rarray.append(LLSD::Date()); + ensure("llsd_equals(longer right array)", ! llsd_equals(larray, rarray)); + rarray = larray; + rarray.erase(2); + ensure("llsd_equals(shorter right array)", ! llsd_equals(larray, rarray)); + + // Map cases + LLSD rmap; + rmap["San Francisco"] = 65; + rmap["Phoenix"] = 92; + rmap["Boston"] = 77; + LLSD lmap(rmap); + ensure("llsd_equals(equal maps)", llsd_equals(lmap, rmap)); + rmap["Boston"] = 80; + ensure("llsd_equals(different [\"Boston\"])", ! llsd_equals(lmap, rmap)); + rmap = lmap; + rmap["Atlanta"] = 95; + ensure("llsd_equals(superset right map)", ! llsd_equals(lmap, rmap)); + rmap = lmap; + lmap["Seattle"] = 72; + ensure("llsd_equals(superset left map)", ! llsd_equals(lmap, rmap)); + } } diff --git a/indra/test/lltimestampcache_tut.cpp b/indra/test/lltimestampcache_tut.cpp index 9e0de0fe60..3b102a3366 100644 --- a/indra/test/lltimestampcache_tut.cpp +++ b/indra/test/lltimestampcache_tut.cpp @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@ * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, diff --git a/indra/test/lltranscode_tut.cpp b/indra/test/lltranscode_tut.cpp index 8abf9dc224..eb21979db0 100644 --- a/indra/test/lltranscode_tut.cpp +++ b/indra/test/lltranscode_tut.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2006-2007, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, diff --git a/indra/test/lltut.cpp b/indra/test/lltut.cpp index 201e174f9c..e4e0de1ff1 100644 --- a/indra/test/lltut.cpp +++ b/indra/test/lltut.cpp @@ -76,9 +76,13 @@ namespace tut void ensure_equals(const char* m, const LLSD& actual, const LLSD& expected) + { + ensure_equals(std::string(m), actual, expected); + } + + void ensure_equals(const std::string& msg, const LLSD& actual, + const LLSD& expected) { - const std::string& msg = m ? m : ""; - ensure_equals(msg + " type", actual.type(), expected.type()); switch (actual.type()) { @@ -128,7 +132,7 @@ namespace tut { ensure_equals(msg + " map keys", actual_iter->first, expected_iter->first); - ensure_equals((msg + "[" + actual_iter->first + "]").c_str(), + ensure_equals(msg + "[" + actual_iter->first + "]", actual_iter->second, expected_iter->second); ++actual_iter; ++expected_iter; @@ -141,7 +145,7 @@ namespace tut for(int i = 0; i < actual.size(); ++i) { - ensure_equals((msg + llformat("[%d]", i)).c_str(), + ensure_equals(msg + llformat("[%d]", i), actual[i], expected[i]); } return; diff --git a/indra/test/lltut.h b/indra/test/lltut.h index 47ea9d3f9e..6322753253 100644 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -74,7 +74,7 @@ namespace tut inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len) { if((expected_len != actual_len) || - (memcmp(actual, expected, actual_len) != 0)) + (std::memcmp(actual, expected, actual_len) != 0)) { std::stringstream ss; ss << (msg?msg:"") << (msg?": ":"") << "not equal"; @@ -121,6 +121,9 @@ namespace tut void ensure_equals(const char* msg, const LLSD& actual, const LLSD& expected); + + void ensure_equals(const std::string& msg, + const LLSD& actual, const LLSD& expected); void ensure_starts_with(const std::string& msg, const std::string& actual, const std::string& expectedStart); diff --git a/indra/test/test.cpp b/indra/test/test.cpp index ba81c6e49e..7dfe8f40b7 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -54,6 +54,11 @@ # include "ctype_workaround.h" #endif +#ifndef LL_WINDOWS +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#endif + namespace tut { std::string sSourceDir; @@ -136,34 +141,31 @@ public: run_completed_(*mStream); } run_completed_(std::cout); - - if (mFailedTests > 0) - { - exit(1); - } } + + int getFailedTests() const { return mFailedTests; } private: void run_completed_(std::ostream &stream) { + stream << "\tTotal Tests:\t" << mTotalTests << std::endl; + stream << "\tPassed Tests:\t" << mPassedTests; + if (mPassedTests == mTotalTests) + { + stream << "\tYAY!! \\o/"; + } stream << std::endl; - stream << "Total Tests: " << mTotalTests << std::endl; - stream << "Passed Tests: " << mPassedTests << std::endl; - stream << std::endl; - stream << "Total Tests: " << mTotalTests << std::endl; - stream << "Passed Tests: " << mPassedTests << std::endl; - if (mSkippedTests > 0) { - stream << "Skipped known failures: " << mSkippedTests + stream << "\tSkipped known failures:\t" << mSkippedTests << std::endl; } if(mFailedTests > 0) { stream << "*********************************" << std::endl; - stream << "Failed Tests: " << mFailedTests << std::endl; + stream << "Failed Tests:\t" << mFailedTests << std::endl; stream << "Please report or fix the problem." << std::endl; stream << "*********************************" << std::endl; } @@ -238,6 +240,11 @@ void wouldHaveCrashed(const std::string& message) int main(int argc, char **argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. +#ifndef LL_WINDOWS + ::testing::InitGoogleMock(&argc, argv); +#endif LLError::initForApplication("."); LLError::setFatalFunction(wouldHaveCrashed); LLError::setDefaultLevel(LLError::LEVEL_ERROR); @@ -340,9 +347,11 @@ int main(int argc, char **argv) tut::runner.get().run_tests(test_group); } + bool success = (callback.getFailedTests() == 0); + if (wait_at_exit) { - std::cerr << "Waiting for input before exiting..." << std::endl; + std::cerr << "Press return to exit..." << std::endl; std::cin.get(); } @@ -352,7 +361,7 @@ int main(int argc, char **argv) delete output; } - if (touch) + if (touch && success) { std::ofstream s; s.open(touch); @@ -361,5 +370,7 @@ int main(int argc, char **argv) } apr_terminate(); - return 0; + + int retval = (success ? 0 : 1); + return retval; } diff --git a/indra/test/test.h b/indra/test/test.h index 16ec4effcf..cee185140c 100644 --- a/indra/test/test.h +++ b/indra/test/test.h @@ -13,12 +13,13 @@ * ("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://secondlife.com/developers/opensource/gplv2 + * 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://secondlife.com/developers/opensource/flossexception + * 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, |