diff options
Diffstat (limited to 'indra/test')
-rw-r--r-- | indra/test/CMakeLists.txt | 6 | ||||
-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 | 133 | ||||
-rw-r--r-- | indra/test/llhttpdate_tut.cpp | 3 | ||||
-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 | 1 | ||||
-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 | 3 | ||||
-rw-r--r-- | indra/test/test.cpp | 19 | ||||
-rw-r--r-- | indra/test/test.h | 5 |
17 files changed, 615 insertions, 163 deletions
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 49a0a8f361..42a32f95b1 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -36,6 +36,7 @@ set(test_SOURCE_FILES llbuffer_tut.cpp lldate_tut.cpp lldependencies_tut.cpp + lldoubledispatch_tut.cpp llerror_tut.cpp llevents_tut.cpp llhost_tut.cpp @@ -67,6 +68,7 @@ set(test_SOURCE_FILES lltimestampcache_tut.cpp lltiming_tut.cpp lltranscode_tut.cpp + lltreeiterators_tut.cpp lltut.cpp lluri_tut.cpp lluuidhashmap_tut.cpp @@ -88,6 +90,7 @@ set(test_SOURCE_FILES set(test_HEADER_FILES CMakeLists.txt + debug.h llpipeutil.h llsdtraits.h lltut.h @@ -124,7 +127,10 @@ target_link_libraries(test ${APRICONV_LIBRARIES} ${PTHREAD_LIBRARY} ${WINDOWS_LIBRARIES} + ${BOOST_PROGRAM_OPTIONS_LIBRARY} + ${BOOST_REGEX_LIBRARY} ${DL_LIBRARY} + ${GOOGLE_PERFTOOLS_LIBRARIES} ) if (WINDOWS) 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 index e401f89b22..31130c3c79 100644 --- a/indra/test/llevents_tut.cpp +++ b/indra/test/llevents_tut.cpp @@ -32,96 +32,10 @@ // other Linden headers #include "lltut.h" #include "stringize.h" +#include "tests/listener.h" using boost::assign::list_of; -/***************************************************************************** -* test listener class -*****************************************************************************/ -class Listener; -std::ostream& operator<<(std::ostream&, const Listener&); - -class Listener -{ -public: - Listener(const std::string& name): - mName(name) - { -// std::cout << *this << ": ctor\n"; - } - Listener(const Listener& that): - mName(that.mName), - mLastEvent(that.mLastEvent) - { -// std::cout << *this << ": copy\n"; - } - virtual ~Listener() - { -// std::cout << *this << ": dtor\n"; - } - std::string getName() const { return mName; } - bool call(const LLSD& event) - { -// std::cout << *this << "::call(" << event << ")\n"; - mLastEvent = event; - return false; - } - bool callstop(const LLSD& event) - { -// std::cout << *this << "::callstop(" << event << ")\n"; - mLastEvent = event; - return true; - } - LLSD getLastEvent() const - { -// std::cout << *this << "::getLastEvent() -> " << mLastEvent << "\n"; - return mLastEvent; - } - void reset(const LLSD& to = LLSD()) - { -// std::cout << *this << "::reset(" << to << ")\n"; - mLastEvent = to; - } - -private: - std::string mName; - LLSD mLastEvent; -}; - -std::ostream& operator<<(std::ostream& out, const Listener& listener) -{ - out << "Listener(" << listener.getName() /* << "@" << &listener */ << ')'; - return out; -} - -struct Collect -{ - bool add(const std::string& bound, const LLSD& event) - { - result.push_back(bound); - return false; - } - void clear() { result.clear(); } - typedef std::vector<std::string> StringList; - StringList result; -}; - -std::ostream& operator<<(std::ostream& out, const Collect::StringList& strings) -{ - out << '('; - Collect::StringList::const_iterator begin(strings.begin()), end(strings.end()); - if (begin != end) - { - out << '"' << *begin << '"'; - while (++begin != end) - { - out << ", \"" << *begin << '"'; - } - } - out << ')'; - return out; -} - template<typename T> T make(const T& value) { return value; } @@ -174,14 +88,7 @@ namespace tut // 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); - // 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. - LLBoundListener connection = per_frame.listen(listener0.getName(), - boost::bind(&Listener::call, - boost::ref(listener0), - _1)); + LLBoundListener connection = listener0.listenTo(per_frame); ensure("connected", connection.connected()); ensure("not blocked", ! connection.blocked()); per_frame.post(1); @@ -207,6 +114,10 @@ namespace tut 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)); } @@ -221,8 +132,7 @@ namespace tut } ensure("threw DupListenerName", threw); // do it right this time - per_frame.listen(listener1.getName(), - boost::bind(&Listener::call, boost::ref(listener1), _1)); + listener1.listenTo(per_frame); per_frame.post(5); check_listener("got", listener0, 5); check_listener("got", listener1, 5); @@ -252,16 +162,10 @@ namespace tut LLEventPump& per_frame(pumps.obtain("per-frame")); listener0.reset(0); listener1.reset(0); - LLBoundListener bound0 = per_frame.listen(listener0.getName(), - boost::bind(&Listener::callstop, - boost::ref(listener0), - _1)); - LLBoundListener bound1 = per_frame.listen(listener1.getName(), - boost::bind(&Listener::call, - boost::ref(listener1), - _1), - // after listener0 - make<LLEventPump::NameList>(list_of(listener0.getName()))); + 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()); @@ -301,7 +205,7 @@ namespace tut // LLEventQueue. LLEventPump& mainloop(pumps.obtain("mainloop")); ensure("LLEventQueue leaf class", dynamic_cast<LLEventQueue*>(&login)); - login.listen(listener0.getName(), boost::bind(&Listener::call, boost::ref(listener0), _1)); + listener0.listenTo(login); listener0.reset(0); login.post(1); check_listener("waiting for queued event", listener0, 0); @@ -354,11 +258,10 @@ namespace tut { set_test_name("stopListening()"); LLEventPump& login(pumps.obtain("login")); - login.listen(listener0.getName(), boost::bind(&Listener::call, boost::ref(listener0), _1)); + listener0.listenTo(login); login.stopListening(listener0.getName()); // should not throw because stopListening() should have removed name - login.listen(listener0.getName(), - boost::bind(&Listener::callstop, boost::ref(listener0), _1)); + listener0.listenTo(login, &Listener::callstop); LLBoundListener wrong = login.getListener("bogus"); ensure("bogus connection disconnected", ! wrong.connected()); ensure("bogus connection blocked", wrong.blocked()); @@ -378,10 +281,8 @@ namespace tut boost::bind(&LLEventPump::post, boost::ref(filter0), _1)); upstream.listen(filter1.getName(), boost::bind(&LLEventPump::post, boost::ref(filter1), _1)); - filter0.listen(listener0.getName(), - boost::bind(&Listener::call, boost::ref(listener0), _1)); - filter1.listen(listener1.getName(), - boost::bind(&Listener::call, boost::ref(listener1), _1)); + listener0.listenTo(filter0); + listener1.listenTo(filter1); listener0.reset(0); listener1.reset(0); upstream.post(1); @@ -536,7 +437,7 @@ namespace tut // Passing a string LLEventPump name to LLListenerOrPumpName listener0.reset(0); LLEventStream random("random"); - random.listen(listener0.getName(), boost::bind(&Listener::call, boost::ref(listener0), _1)); + listener0.listenTo(random); eventSource("random"); check_listener("got by pump name", listener0, 17); bool threw = false; diff --git a/indra/test/llhttpdate_tut.cpp b/indra/test/llhttpdate_tut.cpp index b764696dae..b9733dc030 100644 --- a/indra/test/llhttpdate_tut.cpp +++ b/indra/test/llhttpdate_tut.cpp @@ -50,6 +50,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 +58,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 +68,7 @@ namespace tut template<> template<> void httpdate_object::test<3>() { + //F64 sometime = LLFrameTimer::getTotalSeconds(); time_t sometime; time(&sometime); 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..9edb915703 100755 --- a/indra/test/llsdmessagebuilder_tut.cpp +++ b/indra/test/llsdmessagebuilder_tut.cpp @@ -44,6 +44,7 @@ #include "v3dmath.h" #include "v3math.h" #include "v4math.h" +#include "llsdutil.cpp" #include "llsdutil_math.cpp" #include "lltemplatemessagebuilder.h" 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..d125bb0005 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().insert("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..ba3791cbd4 100644 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -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..0ba5758e15 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -64,13 +64,14 @@ namespace tut class LLTestCallback : public tut::callback { public: - LLTestCallback(bool verbose_mode, std::ostream *stream) : + LLTestCallback(bool verbose_mode, std::ostream *stream, bool wait) : mVerboseMode(verbose_mode), mTotalTests(0), mPassedTests(0), mFailedTests(0), mSkippedTests(0), - mStream(stream) + mStream(stream), + mWaitAtExit(wait) { } @@ -137,6 +138,11 @@ public: } run_completed_(std::cout); + if(mWaitAtExit) { + std::cerr << "Waiting for input before exiting..." << std::endl; + std::cin.get(); + } + if (mFailedTests > 0) { exit(1); @@ -176,6 +182,7 @@ protected: int mFailedTests; int mSkippedTests; std::ostream *mStream; + bool mWaitAtExit; }; static const apr_getopt_option_t TEST_CL_OPTIONS[] = @@ -328,7 +335,7 @@ int main(int argc, char **argv) } // run the tests - LLTestCallback callback(verbose_mode, output); + LLTestCallback callback(verbose_mode, output, wait_at_exit); tut::runner.get().set_callback(&callback); if(test_group.empty()) @@ -339,12 +346,6 @@ int main(int argc, char **argv) { tut::runner.get().run_tests(test_group); } - - if (wait_at_exit) - { - std::cerr << "Waiting for input before exiting..." << std::endl; - std::cin.get(); - } if (output) { 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, |