summaryrefslogtreecommitdiff
path: root/indra/newview/tests
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/tests')
-rw-r--r--indra/newview/tests/llagentaccess_test.cpp2
-rw-r--r--indra/newview/tests/llcapabilitylistener_test.cpp37
-rw-r--r--indra/newview/tests/lldateutil_test.cpp39
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp424
-rw-r--r--indra/newview/tests/llmediadataclient_test.cpp938
-rw-r--r--indra/newview/tests/lltextureinfo_test.cpp284
-rw-r--r--indra/newview/tests/lltextureinfodetails_test.cpp98
-rw-r--r--indra/newview/tests/lltexturestatsuploader_test.cpp156
-rw-r--r--indra/newview/tests/llviewerhelputil_test.cpp128
-rw-r--r--indra/newview/tests/llworldmap_test.cpp523
-rw-r--r--indra/newview/tests/llworldmipmap_test.cpp176
-rw-r--r--indra/newview/tests/llxmlrpclistener_test.cpp230
-rw-r--r--indra/newview/tests/test_llxmlrpc_peer.py59
13 files changed, 3020 insertions, 74 deletions
diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp
index 42872d85fb..e08193f785 100644
--- a/indra/newview/tests/llagentaccess_test.cpp
+++ b/indra/newview/tests/llagentaccess_test.cpp
@@ -29,6 +29,8 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+
+#include "linden_common.h"
#include "../test/lltut.h"
#include "../llagentaccess.h"
diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
index bd6ae90fab..ca7d02fc68 100644
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ b/indra/newview/tests/llcapabilitylistener_test.cpp
@@ -47,9 +47,10 @@
#include "../test/lltut.h"
#include "../llcapabilityprovider.h"
#include "lluuid.h"
-#include "llerrorcontrol.h"
#include "tests/networkio.h"
#include "tests/commtest.h"
+#include "tests/wrapllerrs.h"
+#include "message.h"
#include "stringize.h"
#if defined(LL_WINDOWS)
@@ -127,28 +128,6 @@ namespace tut
typedef llcapears_group::object llcapears_object;
llcapears_group llsdmgr("llcapabilitylistener");
- struct CaptureError: public LLError::OverrideFatalFunction
- {
- CaptureError():
- LLError::OverrideFatalFunction(boost::bind(&CaptureError::operator(), this, _1))
- {
- LLError::setPrintLocation(false);
- }
-
- struct FatalException: public std::runtime_error
- {
- FatalException(const std::string& what): std::runtime_error(what) {}
- };
-
- void operator()(const std::string& message)
- {
- error = message;
- throw FatalException(message);
- }
-
- std::string error;
- };
-
template<> template<>
void llcapears_object::test<1>()
{
@@ -160,10 +139,10 @@ namespace tut
std::string threw;
try
{
- CaptureError capture;
+ WrapLL_ERRS capture;
regionPump.post(request);
}
- catch (const CaptureError::FatalException& e)
+ catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
@@ -207,10 +186,10 @@ namespace tut
std::string threw;
try
{
- CaptureError capture;
+ WrapLL_ERRS capture;
regionPump.post(request);
}
- catch (const CaptureError::FatalException& e)
+ catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
@@ -269,10 +248,10 @@ namespace tut
std::string threw;
try
{
- CaptureError capture;
+ WrapLL_ERRS capture;
regionPump.post(request);
}
- catch (const CaptureError::FatalException& e)
+ catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
index 30e39a3bcf..7ba82fbd2c 100644
--- a/indra/newview/tests/lldateutil_test.cpp
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -28,6 +28,9 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+
+#include "linden_common.h"
+
#include "../test/lltut.h"
#include "../lldateutil.h"
@@ -57,6 +60,11 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::
std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count)
{
+ count_string_t key(xml_desc, count);
+ if (gCountString.find(key) == gCountString.end())
+ {
+ return std::string("Couldn't find ") + xml_desc;
+ }
return gCountString[ count_string_t(xml_desc, count) ];
}
@@ -88,8 +96,11 @@ namespace tut
gCountString[ count_string_t("AgeYears", 2) ] = "2 years";
gCountString[ count_string_t("AgeMonths", 1) ] = "1 month";
gCountString[ count_string_t("AgeMonths", 2) ] = "2 months";
+ gCountString[ count_string_t("AgeMonths", 11) ]= "11 months";
gCountString[ count_string_t("AgeWeeks", 1) ] = "1 week";
gCountString[ count_string_t("AgeWeeks", 2) ] = "2 weeks";
+ gCountString[ count_string_t("AgeWeeks", 3) ] = "3 weeks";
+ gCountString[ count_string_t("AgeWeeks", 4) ] = "4 weeks";
gCountString[ count_string_t("AgeDays", 1) ] = "1 day";
gCountString[ count_string_t("AgeDays", 2) ] = "2 days";
}
@@ -110,12 +121,18 @@ namespace tut
ensure_equals("years",
LLDateUtil::ageFromDate("12/31/2007", mNow),
"2 years old" );
- ensure_equals("single year",
- LLDateUtil::ageFromDate("12/31/2008", mNow),
- "1 year old" );
+ ensure_equals("years",
+ LLDateUtil::ageFromDate("1/1/2008", mNow),
+ "1 year 11 months old" );
+ ensure_equals("single year + one month",
+ LLDateUtil::ageFromDate("11/30/2008", mNow),
+ "1 year 1 month old" );
ensure_equals("single year + a bit",
LLDateUtil::ageFromDate("12/12/2008", mNow),
"1 year old" );
+ ensure_equals("single year",
+ LLDateUtil::ageFromDate("12/31/2008", mNow),
+ "1 year old" );
}
template<> template<>
@@ -125,6 +142,9 @@ namespace tut
ensure_equals("months",
LLDateUtil::ageFromDate("10/30/2009", mNow),
"2 months old" );
+ ensure_equals("months 2",
+ LLDateUtil::ageFromDate("10/31/2009", mNow),
+ "2 months old" );
ensure_equals("single month",
LLDateUtil::ageFromDate("11/30/2009", mNow),
"1 month old" );
@@ -134,6 +154,9 @@ namespace tut
void dateutil_object_t::test<3>()
{
set_test_name("Weeks");
+ ensure_equals("4 weeks",
+ LLDateUtil::ageFromDate("12/1/2009", mNow),
+ "4 weeks old" );
ensure_equals("weeks",
LLDateUtil::ageFromDate("12/17/2009", mNow),
"2 weeks old" );
@@ -156,4 +179,14 @@ namespace tut
LLDateUtil::ageFromDate("12/31/2009", mNow),
"Joined today" );
}
+
+ template<> template<>
+ void dateutil_object_t::test<5>()
+ {
+ set_test_name("2010 rollover");
+ LLDate now(std::string("2010-01-04T12:00:00Z"));
+ ensure_equals("days",
+ LLDateUtil::ageFromDate("12/13/2009", now),
+ "3 weeks old" );
+ }
}
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
new file mode 100644
index 0000000000..ef93586c6e
--- /dev/null
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -0,0 +1,424 @@
+/**
+ * @file lllogininstance_test.cpp
+ * @brief Test for lllogininstance.cpp.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * Copyright (c) 2008, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+// Own header
+#include "../lllogininstance.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "llevents.h"
+
+#if defined(LL_WINDOWS)
+#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr
+#endif
+
+// Constants
+const std::string VIEWERLOGIN_URI("viewerlogin_uri");
+const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid");
+
+const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno");
+
+// Link seams.
+
+//-----------------------------------------------------------------------------
+static LLEventStream gTestPump("test_pump");
+
+#include "lllogin.h"
+static std::string gLoginURI;
+static LLSD gLoginCreds;
+static bool gDisconnectCalled = false;
+class LLLogin::Impl
+{
+};
+LLLogin::LLLogin() {}
+LLLogin::~LLLogin() {}
+LLEventPump& LLLogin::getEventPump() { return gTestPump; }
+void LLLogin::connect(const std::string& uri, const LLSD& credentials)
+{
+ gLoginURI = uri;
+ gLoginCreds = credentials;
+}
+
+void LLLogin::disconnect()
+{
+ gDisconnectCalled = true;
+}
+
+//-----------------------------------------------------------------------------
+#include "../llviewernetwork.h"
+unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'};
+
+LLViewerLogin::LLViewerLogin() : mGridChoice(GRID_INFO_NONE) {}
+LLViewerLogin::~LLViewerLogin() {}
+void LLViewerLogin::getLoginURIs(std::vector<std::string>& uris) const
+{
+ uris.push_back(VIEWERLOGIN_URI);
+}
+std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; }
+
+//-----------------------------------------------------------------------------
+#include "../llviewercontrol.h"
+LLControlGroup gSavedSettings("Global");
+std::string gCurrentVersion = "invalid_version";
+
+LLControlGroup::LLControlGroup(const std::string& name) :
+ LLInstanceTracker<LLControlGroup, std::string>(name){}
+LLControlGroup::~LLControlGroup() {}
+void LLControlGroup::setBOOL(const std::string& name, BOOL val) {}
+BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; }
+F32 LLControlGroup::getF32(const std::string& name) { return 0.0f; }
+U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; }
+void LLControlGroup::setString(const std::string& name, const std::string& val) {}
+std::string LLControlGroup::getString(const std::string& name) { return "test_string"; }
+BOOL LLControlGroup::declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, BOOL persist) { return TRUE; }
+BOOL LLControlGroup::declareString(const std::string& name, const std::string &initial_val, const std::string& comment, BOOL persist) { return TRUE; }
+
+#include "lluicolortable.h"
+void LLUIColorTable::saveUserSettings(void)const {}
+
+//-----------------------------------------------------------------------------
+#include "../llurlsimstring.h"
+LLURLSimString LLURLSimString::sInstance;
+bool LLURLSimString::parse() { return true; }
+
+//-----------------------------------------------------------------------------
+#include "llnotifications.h"
+#include "llfloaterreg.h"
+static std::string gTOSType;
+static LLEventPump * gTOSReplyPump = NULL;
+
+//static
+LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
+{
+ gTOSType = name;
+ gTOSReplyPump = &LLEventPumps::instance().obtain(key["reply_pump"]);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// LLNotifications
+class MockNotifications : public LLNotificationsInterface
+{
+ boost::function<void (const LLSD&, const LLSD&)> mResponder;
+ int mAddedCount;
+
+public:
+ MockNotifications() :
+ mResponder(0),
+ mAddedCount(0)
+ {
+ }
+
+ virtual ~MockNotifications() {}
+
+ /* virtual */ LLNotificationPtr add(
+ const std::string& name,
+ const LLSD& substitutions,
+ const LLSD& payload,
+ LLNotificationFunctorRegistry::ResponseFunctor functor)
+ {
+ mResponder = functor;
+ mAddedCount++;
+ return LLNotificationPtr((LLNotification*)NULL);
+ }
+
+ void sendYesResponse()
+ {
+ LLSD notification;
+ LLSD response;
+ response = 1;
+ mResponder(notification, response);
+ }
+
+ void sendNoResponse()
+ {
+ LLSD notification;
+ LLSD response;
+ response = 2;
+ mResponder(notification, response);
+ }
+
+ void sendBogusResponse()
+ {
+ LLSD notification;
+ LLSD response;
+ response = 666;
+ mResponder(notification, response);
+ }
+
+ int addedCount() { return mAddedCount; }
+};
+
+S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response)
+{
+ return response.asInteger();
+}
+
+// misc
+std::string xml_escape_string(const std::string& in)
+{
+ return in;
+}
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct lllogininstance_data
+ {
+ lllogininstance_data() : logininstance(LLLoginInstance::getInstance())
+ {
+ // Global initialization
+ gLoginURI.clear();
+ gLoginCreds.clear();
+ gDisconnectCalled = false;
+
+ gTOSType = ""; // Set to invalid value.
+ gTOSReplyPump = 0; // clear the callback.
+
+
+ gSavedSettings.declareBOOL("NoInventoryLibrary", FALSE, "", FALSE);
+ gSavedSettings.declareBOOL("ConnectAsGod", FALSE, "", FALSE);
+ gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE);
+ gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE);
+ gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE);
+ gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE);
+ gSavedSettings.declareString("NextLoginLocation", "", "", FALSE);
+ gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE);
+
+ credentials["first"] = "testfirst";
+ credentials["last"] = "testlast";
+ credentials["passwd"] = "testpass";
+
+ logininstance->setNotificationsInterface(&notifications);
+ }
+
+ LLLoginInstance* logininstance;
+ LLSD credentials;
+ MockNotifications notifications;
+ };
+
+ typedef test_group<lllogininstance_data> lllogininstance_group;
+ typedef lllogininstance_group::object lllogininstance_object;
+ lllogininstance_group llsdmgr("lllogininstance");
+
+ template<> template<>
+ void lllogininstance_object::test<1>()
+ {
+ set_test_name("Test Simple Success And Disconnect");
+
+ // Test default connect.
+ logininstance->connect(credentials);
+
+ ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
+
+ // Dummy success response.
+ LLSD response;
+ response["state"] = "online";
+ response["change"] = "connect";
+ response["progress"] = 1.0;
+ response["transfer_rate"] = 7;
+ response["data"] = "test_data";
+
+ gTestPump.post(response);
+
+ ensure("Success response", logininstance->authSuccess());
+ ensure_equals("Test Response Data", logininstance->getResponse().asString(), "test_data");
+
+ logininstance->disconnect();
+
+ ensure_equals("Called Login Module Disconnect", gDisconnectCalled, true);
+
+ response.clear();
+ response["state"] = "offline";
+ response["change"] = "disconnect";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 0;
+ response["data"] = "test_data";
+
+ gTestPump.post(response);
+
+ ensure("Disconnected", !(logininstance->authSuccess()));
+ }
+
+ template<> template<>
+ void lllogininstance_object::test<2>()
+ {
+ set_test_name("Test User TOS/Critical message Interaction");
+
+ const std::string test_uri = "testing-uri";
+
+ // Test default connect.
+ logininstance->connect(test_uri, credentials);
+
+ // connect should call LLLogin::connect to init gLoginURI and gLoginCreds.
+ ensure_equals("Default connect uri", gLoginURI, "testing-uri");
+ ensure_equals("Default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);
+ ensure_equals("Default for read critical", gLoginCreds["params"]["read_critical"].asBoolean(), false);
+
+ // TOS failure response.
+ LLSD response;
+ response["state"] = "offline";
+ response["change"] = "fail.login";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 7;
+ response["data"]["reason"] = "tos";
+ gTestPump.post(response);
+
+ ensure_equals("TOS Dialog type", gTOSType, "message_tos");
+ ensure("TOS callback given", gTOSReplyPump != 0);
+ gTOSReplyPump->post(false); // Call callback denying TOS.
+ ensure("No TOS, failed auth", logininstance->authFailure());
+
+ // Start again.
+ logininstance->connect(test_uri, credentials);
+ gTestPump.post(response); // Fail for tos again.
+ gTOSReplyPump->post(true); // Accept tos, should reconnect w/ agree_to_tos.
+ ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true);
+ ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess());
+
+ // Fail connection, attempt connect again.
+ // The new request should have reset agree to tos to default.
+ response["data"]["reason"] = "key"; // bad creds.
+ gTestPump.post(response);
+ ensure("TOS auth failure", logininstance->authFailure());
+
+ logininstance->connect(test_uri, credentials);
+ ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false);
+
+ // Critical Message failure response.
+ logininstance->connect(test_uri, credentials);
+ response["data"]["reason"] = "critical"; // Change response to "critical message"
+ gTestPump.post(response);
+
+ ensure_equals("TOS Dialog type", gTOSType, "message_critical");
+ ensure("TOS callback given", gTOSReplyPump != 0);
+ gTOSReplyPump->post(true);
+ ensure_equals("Accepted read critical message", gLoginCreds["params"]["read_critical"].asBoolean(), true);
+ ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess());
+
+ // Fail then attempt new connection
+ response["data"]["reason"] = "key"; // bad creds.
+ gTestPump.post(response);
+ ensure("TOS auth failure", logininstance->authFailure());
+ logininstance->connect(test_uri, credentials);
+ ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false);
+ }
+
+ template<> template<>
+ void lllogininstance_object::test<3>()
+ {
+ set_test_name("Test Mandatory Update User Accepts");
+
+ // Part 1 - Mandatory Update, with User accepts response.
+ // Test connect with update needed.
+ logininstance->connect(credentials);
+
+ ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
+
+ // Update needed failure response.
+ LLSD response;
+ response["state"] = "offline";
+ response["change"] = "fail.login";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 7;
+ response["data"]["reason"] = "update";
+ gTestPump.post(response);
+
+ ensure_equals("Notification added", notifications.addedCount(), 1);
+
+ notifications.sendYesResponse();
+
+ ensure("Disconnected", !(logininstance->authSuccess()));
+ }
+
+ template<> template<>
+ void lllogininstance_object::test<4>()
+ {
+ set_test_name("Test Mandatory Update User Decline");
+
+ // Test connect with update needed.
+ logininstance->connect(credentials);
+
+ ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
+
+ // Update needed failure response.
+ LLSD response;
+ response["state"] = "offline";
+ response["change"] = "fail.login";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 7;
+ response["data"]["reason"] = "update";
+ gTestPump.post(response);
+
+ ensure_equals("Notification added", notifications.addedCount(), 1);
+ notifications.sendNoResponse();
+
+ ensure("Disconnected", !(logininstance->authSuccess()));
+ }
+
+ template<> template<>
+ void lllogininstance_object::test<6>()
+ {
+ set_test_name("Test Optional Update User Accept");
+
+ // Part 3 - Mandatory Update, with bogus response.
+ // Test connect with update needed.
+ logininstance->connect(credentials);
+
+ ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
+
+ // Update needed failure response.
+ LLSD response;
+ response["state"] = "offline";
+ response["change"] = "fail.login";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 7;
+ response["data"]["reason"] = "optional";
+ gTestPump.post(response);
+
+ ensure_equals("Notification added", notifications.addedCount(), 1);
+ notifications.sendYesResponse();
+
+ ensure("Disconnected", !(logininstance->authSuccess()));
+ }
+
+ template<> template<>
+ void lllogininstance_object::test<7>()
+ {
+ set_test_name("Test Optional Update User Denies");
+
+ // Part 3 - Mandatory Update, with bogus response.
+ // Test connect with update needed.
+ logininstance->connect(credentials);
+
+ ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI);
+
+ // Update needed failure response.
+ LLSD response;
+ response["state"] = "offline";
+ response["change"] = "fail.login";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 7;
+ response["data"]["reason"] = "optional";
+ gTestPump.post(response);
+
+ ensure_equals("Notification added", notifications.addedCount(), 1);
+ notifications.sendNoResponse();
+
+ // User skips, should be reconnecting.
+ ensure_equals("reconnect uri", gLoginURI, VIEWERLOGIN_URI);
+ ensure_equals("skipping optional update", gLoginCreds["params"]["skipoptional"].asBoolean(), true);
+ }
+}
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
new file mode 100644
index 0000000000..33d413bd21
--- /dev/null
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -0,0 +1,938 @@
+/**
+ * @file llmediadataclient_test.cpp
+ * @brief LLMediaDatClient tests
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-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$
+ */
+
+#include "linden_common.h"
+#include "../llviewerprecompiledheaders.h"
+
+#include <iostream>
+#include "../test/lltut.h"
+
+#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "llerrorcontrol.h"
+#include "llhttpstatuscodes.h"
+
+#include "../llmediadataclient.h"
+#include "../llvovolume.h"
+
+#include "../../llprimitive/llmediaentry.cpp"
+#include "../../llprimitive/lltextureentry.cpp"
+#include "../../llmessage/tests/llcurl_stub.cpp"
+
+#if LL_WINDOWS
+#pragma warning (push)
+#pragma warning (disable : 4702) // boost::lexical_cast generates this warning
+#endif
+#include <boost/lexical_cast.hpp>
+#if LL_WINDOWS
+#pragma warning (pop)
+#endif
+
+#define VALID_OBJECT_ID "3607d5c4-644b-4a8a-871a-8b78471af2a2"
+#define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111"
+#define VALID_OBJECT_ID_2 "22222222-2222-2222-2222-222222222222"
+#define VALID_OBJECT_ID_3 "33333333-3333-3333-3333-333333333333"
+#define VALID_OBJECT_ID_4 "44444444-4444-4444-4444-444444444444"
+
+#define FAKE_OBJECT_MEDIA_CAP_URL "foo_ObjectMedia"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL "foo_ObjectMediaNavigate"
+#define FAKE_OBJECT_MEDIA_CAP_URL_503 "foo_ObjectMedia_503"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR "foo_ObjectMediaNavigate_ERROR"
+
+#define MEDIA_DATA "\
+<array> \
+<string>foo</string> \
+<string>bar</string> \
+<string>baz</string> \
+</array>"
+
+#define _DATA_URLS(ID,INTEREST,NEW,URL1,URL2) " \
+<llsd> \
+ <map> \
+ <key>uuid</key> \
+ <string>" ID "</string> \
+ <key>interest</key> \
+ <real>" INTEREST "</real> \
+ <key>cap_urls</key> \
+ <map> \
+ <key>ObjectMedia</key> \
+ <string>" URL1 "</string> \
+ <key>ObjectMediaNavigate</key> \
+ <string>" URL2 "</string> \
+ </map> \
+ <key>media_data</key> \
+ " MEDIA_DATA " \
+ <key>is_dead</key> \
+ <boolean>false</boolean> \
+ <key>is_new</key> \
+ <boolean>" NEW "</boolean> \
+ </map> \
+</llsd>"
+
+#define _DATA(ID,INTEREST,NEW) _DATA_URLS(ID,INTEREST,NEW,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
+
+const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","true");
+
+#define STR(I) boost::lexical_cast<std::string>(I)
+
+#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" << \
+"================================================================================\n" << \
+"==================================== TEST " #N " ===================================\n" << \
+"================================================================================\n" << LL_ENDL;
+
+LLSD *gPostRecords = NULL;
+F64 gMinimumInterestLevel = (F64)0.0;
+
+// stubs:
+void LLHTTPClient::post(
+ const std::string& url,
+ const LLSD& body,
+ LLHTTPClient::ResponderPtr responder,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ LLSD record;
+ record["url"] = url;
+ record["body"] = body;
+ record["headers"] = headers;
+ record["timeout"] = timeout;
+ gPostRecords->append(record);
+
+ // Magic URL that triggers a 503:
+ LLSD result;
+ result[LLTextureEntry::OBJECT_ID_KEY] = body[LLTextureEntry::OBJECT_ID_KEY];
+ if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 )
+ {
+ responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason");
+ return;
+ }
+ else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR)
+ {
+ LLSD error;
+ error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;
+ result["error"] = error;
+ }
+ responder->result(result);
+}
+
+const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+
+class LLMediaDataClientObjectTest : public LLMediaDataClientObject
+{
+public:
+ LLMediaDataClientObjectTest(const char *data)
+ {
+ std::istringstream d(data);
+ LLSDSerialize::fromXML(mRep, d);
+ mNumBounceBacks = 0;
+
+ // std::cout << ll_pretty_print_sd(mRep) << std::endl;
+ // std::cout << "ID: " << getID() << std::endl;
+ }
+ LLMediaDataClientObjectTest(const LLSD &rep)
+ : mRep(rep), mNumBounceBacks(0) {}
+ ~LLMediaDataClientObjectTest()
+ { LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; }
+
+ virtual U8 getMediaDataCount() const
+ { return mRep["media_data"].size(); }
+ virtual LLSD getMediaDataLLSD(U8 index) const
+ { return mRep["media_data"][(LLSD::Integer)index]; }
+ virtual LLUUID getID() const
+ { return mRep["uuid"]; }
+ virtual void mediaNavigateBounceBack(U8 index)
+ { mNumBounceBacks++; }
+
+ virtual bool hasMedia() const
+ { return mRep.has("media_data"); }
+
+ virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &media_version)
+ { mRep["media_data"] = media_data_array; mRep["media_version"] = media_version; }
+
+ virtual F64 getMediaInterest() const
+ { return (LLSD::Real)mRep["interest"]; }
+
+ virtual bool isInterestingEnough() const
+ { return getMediaInterest() > gMinimumInterestLevel; }
+
+ virtual std::string getCapabilityUrl(const std::string &name) const
+ { return mRep["cap_urls"][name]; }
+
+ virtual bool isDead() const
+ { return mRep["is_dead"]; }
+
+ virtual U32 getMediaVersion() const
+ { return (LLSD::Integer)mRep["media_version"]; }
+
+ virtual bool isNew() const
+ { return mRep["is_new"]; }
+
+ void setMediaInterest(F64 val)
+ { mRep["interest"] = val; }
+
+ int getNumBounceBacks() const
+ { return mNumBounceBacks; }
+
+ void markDead()
+ { mRep["is_dead"] = true; }
+
+ void markOld()
+ { mRep["is_new"] = false; }
+
+private:
+ LLSD mRep;
+ int mNumBounceBacks;
+};
+
+// This special timer delay should ensure that the timer will fire on the very
+// next pump, no matter what (though this does make an assumption about the
+// implementation of LLEventTimer::updateClass()):
+const F32 NO_PERIOD = -1000.0f;
+
+static void pump_timers()
+{
+ LLEventTimer::updateClass();
+}
+
+namespace tut
+{
+ struct mediadataclient
+ {
+ mediadataclient() {
+ gPostRecords = &mLLSD;
+ gMinimumInterestLevel = (F64)0.0;
+
+// LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+// LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
+// LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
+ }
+ LLSD mLLSD;
+ };
+
+ typedef test_group<mediadataclient> mediadataclient_t;
+ typedef mediadataclient_t::object mediadataclient_object_t;
+ tut::mediadataclient_t tut_mediadataclient("mediadataclient");
+
+ void ensure(const std::string &msg, int value, int expected)
+ {
+ std::string m = msg;
+ m += " value: " + STR(value);
+ m += ", expected: " + STR(expected);
+ ensure(m, value == expected);
+ }
+
+ void ensure(const std::string &msg, const std::string & value, const std::string & expected)
+ {
+ std::string m = msg;
+ m += " value: " + value;
+ m += ", expected: " + expected;
+ ensure(m, value == expected);
+ }
+
+ void ensure(const std::string &msg, const LLUUID & value, const LLUUID & expected)
+ {
+ std::string m = msg;
+ m += " value: " + value.asString();
+ m += ", expected: " + expected.asString();
+ ensure(m, value == expected);
+ }
+
+ void ensure_llsd(const std::string &msg, const LLSD & value, const char *expected)
+ {
+ LLSD expected_llsd;
+ std::istringstream e(expected);
+ LLSDSerialize::fromXML(expected_llsd, e);
+
+ std::string value_str = ll_pretty_print_sd(value);
+ std::string expected_str = ll_pretty_print_sd(expected_llsd);
+ std::string m = msg;
+ m += " value: " + value_str;
+ m += ", expected: " + expected_str;
+ ensure(m, value_str == expected_str);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<1>()
+ {
+ //
+ // Test fetchMedia()
+ //
+ LOG_TEST(1);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ int num_refs_start = o->getNumRefs();
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+ mdc->fetchMedia(o);
+
+ // Make sure no posts happened yet...
+ ensure("post records", gPostRecords->size(), 0);
+
+ ::pump_timers();
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("post GET", (*gPostRecords)[0]["body"]["verb"], "GET");
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<2>()
+ {
+ //
+ // Test updateMedia()
+ //
+ LOG_TEST(2);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ {
+ // queue time w/ no delay ensures that ::pump_timers() will hit the tick()
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+ mdc->updateMedia(o);
+ ensure("post records", gPostRecords->size(), 0);
+ ::pump_timers();
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("post UPDATE", (*gPostRecords)[0]["body"]["verb"], "UPDATE");
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure_llsd("post data llsd", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
+ "<llsd>" MEDIA_DATA "</llsd>");
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<3>()
+ {
+ //
+ // Test navigate()
+ //
+ LOG_TEST(3);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ {
+ LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
+ const char *TEST_URL = "http://example.com";
+ mdc->navigate(o, 0, TEST_URL);
+ ensure("post records", gPostRecords->size(), 0);
+ ::pump_timers();
+
+ // ensure no bounce back
+ ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0);
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL);
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+ ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<4>()
+ {
+ //
+ // Test queue ordering
+ //
+ LOG_TEST(4);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_1,"1.0","true"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_2,"3.0","true"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_3,"2.0","true"));
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+ const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+
+ // Make sure no posts happened yet...
+ ensure("post records", gPostRecords->size(), 0);
+
+ // tick 3 times...
+ ::pump_timers();
+ ensure("post records", gPostRecords->size(), 1);
+ ::pump_timers();
+ ensure("post records", gPostRecords->size(), 2);
+ ::pump_timers();
+ ensure("post records", gPostRecords->size(), 3);
+
+ for( int i=0; i < 3; i++ )
+ {
+ ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+ ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(),
+ LLUUID(ORDERED_OBJECT_IDS[i]));
+ }
+
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<5>()
+ {
+ //
+ // Test fetchMedia() getting a 503 error
+ //
+ LOG_TEST(5);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+ _DATA_URLS(VALID_OBJECT_ID,
+ "1.0","true",
+ FAKE_OBJECT_MEDIA_CAP_URL_503,
+ FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL));
+ int num_refs_start = o->getNumRefs();
+ {
+ const int NUM_RETRIES = 5;
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD,NUM_RETRIES);
+
+ // This should generate a retry
+ mdc->fetchMedia(o);
+
+ // Make sure no posts happened yet...
+ ensure("post records before", gPostRecords->size(), 0);
+
+ // Once, causes retry
+ // Second, fires retry timer
+ // Third, fires queue timer again
+ for (int i=0; i<NUM_RETRIES; ++i)
+ {
+ ::pump_timers(); // Should pump (fire) the queue timer, causing a retry timer to be scheduled
+ // XXX This ensure is not guaranteed, because scheduling a timer might actually get it pumped in the same loop
+ //ensure("post records " + STR(i), gPostRecords->size(), i+1);
+ ::pump_timers(); // Should pump (fire) the retry timer, scheduling the queue timer
+ }
+
+ // Do some extra pumps to make sure no other timer work occurs.
+ ::pump_timers();
+ ::pump_timers();
+ ::pump_timers();
+
+ // Make sure there were 2 posts
+ ensure("post records after", gPostRecords->size(), NUM_RETRIES);
+ for (int i=0; i<NUM_RETRIES; ++i)
+ {
+ ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL_503);
+ ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+ ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ }
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ template<> template<>
+ void mediadataclient_object_t::test<6>()
+ {
+ //
+ // Test navigate() with a bounce back
+ //
+ LOG_TEST(6);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+ _DATA_URLS(VALID_OBJECT_ID,
+ "1.0","true",
+ FAKE_OBJECT_MEDIA_CAP_URL,
+ FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
+ {
+ LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
+ const char *TEST_URL = "http://example.com";
+ mdc->navigate(o, 0, TEST_URL);
+ ensure("post records", gPostRecords->size(), 0);
+ ::pump_timers();
+
+ // ensure bounce back
+ ensure("bounce back",
+ dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(),
+ 1);
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR);
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+ ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ template<> template<>
+ void mediadataclient_object_t::test<7>()
+ {
+ // Test LLMediaDataClient::isInQueue()
+ LOG_TEST(7);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_1,"3.0","true"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_2,"1.0","true"));
+ int num_refs_start = o1->getNumRefs();
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+
+ ensure("not in queue yet 1", ! mdc->isInQueue(o1));
+ ensure("not in queue yet 2", ! mdc->isInQueue(o2));
+
+ mdc->fetchMedia(o1);
+
+ ensure("is in queue", mdc->isInQueue(o1));
+ ensure("is not in queue", ! mdc->isInQueue(o2));
+
+ ::pump_timers();
+
+ ensure("not in queue anymore", ! mdc->isInQueue(o1));
+ ensure("still is not in queue", ! mdc->isInQueue(o2));
+
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o1->getNumRefs(), num_refs_start);
+
+ }
+
+ template<> template<>
+ void mediadataclient_object_t::test<8>()
+ {
+ // Test queue handling of objects that are marked dead.
+ LOG_TEST(8);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"4.0","true"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"3.0","true"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"2.0","true"));
+ LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"1.0","true"));
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+
+ // queue up all 4 objects
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+ mdc->fetchMedia(o4);
+
+ // and mark the second and fourth ones dead.
+ dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o2))->markDead();
+ dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o4))->markDead();
+
+ ensure("is in queue 1", mdc->isInQueue(o1));
+ ensure("is in queue 2", mdc->isInQueue(o2));
+ ensure("is in queue 3", mdc->isInQueue(o3));
+ ensure("is in queue 4", mdc->isInQueue(o4));
+ ensure("post records", gPostRecords->size(), 0);
+
+ ::pump_timers();
+
+ // The first tick should remove the first one
+ ensure("is not in queue 1", !mdc->isInQueue(o1));
+ ensure("is in queue 2", mdc->isInQueue(o2));
+ ensure("is in queue 3", mdc->isInQueue(o3));
+ ensure("is in queue 4", mdc->isInQueue(o4));
+ ensure("post records", gPostRecords->size(), 1);
+
+ ::pump_timers();
+
+ // The second tick should skip the second and remove the third
+ ensure("is not in queue 2", !mdc->isInQueue(o2));
+ ensure("is not in queue 3", !mdc->isInQueue(o3));
+ ensure("is in queue 4", mdc->isInQueue(o4));
+ ensure("post records", gPostRecords->size(), 2);
+
+ ::pump_timers();
+
+ // The third tick should skip the fourth one and empty the queue.
+ ensure("is not in queue 4", !mdc->isInQueue(o4));
+ ensure("post records", gPostRecords->size(), 2);
+
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ ensure("refcount of o4", o4->getNumRefs(), 1);
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<9>()
+ {
+ //
+ // Test queue re-ordering
+ //
+ LOG_TEST(9);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"40.0","true"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"30.0","true"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"20.0","true"));
+ LLMediaDataClientObjectTest *object4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"10.0","true"));
+ LLMediaDataClientObject::ptr_t o4 = object4;
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+
+ // queue up all 4 objects. They should now be in the queue in
+ // order 1 through 4, with 4 being at the front of the queue
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+ mdc->fetchMedia(o4);
+
+ int tick_num = 0;
+
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // The first tick should remove the first one
+ ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
+
+ // Now, pretend that object 4 moved relative to the avatar such
+ // that it is now closest
+ object4->setMediaInterest(50.0);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // The second tick should still pick off item 2, but then re-sort
+ // have picked off object 4
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // The third tick should pick off object 2
+ ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
+
+ // The fourth tick should pick off object 3
+ ::pump_timers();
+ ++tick_num;
+
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
+
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ ensure("refcount of o4", o4->getNumRefs(), 1);
+ }
+
+
+ template<> template<>
+ void mediadataclient_object_t::test<10>()
+ {
+ //
+ // Test using the "round-robin" queue
+ //
+ LOG_TEST(10);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","true"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","false"));
+ LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","false"));
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+
+ // queue up all 4 objects. The first two should be in the sorted
+ // queue [2 1], the second in the round-robin queue. The queues
+ // are serviced interleaved, so we should expect:
+ // 2, 4, 1, 3
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+ mdc->fetchMedia(o4);
+
+ int tick_num = 0;
+
+ // 0
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 1 The first tick should remove object 2
+ ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_2));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 2 The second tick should send object 4, but it will still be
+ // "in the queue"
+ ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[1]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_4));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 3 The third tick should remove object 1
+ ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[2]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_1));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 4 The fourth tick should send object 3, but it will still be
+ // "in the queue"
+ ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[3]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_3));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 5 The fifth tick should now identify objects 3 and 4 as no longer
+ // needing "updating", and remove them from the queue
+ ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
+
+ ::pump_timers();
+
+ // Whew....better be empty
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ ensure("refcount of o4", o4->getNumRefs(), 1);
+ }
+
+
+ template<> template<>
+ void mediadataclient_object_t::test<11>()
+ {
+ //
+ // Test LLMediaDataClient's destructor
+ //
+ LOG_TEST(11);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ int num_refs_start = o->getNumRefs();
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+ mdc->fetchMedia(o);
+ // must tick enough times to clear refcount of mdc
+ ::pump_timers();
+ }
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ template<> template<>
+ void mediadataclient_object_t::test<12>()
+ {
+ //
+ // Test the "not interesting enough" call
+ //
+ LOG_TEST(12);
+
+ LLMediaDataClientObjectTest *object1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
+ LLMediaDataClientObject::ptr_t o1 = object1;
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","true"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","true"));
+ LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","true"));
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
+
+ // queue up all 4 objects. The first two are "interesting enough".
+ // Firing the timer 4 times should therefore leave them.
+ // Note that they should be sorted 4,3,2,1
+ // Then, we'll make one "interesting enough", fire the timer a few
+ // times, and make sure only it gets pulled off the queue
+ gMinimumInterestLevel = 2.5;
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+ mdc->fetchMedia(o4);
+
+ int tick_num = 0;
+
+ // 0
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 1 The first tick should remove object 4
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_4));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 2 The second tick should send object 3
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[1]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_3));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 3 The third tick should not pull off anything
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 4 The fourth tick (for good measure) should not pull off anything
+ ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
+
+ // Okay, now futz with object 1's interest, such that it is now
+ // "interesting enough"
+ object1->setMediaInterest((F64)5.0);
+
+ // This should sort so that the queue is now [1 2]
+ ::pump_timers();
+ ++tick_num;
+
+ // 5 The fifth tick should now identify objects 3 and 4 as no longer
+ // needing "updating", and remove them from the queue
+ ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
+ ensure(STR(tick_num) + ". post object id", (*gPostRecords)[2]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_1));
+
+ ::pump_timers();
+ ++tick_num;
+
+ // 6 The sixth tick should not pull off anything
+ ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
+ ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
+ ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
+ ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
+ ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
+
+ ::pump_timers();
+ ++tick_num;
+
+ // Whew....better NOT be empty ... o2 should still be there
+ ensure("queue not empty", !mdc->isEmpty());
+
+ // But, we need to clear the queue, or else we won't destroy MDC...
+ // this is a strange interplay between the queue timer and the MDC
+ ensure("o2 couldn't be removed from queue", mdc->removeFromQueue(o2));
+ // tick
+ ::pump_timers();
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ ensure("refcount of o4", o4->getNumRefs(), 1);
+ }
+}
diff --git a/indra/newview/tests/lltextureinfo_test.cpp b/indra/newview/tests/lltextureinfo_test.cpp
new file mode 100644
index 0000000000..8dfba46262
--- /dev/null
+++ b/indra/newview/tests/lltextureinfo_test.cpp
@@ -0,0 +1,284 @@
+/**
+ * @file llwtextureinfo_test.cpp
+ * @author Si & Gabriel
+ * @date 2009-03-30
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-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: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltextureinfo.h"
+// Dependencies
+#include "../lltextureinfodetails.cpp"
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct textureinfo_test
+ {
+ // Constructor and destructor of the test wrapper
+ textureinfo_test()
+ {
+ }
+ ~textureinfo_test()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<textureinfo_test> textureinfo_t;
+ typedef textureinfo_t::object textureinfo_object_t;
+ tut::textureinfo_t tut_textureinfo("textureinfo");
+
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLTextureInfo
+ // ---------------------------------------------------------------------------------------
+
+
+ // Test instantiation
+ template<> template<>
+ void textureinfo_object_t::test<1>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+ ensure("have we crashed?", true);
+ }
+
+ // Check lltextureinfo does not contain UUIDs we haven't added
+ template<> template<>
+ void textureinfo_object_t::test<2>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+ ensure(!tex_info.has(nonExistant));
+ }
+
+ // Check we can add a request time for a texture
+ template<> template<>
+ void textureinfo_object_t::test<3>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id, 200);
+
+ ensure_equals(tex_info.getRequestStartTime(id), 200);
+ }
+
+ // Check time for non-existant texture
+ template<> template<>
+ void textureinfo_object_t::test<4>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+ ensure_equals(tex_info.getRequestStartTime(nonExistant), 0);
+ }
+
+ // Check download complete time for non existant texture
+ template<> template<>
+ void textureinfo_object_t::test<5>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+ ensure_equals(tex_info.getRequestCompleteTime(nonExistant), 0);
+ }
+
+ // requested size is passed in correctly
+ template<> template<>
+ void textureinfo_object_t::test<6>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestSize(id, 600);
+
+ ensure_equals(tex_info.getRequestSize(id), 600);
+ }
+
+ // transport type is recorded correctly (http)
+ template<> template<>
+ void textureinfo_object_t::test<7>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+
+ ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ }
+
+ // transport type is recorded correctly (udp)
+ template<> template<>
+ void textureinfo_object_t::test<8>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_UDP);
+
+ ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_UDP);
+ }
+
+ // request offset is recorded correctly
+ template<> template<>
+ void textureinfo_object_t::test<9>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestOffset(id, 1234);
+
+ ensure_equals(tex_info.getRequestOffset(id), 1234);
+ }
+
+ // ask for averages gives us correct figure
+ template<> template<>
+ void textureinfo_object_t::test<10>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ S32 requestStartTimeOne = 200;
+ S32 requestEndTimeOne = 400;
+ S32 requestSizeOne = 1024;
+ S32 requestSizeOneBits = requestSizeOne * 8;
+ LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id1, requestStartTimeOne);
+ tex_info.setRequestSize(id1, requestSizeOne);
+ tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+ U32 requestStartTimeTwo = 100;
+ U32 requestEndTimeTwo = 500;
+ U32 requestSizeTwo = 2048;
+ S32 requestSizeTwoBits = requestSizeTwo * 8;
+ LLUUID id2("10e65d70-46fd-429f-841a-bf698e9424d4");
+ tex_info.setRequestStartTime(id2, requestStartTimeTwo);
+ tex_info.setRequestSize(id2, requestSizeTwo);
+ tex_info.setRequestType(id2, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ tex_info.setRequestCompleteTimeAndLog(id2, requestEndTimeTwo);
+
+ S32 averageBitRate = ((requestSizeOneBits/(requestEndTimeOne - requestStartTimeOne)) +
+ (requestSizeTwoBits/(requestEndTimeTwo - requestStartTimeTwo))) / 2;
+
+ S32 totalBytes = requestSizeOne + requestSizeTwo;
+
+ LLSD results = tex_info.getAverages();
+ ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), averageBitRate);
+ ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), totalBytes);
+ ensure_equals("is transport correct", results["transport"].asString(), std::string("HTTP"));
+ }
+
+ // make sure averages cleared when reset is called
+ template<> template<>
+ void textureinfo_object_t::test<11>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ S32 requestStartTimeOne = 200;
+ S32 requestEndTimeOne = 400;
+ S32 requestSizeOne = 1024;
+ LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id1, requestStartTimeOne);
+ tex_info.setRequestSize(id1, requestSizeOne);
+ tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+ tex_info.getAverages();
+ tex_info.reset();
+ LLSD results = tex_info.getAverages();
+ ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), 0);
+ ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), 0);
+ ensure_equals("is transport correct", results["transport"].asString(), std::string("NONE"));
+ }
+
+ // make sure map item removed when expired
+ template<> template<>
+ void textureinfo_object_t::test<12>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ S32 requestStartTimeOne = 200;
+ S32 requestEndTimeOne = 400;
+ S32 requestSizeOne = 1024;
+ LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id1, requestStartTimeOne);
+ tex_info.setRequestSize(id1, requestSizeOne);
+ tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+
+ ensure_equals("map item created", tex_info.getTextureInfoMapSize(), 1);
+
+ tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+ ensure_equals("map item removed when consumed", tex_info.getTextureInfoMapSize(), 0);
+ }
+}
+
diff --git a/indra/newview/tests/lltextureinfodetails_test.cpp b/indra/newview/tests/lltextureinfodetails_test.cpp
new file mode 100644
index 0000000000..aa2697fb8e
--- /dev/null
+++ b/indra/newview/tests/lltextureinfodetails_test.cpp
@@ -0,0 +1,98 @@
+/**
+ * @file llwtextureinfodetails_test.cpp
+ * @author Si & Gabriel
+ * @date 2009-03-30
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-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: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltextureinfodetails.h"
+// Dependencies
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct textureinfodetails_test
+ {
+ // Constructor and destructor of the test wrapper
+ textureinfodetails_test()
+ {
+ }
+ ~textureinfodetails_test()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<textureinfodetails_test> textureinfodetails_t;
+ typedef textureinfodetails_t::object textureinfodetails_object_t;
+ tut::textureinfodetails_t tut_textureinfodetails("textureinfodetails");
+
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLTextureInfo
+ // ---------------------------------------------------------------------------------------
+
+
+ // Test instantiation
+ template<> template<>
+ void textureinfodetails_object_t::test<1>()
+ {
+ ensure("have we crashed?", true);
+ }
+}
diff --git a/indra/newview/tests/lltexturestatsuploader_test.cpp b/indra/newview/tests/lltexturestatsuploader_test.cpp
new file mode 100644
index 0000000000..77a3e2c3d8
--- /dev/null
+++ b/indra/newview/tests/lltexturestatsuploader_test.cpp
@@ -0,0 +1,156 @@
+/**
+ * @file lltexturestatsuploader_test.cpp
+ * @author Si
+ * @date 2009-05-27
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-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: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltexturestatsuploader.h"
+// Dependencies
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+#include "boost/intrusive_ptr.hpp"
+void boost::intrusive_ptr_add_ref(LLCurl::Responder*){}
+void boost::intrusive_ptr_release(LLCurl::Responder* p){}
+const F32 HTTP_REQUEST_EXPIRY_SECS = 0.0f;
+
+static std::string most_recent_url;
+static LLSD most_recent_body;
+
+void LLHTTPClient::post(
+ const std::string& url,
+ const LLSD& body,
+ ResponderPtr,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ // set some sensor code
+ most_recent_url = url;
+ most_recent_body = body;
+ return;
+}
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct texturestatsuploader_test
+ {
+ // Constructor and destructor of the test wrapper
+ texturestatsuploader_test()
+ {
+ most_recent_url = "some sort of default text that should never match anything the tests are expecting!";
+ LLSD blank_llsd;
+ most_recent_body = blank_llsd;
+ }
+ ~texturestatsuploader_test()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<texturestatsuploader_test> texturestatsuploader_t;
+ typedef texturestatsuploader_t::object texturestatsuploader_object_t;
+ tut::texturestatsuploader_t tut_texturestatsuploader("texturestatsuploader");
+
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLTextureInfo
+ // ---------------------------------------------------------------------------------------
+
+
+ // Test instantiation
+ template<> template<>
+ void texturestatsuploader_object_t::test<1>()
+ {
+ LLTextureStatsUploader tsu;
+ llinfos << &tsu << llendl;
+ ensure("have we crashed?", true);
+ }
+
+ // does it call out to the provided url if we ask it to?
+ template<> template<>
+ void texturestatsuploader_object_t::test<2>()
+ {
+ LLTextureStatsUploader tsu;
+ std::string url = "http://blahblahblah";
+ LLSD texture_stats;
+ tsu.uploadStatsToSimulator(url, texture_stats);
+ ensure_equals("did the right url get called?", most_recent_url, url);
+ ensure_equals("did the right body get sent?", most_recent_body, texture_stats);
+ }
+
+ // does it not call out to the provided url if we send it an ungranted cap?
+ template<> template<>
+ void texturestatsuploader_object_t::test<3>()
+ {
+ LLTextureStatsUploader tsu;
+
+ // this url left intentionally blank to mirror
+ // not getting a cap in the caller.
+ std::string url_for_ungranted_cap = "";
+
+ LLSD texture_stats;
+ std::string most_recent_url_before_test = most_recent_url;
+ tsu.uploadStatsToSimulator(url_for_ungranted_cap, texture_stats);
+
+ ensure_equals("hopefully no url got called!", most_recent_url, most_recent_url_before_test);
+ }
+
+ // does it call out if the data is empty?
+ // should it even do that?
+}
+
diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp
index 40f7d532bc..eecc79d36c 100644
--- a/indra/newview/tests/llviewerhelputil_test.cpp
+++ b/indra/newview/tests/llviewerhelputil_test.cpp
@@ -30,48 +30,81 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+
#include "../test/lltut.h"
#include "../llviewerhelputil.h"
+#include "../llweb.h"
#include "llcontrol.h"
-#include "llsys.h"
#include <iostream>
-//----------------------------------------------------------------------------
-// Implementation of enough of LLControlGroup to support the tests:
+// values for all of the supported substitutions parameters
+static std::string gHelpURL;
+static std::string gVersion;
+static std::string gChannel;
+static std::string gLanguage;
+static std::string gGrid;
+static std::string gOS;
-static std::map<std::string,std::string> test_stringvec;
+//----------------------------------------------------------------------------
+// Mock objects for the dependencies of the code we're testing
LLControlGroup::LLControlGroup(const std::string& name)
- : LLInstanceTracker<LLControlGroup, std::string>(name)
-{
-}
-
-LLControlGroup::~LLControlGroup()
-{
-}
-
-// Implementation of just the LLControlGroup methods we requre
+ : LLInstanceTracker<LLControlGroup, std::string>(name) {}
+LLControlGroup::~LLControlGroup() {}
BOOL LLControlGroup::declareString(const std::string& name,
const std::string& initial_val,
const std::string& comment,
- BOOL persist)
+ BOOL persist) {return TRUE;}
+void LLControlGroup::setString(const std::string& name, const std::string& val){}
+std::string LLControlGroup::getString(const std::string& name)
{
- test_stringvec[name] = initial_val;
- return true;
+ if (name == "HelpURLFormat")
+ return gHelpURL;
+ return "";
}
+LLControlGroup gSavedSettings("test");
-void LLControlGroup::setString(const std::string& name, const std::string& val)
+static void substitute_string(std::string &input, const std::string &search, const std::string &replace)
{
- test_stringvec[name] = val;
+ size_t pos = input.find(search);
+ while (pos != std::string::npos)
+ {
+ input = input.replace(pos, search.size(), replace);
+ pos = input.find(search);
+ }
}
-std::string LLControlGroup::getString(const std::string& name)
+class LLAgent
{
- return test_stringvec[name];
+public:
+ LLAgent() {}
+ ~LLAgent() {}
+#ifdef __GNUC__
+ __attribute__ ((noinline))
+#endif
+ bool isGodlike() const { return FALSE; }
+};
+LLAgent gAgent;
+
+std::string LLWeb::expandURLSubstitutions(const std::string &url,
+ const LLSD &default_subs)
+{
+ (void)gAgent.isGodlike(); // ref symbol to stop compiler from stripping it
+ std::string new_url = url;
+ substitute_string(new_url, "[TOPIC]", default_subs["TOPIC"].asString());
+ substitute_string(new_url, "[VERSION]", gVersion);
+ substitute_string(new_url, "[CHANNEL]", gChannel);
+ substitute_string(new_url, "[LANGUAGE]", gLanguage);
+ substitute_string(new_url, "[GRID]", gGrid);
+ substitute_string(new_url, "[OS]", gOS);
+ return new_url;
}
+
//----------------------------------------------------------------------------
namespace tut
@@ -87,41 +120,52 @@ namespace tut
template<> template<>
void viewerhelputil_object_t::test<1>()
{
- LLOSInfo osinfo;
- LLControlGroup cgr("test");
- cgr.declareString("HelpURLFormat", "fooformat", "declared_for_test", FALSE);
- cgr.declareString("VersionChannelName", "foochannelname", "declared_for_test", FALSE);
- cgr.declareString("Language", "foolanguage", "declared_for_test", FALSE);
std::string topic("test_topic");
-
std::string subresult;
- cgr.setString("HelpURLFormat", "fooformat");
- subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo);
+ gHelpURL = "fooformat";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
ensure_equals("no substitution tags", subresult, "fooformat");
- cgr.setString("HelpURLFormat", "");
- subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo);
+ gHelpURL = "";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
ensure_equals("blank substitution format", subresult, "");
- cgr.setString("HelpURLFormat", "[LANGUAGE]");
- cgr.setString("Language", "");
- subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo);
+ gHelpURL = "[TOPIC]";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
+ ensure_equals("topic name", subresult, "test_topic");
+
+ gHelpURL = "[LANGUAGE]";
+ gLanguage = "";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
ensure_equals("simple substitution with blank", subresult, "");
- cgr.setString("HelpURLFormat", "[LANGUAGE]");
- cgr.setString("Language", "Esperanto");
- subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo);
+ gHelpURL = "[LANGUAGE]";
+ gLanguage = "Esperanto";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
ensure_equals("simple substitution", subresult, "Esperanto");
- cgr.setString("HelpURLFormat", "[XXX]");
- subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo);
+ gHelpURL = "http://secondlife.com/[LANGUAGE]";
+ gLanguage = "Gaelic";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
+ ensure_equals("simple substitution with url", subresult, "http://secondlife.com/Gaelic");
+
+ gHelpURL = "[XXX]";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
ensure_equals("unknown substitution", subresult, "[XXX]");
- cgr.setString("HelpURLFormat", "[LANGUAGE]/[LANGUAGE]");
- cgr.setString("Language", "Esperanto");
- subresult = LLViewerHelpUtil::buildHelpURL(topic, cgr, osinfo);
+ gHelpURL = "[LANGUAGE]/[LANGUAGE]";
+ gLanguage = "Esperanto";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
ensure_equals("multiple substitution", subresult, "Esperanto/Esperanto");
+
+ gHelpURL = "http://[CHANNEL]/[VERSION]/[LANGUAGE]/[OS]/[GRID]/[XXX]";
+ gChannel = "Second Life Test";
+ gVersion = "2.0";
+ gLanguage = "gaelic";
+ gOS = "AmigaOS 2.1";
+ gGrid = "mysim";
+ subresult = LLViewerHelpUtil::buildHelpURL(topic);
+ ensure_equals("complex substitution", subresult, "http://Second Life Test/2.0/gaelic/AmigaOS 2.1/mysim/[XXX]");
}
-
}
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
new file mode 100644
index 0000000000..56cf86f6df
--- /dev/null
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -0,0 +1,523 @@
+/**
+ * @file llworldmap_test.cpp
+ * @author Merov Linden
+ * @date 2009-03-09
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-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: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../llworldmap.h"
+// Dependencies
+#include "../llviewerimagelist.h"
+#include "../llworldmapmessage.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+// Stub image calls
+LLViewerImageList::LLViewerImageList() { }
+LLViewerImageList::~LLViewerImageList() { }
+LLViewerImageList gImageList;
+LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
+ BOOL usemipmaps,
+ BOOL level_immediate,
+ LLGLint internal_format,
+ LLGLenum primary_format,
+ LLHost request_from_host)
+{ return NULL; }
+void LLViewerImage::setBoostLevel(S32 level) { }
+void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { }
+
+// Stub related map calls
+LLWorldMapMessage::LLWorldMapMessage() { }
+LLWorldMapMessage::~LLWorldMapMessage() { }
+void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) { }
+void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { }
+LLWorldMipmap::LLWorldMipmap() { }
+LLWorldMipmap::~LLWorldMipmap() { }
+void LLWorldMipmap::reset() { }
+void LLWorldMipmap::dropBoostLevels() { }
+void LLWorldMipmap::equalizeBoostLevels() { }
+LLPointer<LLViewerImage> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load)
+{ return NULL; }
+
+// Stub other stuff
+BOOL gPacificDaylightTime;
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+const F32 X_WORLD_TEST = 1000.0f * REGION_WIDTH_METERS;
+const F32 Y_WORLD_TEST = 2000.0f * REGION_WIDTH_METERS;
+const F32 Z_WORLD_TEST = 240.0f;
+const std::string ITEM_NAME_TEST = "Item Foo";
+const std::string TOOLTIP_TEST = "Tooltip Foo";
+
+const std::string SIM_NAME_TEST = "Sim Foo";
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct iteminfo_test
+ {
+ // Instance to be tested
+ LLItemInfo* mItem;
+
+ // Constructor and destructor of the test wrapper
+ iteminfo_test()
+ {
+ LLUUID id;
+ mItem = new LLItemInfo(X_WORLD_TEST, Y_WORLD_TEST, ITEM_NAME_TEST, id);
+ }
+ ~iteminfo_test()
+ {
+ delete mItem;
+ }
+ };
+
+ struct siminfo_test
+ {
+ // Instance to be tested
+ LLSimInfo* mSim;
+
+ // Constructor and destructor of the test wrapper
+ siminfo_test()
+ {
+ U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+ mSim = new LLSimInfo(handle);
+ }
+ ~siminfo_test()
+ {
+ delete mSim;
+ }
+ };
+
+ struct worldmap_test
+ {
+ // Instance to be tested
+ LLWorldMap* mWorld;
+
+ // Constructor and destructor of the test wrapper
+ worldmap_test()
+ {
+ mWorld = LLWorldMap::getInstance();
+ }
+ ~worldmap_test()
+ {
+ mWorld = NULL;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<iteminfo_test> iteminfo_t;
+ typedef iteminfo_t::object iteminfo_object_t;
+ tut::iteminfo_t tut_iteminfo("iteminfo");
+
+ typedef test_group<siminfo_test> siminfo_t;
+ typedef siminfo_t::object siminfo_object_t;
+ tut::siminfo_t tut_siminfo("siminfo");
+
+ typedef test_group<worldmap_test> worldmap_t;
+ typedef worldmap_t::object worldmap_object_t;
+ tut::worldmap_t tut_worldmap("worldmap");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLItemInfo interface
+ // ---------------------------------------------------------------------------------------
+ template<> template<>
+ void iteminfo_object_t::test<1>()
+ {
+ // Test 1 : setCount() / getCount()
+ mItem->setCount(10);
+ ensure("LLItemInfo::setCount() test failed", mItem->getCount() == 10);
+ // Test 2 : setTooltip() / getToolTip()
+ std::string tooltip = TOOLTIP_TEST;
+ mItem->setTooltip(tooltip);
+ ensure("LLItemInfo::setTooltip() test failed", mItem->getToolTip() == TOOLTIP_TEST);
+ // Test 3 : setElevation() / getGlobalPosition()
+ mItem->setElevation(Z_WORLD_TEST);
+ LLVector3d pos = mItem->getGlobalPosition();
+ LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, Z_WORLD_TEST);
+ ensure("LLItemInfo::getGlobalPosition() test failed", pos == ref);
+ // Test 4 : getName()
+ std::string name = mItem->getName();
+ ensure("LLItemInfo::getName() test failed", name == ITEM_NAME_TEST);
+ // Test 5 : isName()
+ ensure("LLItemInfo::isName() test failed", mItem->isName(name));
+ // Test 6 : getUUID()
+ LLUUID id;
+ ensure("LLItemInfo::getUUID() test failed", mItem->getUUID() == id);
+ // Test 7 : getRegionHandle()
+ U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+ ensure("LLItemInfo::getRegionHandle() test failed", mItem->getRegionHandle() == handle);
+ }
+ // ---------------------------------------------------------------------------------------
+ // Test the LLSimInfo interface
+ // ---------------------------------------------------------------------------------------
+ // Test Setters and Accessors methods
+ template<> template<>
+ void siminfo_object_t::test<1>()
+ {
+ // Test 1 : setName() / getName()
+ std::string name = SIM_NAME_TEST;
+ mSim->setName(name);
+ ensure("LLSimInfo::setName() test failed", mSim->getName() == SIM_NAME_TEST);
+ // Test 2 : isName()
+ ensure("LLSimInfo::isName() test failed", mSim->isName(name));
+ // Test 3 : getGlobalPos()
+ LLVector3 local;
+ LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, 0.0f);
+ LLVector3d pos = mSim->getGlobalPos(local);
+ ensure("LLSimInfo::getGlobalPos() test failed", pos == ref);
+ // Test 4 : getGlobalOrigin()
+ pos = mSim->getGlobalOrigin();
+ ensure("LLSimInfo::getGlobalOrigin() test failed", pos == ref);
+ // Test 5 : clearImage()
+ try {
+ mSim->clearImage();
+ } catch (...) {
+ fail("LLSimInfo::clearImage() test failed");
+ }
+ // Test 6 : dropImagePriority()
+ try {
+ mSim->dropImagePriority();
+ } catch (...) {
+ fail("LLSimInfo::dropImagePriority() test failed");
+ }
+ // Test 7 : updateAgentCount()
+ try {
+ mSim->updateAgentCount(0.0f);
+ } catch (...) {
+ fail("LLSimInfo::updateAgentCount() test failed");
+ }
+ // Test 8 : getAgentCount()
+ S32 agents = mSim->getAgentCount();
+ ensure("LLSimInfo::getAgentCount() test failed", agents == 0);
+ // Test 9 : setLandForSaleImage() / getLandForSaleImage()
+ LLUUID id;
+ mSim->setLandForSaleImage(id);
+ LLPointer<LLViewerImage> image = mSim->getLandForSaleImage();
+ ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull());
+ // Test 10 : isPG()
+ mSim->setAccess(SIM_ACCESS_PG);
+ ensure("LLSimInfo::isPG() test failed", mSim->isPG());
+ // Test 11 : isDown()
+ mSim->setAccess(SIM_ACCESS_DOWN);
+ ensure("LLSimInfo::isDown() test failed", mSim->isDown());
+ // Test 12 : Access strings can't be accessed from unit test...
+ //ensure("LLSimInfo::getAccessString() test failed", mSim->getAccessString() == "Offline");
+ // Test 13 : Region strings can't be accessed from unit test...
+ //mSim->setRegionFlags(REGION_FLAGS_SANDBOX);
+ //ensure("LLSimInfo::setRegionFlags() test failed", mSim->getFlagsString() == "Sandbox");
+ }
+ // Test management of LLInfoItem lists
+ template<> template<>
+ void siminfo_object_t::test<2>()
+ {
+ // Test 14 : clearItems()
+ try {
+ mSim->clearItems();
+ } catch (...) {
+ fail("LLSimInfo::clearItems() at init test failed");
+ }
+
+ // Test 15 : Verify that all the lists are empty
+ LLSimInfo::item_info_list_t list;
+ list = mSim->getTeleHub();
+ ensure("LLSimInfo::getTeleHub() empty at init test failed", list.empty());
+ list = mSim->getInfoHub();
+ ensure("LLSimInfo::getInfoHub() empty at init test failed", list.empty());
+ list = mSim->getPGEvent();
+ ensure("LLSimInfo::getPGEvent() empty at init test failed", list.empty());
+ list = mSim->getMatureEvent();
+ ensure("LLSimInfo::getMatureEvent() empty at init test failed", list.empty());
+ list = mSim->getLandForSale();
+ ensure("LLSimInfo::getLandForSale() empty at init test failed", list.empty());
+ list = mSim->getAgentLocation();
+ ensure("LLSimInfo::getAgentLocation() empty at init test failed", list.empty());
+
+ // Create an item to be inserted
+ LLUUID id;
+ LLItemInfo item(X_WORLD_TEST, Y_WORLD_TEST, ITEM_NAME_TEST, id);
+
+ // Insert the item in each list
+ mSim->insertTeleHub(item);
+ mSim->insertInfoHub(item);
+ mSim->insertPGEvent(item);
+ mSim->insertMatureEvent(item);
+ mSim->insertLandForSale(item);
+ mSim->insertAgentLocation(item);
+
+ // Test 16 : Verify that the lists contain 1 item each
+ list = mSim->getTeleHub();
+ ensure("LLSimInfo::insertTeleHub() test failed", list.size() == 1);
+ list = mSim->getInfoHub();
+ ensure("LLSimInfo::insertInfoHub() test failed", list.size() == 1);
+ list = mSim->getPGEvent();
+ ensure("LLSimInfo::insertPGEvent() test failed", list.size() == 1);
+ list = mSim->getMatureEvent();
+ ensure("LLSimInfo::insertMatureEvent() test failed", list.size() == 1);
+ list = mSim->getLandForSale();
+ ensure("LLSimInfo::insertLandForSale() test failed", list.size() == 1);
+ list = mSim->getAgentLocation();
+ ensure("LLSimInfo::insertAgentLocation() test failed", list.size() == 1);
+
+ // Test 17 : clearItems()
+ try {
+ mSim->clearItems();
+ } catch (...) {
+ fail("LLSimInfo::clearItems() at end test failed");
+ }
+
+ // Test 18 : Verify that all the lists are empty again... *except* agent which is persisted!! (on purpose)
+ list = mSim->getTeleHub();
+ ensure("LLSimInfo::getTeleHub() empty after clear test failed", list.empty());
+ list = mSim->getInfoHub();
+ ensure("LLSimInfo::getInfoHub() empty after clear test failed", list.empty());
+ list = mSim->getPGEvent();
+ ensure("LLSimInfo::getPGEvent() empty after clear test failed", list.empty());
+ list = mSim->getMatureEvent();
+ ensure("LLSimInfo::getMatureEvent() empty after clear test failed", list.empty());
+ list = mSim->getLandForSale();
+ ensure("LLSimInfo::getLandForSale() empty after clear test failed", list.empty());
+ list = mSim->getAgentLocation();
+ ensure("LLSimInfo::getAgentLocation() empty after clear test failed", list.size() == 1);
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLWorldMap interface
+ // ---------------------------------------------------------------------------------------
+ // Test Setters and Accessors methods
+ template<> template<>
+ void worldmap_object_t::test<1>()
+ {
+ // Test 1 : reset()
+ try {
+ mWorld->reset();
+ } catch (...) {
+ fail("LLWorldMap::reset() at init test failed");
+ }
+ // Test 2 : clearImageRefs()
+ try {
+ mWorld->clearImageRefs();
+ } catch (...) {
+ fail("LLWorldMap::clearImageRefs() test failed");
+ }
+ // Test 3 : dropImagePriorities()
+ try {
+ mWorld->dropImagePriorities();
+ } catch (...) {
+ fail("LLWorldMap::dropImagePriorities() test failed");
+ }
+ // Test 4 : reloadItems()
+ try {
+ mWorld->reloadItems(true);
+ } catch (...) {
+ fail("LLWorldMap::reloadItems() test failed");
+ }
+ // Test 5 : updateRegions()
+ try {
+ mWorld->updateRegions(1000, 1000, 1004, 1004);
+ } catch (...) {
+ fail("LLWorldMap::updateRegions() test failed");
+ }
+ // Test 6 : equalizeBoostLevels()
+ try {
+ mWorld->equalizeBoostLevels();
+ } catch (...) {
+ fail("LLWorldMap::equalizeBoostLevels() test failed");
+ }
+ // Test 7 : getObjectsTile()
+ try {
+ LLPointer<LLViewerImage> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
+ ensure("LLWorldMap::getObjectsTile() failed", image.isNull());
+ } catch (...) {
+ fail("LLWorldMap::getObjectsTile() test failed with exception");
+ }
+ }
+ // Test management of LLSimInfo lists
+ template<> template<>
+ void worldmap_object_t::test<2>()
+ {
+ // Test 8 : reset()
+ try {
+ mWorld->reset();
+ } catch (...) {
+ fail("LLWorldMap::reset() at init test failed");
+ }
+
+ // Test 9 : Verify that all the region list is empty
+ LLWorldMap::sim_info_map_t list;
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::getRegionMap() empty at init test failed", list.empty());
+
+ // Test 10 : Insert a region
+ bool success;
+ LLUUID id;
+ std::string name_sim = SIM_NAME_TEST;
+ success = mWorld->insertRegion( U32(X_WORLD_TEST),
+ U32(Y_WORLD_TEST),
+ name_sim,
+ id,
+ SIM_ACCESS_PG,
+ REGION_FLAGS_SANDBOX);
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::insertRegion() failed", success && (list.size() == 1));
+
+ // Test 11 : Insert an item in the same region -> number of regions doesn't increase
+ std::string name_item = ITEM_NAME_TEST;
+ success = mWorld->insertItem( U32(X_WORLD_TEST + REGION_WIDTH_METERS/2),
+ U32(Y_WORLD_TEST + REGION_WIDTH_METERS/2),
+ name_item,
+ id,
+ MAP_ITEM_LAND_FOR_SALE,
+ 0, 0);
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::insertItem() in existing region failed", success && (list.size() == 1));
+
+ // Test 12 : Insert an item in another region -> number of regions increases
+ success = mWorld->insertItem( U32(X_WORLD_TEST + REGION_WIDTH_METERS*2),
+ U32(Y_WORLD_TEST + REGION_WIDTH_METERS*2),
+ name_item,
+ id,
+ MAP_ITEM_LAND_FOR_SALE,
+ 0, 0);
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::insertItem() in unexisting region failed", success && (list.size() == 2));
+
+ // Test 13 : simInfoFromPosGlobal() in region
+ LLVector3d pos1( X_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2,
+ Y_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2,
+ 0.0f);
+ LLSimInfo* sim;
+ sim = mWorld->simInfoFromPosGlobal(pos1);
+ ensure("LLWorldMap::simInfoFromPosGlobal() test on existing region failed", sim != NULL);
+
+ // Test 14 : simInfoFromPosGlobal() outside region
+ LLVector3d pos2( X_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2,
+ Y_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2,
+ 0.0f);
+ sim = mWorld->simInfoFromPosGlobal(pos2);
+ ensure("LLWorldMap::simInfoFromPosGlobal() test outside region failed", sim == NULL);
+
+ // Test 15 : simInfoFromName()
+ sim = mWorld->simInfoFromName(name_sim);
+ ensure("LLWorldMap::simInfoFromName() test on existing region failed", sim != NULL);
+
+ // Test 16 : simInfoFromHandle()
+ U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+ sim = mWorld->simInfoFromHandle(handle);
+ ensure("LLWorldMap::simInfoFromHandle() test on existing region failed", sim != NULL);
+
+ // Test 17 : simNameFromPosGlobal()
+ LLVector3d pos3( X_WORLD_TEST + REGION_WIDTH_METERS/2,
+ Y_WORLD_TEST + REGION_WIDTH_METERS/2,
+ 0.0f);
+ success = mWorld->simNameFromPosGlobal(pos3, name_sim);
+ ensure("LLWorldMap::simNameFromPosGlobal() test on existing region failed", success && (name_sim == SIM_NAME_TEST));
+
+ // Test 18 : reset()
+ try {
+ mWorld->reset();
+ } catch (...) {
+ fail("LLWorldMap::reset() at end test failed");
+ }
+
+ // Test 19 : Verify that all the region list is empty
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::getRegionMap() empty at end test failed", list.empty());
+ }
+ // Test tracking
+ template<> template<>
+ void worldmap_object_t::test<3>()
+ {
+ // Point to track
+ LLVector3d pos( X_WORLD_TEST + REGION_WIDTH_METERS/2, Y_WORLD_TEST + REGION_WIDTH_METERS/2, Z_WORLD_TEST);
+
+ // Test 20 : no tracking
+ mWorld->cancelTracking();
+ ensure("LLWorldMap::cancelTracking() at begin test failed", mWorld->isTracking() == false);
+
+ // Test 21 : set tracking
+ mWorld->setTracking(pos);
+ ensure("LLWorldMap::setTracking() failed", mWorld->isTracking() && !mWorld->isTrackingValidLocation());
+
+ // Test 22 : set click and commit flags
+ mWorld->setTrackingDoubleClick();
+ ensure("LLWorldMap::setTrackingDoubleClick() failed", mWorld->isTrackingDoubleClick());
+ mWorld->setTrackingCommit();
+ ensure("LLWorldMap::setTrackingCommit() failed", mWorld->isTrackingCommit());
+
+ // Test 23 : in rectangle test
+ bool inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST, Y_WORLD_TEST,
+ X_WORLD_TEST + REGION_WIDTH_METERS,
+ Y_WORLD_TEST + REGION_WIDTH_METERS);
+ ensure("LLWorldMap::isTrackingInRectangle() in rectangle failed", inRect);
+ inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST + REGION_WIDTH_METERS,
+ Y_WORLD_TEST + REGION_WIDTH_METERS,
+ X_WORLD_TEST + 2 * REGION_WIDTH_METERS,
+ Y_WORLD_TEST + 2 * REGION_WIDTH_METERS);
+ ensure("LLWorldMap::isTrackingInRectangle() outside rectangle failed", !inRect);
+
+ // Test 24 : set tracking to valid and invalid
+ mWorld->setTrackingValid();
+ ensure("LLWorldMap::setTrackingValid() failed", mWorld->isTrackingValidLocation() && !mWorld->isTrackingInvalidLocation());
+ mWorld->setTrackingInvalid();
+ ensure("LLWorldMap::setTrackingInvalid() failed", !mWorld->isTrackingValidLocation() && mWorld->isTrackingInvalidLocation());
+
+ // Test 25 : getTrackedPositionGlobal()
+ LLVector3d res = mWorld->getTrackedPositionGlobal();
+ ensure("LLWorldMap::getTrackedPositionGlobal() failed", res == pos);
+
+ // Test 26 : reset tracking
+ mWorld->cancelTracking();
+ ensure("LLWorldMap::cancelTracking() at end test failed", mWorld->isTracking() == false);
+ }
+}
diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp
new file mode 100644
index 0000000000..9938175c55
--- /dev/null
+++ b/indra/newview/tests/llworldmipmap_test.cpp
@@ -0,0 +1,176 @@
+/**
+ * @file llworldmipmap_test.cpp
+ * @author Merov Linden
+ * @date 2009-02-03
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-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: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../llworldmipmap.h"
+// Dependencies
+#include "../llviewerimagelist.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+LLViewerImageList::LLViewerImageList() { }
+LLViewerImageList::~LLViewerImageList() { }
+
+LLViewerImageList gImageList;
+
+LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url,
+ BOOL usemipmaps,
+ BOOL level_immediate,
+ LLGLint internal_format,
+ LLGLenum primary_format,
+ const LLUUID& force_id)
+{ return NULL; }
+void LLViewerImage::setBoostLevel(S32 level) { }
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+ // Test wrapper declaration
+ struct worldmipmap_test
+ {
+ // Derived test class
+ class LLTestWorldMipmap : public LLWorldMipmap
+ {
+ // Put here stubbs of virtual methods we shouldn't call all the way down
+ };
+ // Instance to be tested
+ LLTestWorldMipmap* mMap;
+
+ // Constructor and destructor of the test wrapper
+ worldmipmap_test()
+ {
+ mMap = new LLTestWorldMipmap;
+ }
+ ~worldmipmap_test()
+ {
+ delete mMap;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<worldmipmap_test> worldmipmap_t;
+ typedef worldmipmap_t::object worldmipmap_object_t;
+ tut::worldmipmap_t tut_worldmipmap("worldmipmap");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+ // Test static methods
+ // Test 1 : scaleToLevel()
+ template<> template<>
+ void worldmipmap_object_t::test<1>()
+ {
+ S32 level = mMap->scaleToLevel(0.0);
+ ensure("scaleToLevel() test 1 failed", level == LLWorldMipmap::MAP_LEVELS);
+ level = mMap->scaleToLevel(LLWorldMipmap::MAP_TILE_SIZE);
+ ensure("scaleToLevel() test 2 failed", level == 1);
+ level = mMap->scaleToLevel(10 * LLWorldMipmap::MAP_TILE_SIZE);
+ ensure("scaleToLevel() test 3 failed", level == 1);
+ }
+ // Test 2 : globalToMipmap()
+ template<> template<>
+ void worldmipmap_object_t::test<2>()
+ {
+ U32 grid_x, grid_y;
+ mMap->globalToMipmap(1000.f*REGION_WIDTH_METERS, 1000.f*REGION_WIDTH_METERS, 1, &grid_x, &grid_y);
+ ensure("globalToMipmap() test 1 failed", (grid_x == 1000) && (grid_y == 1000));
+ mMap->globalToMipmap(0.0, 0.0, LLWorldMipmap::MAP_LEVELS, &grid_x, &grid_y);
+ ensure("globalToMipmap() test 2 failed", (grid_x == 0) && (grid_y == 0));
+ }
+ // Test 3 : getObjectsTile()
+ template<> template<>
+ void worldmipmap_object_t::test<3>()
+ {
+ // Depends on some inline methods in LLViewerImage... Thinking about how to make this work
+ // LLPointer<LLViewerImage> img = mMap->getObjectsTile(0, 0, 1);
+ // ensure("getObjectsTile() test failed", img.isNull());
+ }
+ // Test 4 : equalizeBoostLevels()
+ template<> template<>
+ void worldmipmap_object_t::test<4>()
+ {
+ try
+ {
+ mMap->equalizeBoostLevels();
+ }
+ catch (...)
+ {
+ fail("equalizeBoostLevels() test failed");
+ }
+ }
+ // Test 5 : dropBoostLevels()
+ template<> template<>
+ void worldmipmap_object_t::test<5>()
+ {
+ try
+ {
+ mMap->dropBoostLevels();
+ }
+ catch (...)
+ {
+ fail("dropBoostLevels() test failed");
+ }
+ }
+ // Test 6 : reset()
+ template<> template<>
+ void worldmipmap_object_t::test<6>()
+ {
+ try
+ {
+ mMap->reset();
+ }
+ catch (...)
+ {
+ fail("reset() test failed");
+ }
+ }
+}
diff --git a/indra/newview/tests/llxmlrpclistener_test.cpp b/indra/newview/tests/llxmlrpclistener_test.cpp
new file mode 100644
index 0000000000..c2c7e963b9
--- /dev/null
+++ b/indra/newview/tests/llxmlrpclistener_test.cpp
@@ -0,0 +1,230 @@
+/*
+ * @file llxmlrpclistener_test.cpp
+ * @author Nat Goodspeed
+ * @date 2009-03-20
+ * @brief Test for llxmlrpclistener.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+// associated header
+#include "../llxmlrpclistener.h"
+// STL headers
+#include <iomanip>
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "../llxmlrpctransaction.h"
+#include "llevents.h"
+#include "lleventfilter.h"
+#include "llsd.h"
+#include "llcontrol.h"
+#include "tests/wrapllerrs.h"
+
+LLControlGroup gSavedSettings("Global");
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct data
+ {
+ data():
+ pumps(LLEventPumps::instance()),
+ uri("http://127.0.0.1:8000")
+ {
+ // These variables are required by machinery used by
+ // LLXMLRPCTransaction. The values reflect reality for this test
+ // executable; hopefully these values are correct.
+ gSavedSettings.declareBOOL("BrowserProxyEnabled", FALSE, "", FALSE); // don't persist
+ gSavedSettings.declareBOOL("NoVerifySSLCert", TRUE, "", FALSE); // don't persist
+ }
+
+ // LLEventPump listener signature
+ bool captureReply(const LLSD& r)
+ {
+ reply = r;
+ return false;
+ }
+
+ LLSD reply;
+ LLEventPumps& pumps;
+ std::string uri;
+ };
+ typedef test_group<data> llxmlrpclistener_group;
+ typedef llxmlrpclistener_group::object object;
+ llxmlrpclistener_group llxmlrpclistenergrp("llxmlrpclistener");
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("request validation");
+ WrapLL_ERRS capture;
+ LLSD request;
+ request["uri"] = uri;
+ std::string threw;
+ try
+ {
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ threw = e.what();
+ }
+ ensure_contains("threw exception", threw, "missing params");
+ ensure_contains("identified missing", threw, "method");
+ ensure_contains("identified missing", threw, "reply");
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("param types validation");
+ WrapLL_ERRS capture;
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "hello";
+ request["reply"] = "reply";
+ LLSD& params(request["params"]);
+ params["who"]["specifically"] = "world"; // LLXMLRPCListener only handles scalar params
+ std::string threw;
+ try
+ {
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ threw = e.what();
+ }
+ ensure_contains("threw exception", threw, "unknown type");
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("success case");
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "hello";
+ request["reply"] = "reply";
+ LLSD& params(request["params"]);
+ params["who"] = "world";
+ // Set up a timeout filter so we don't spin forever waiting.
+ LLEventTimeout watchdog;
+ // Connect the timeout filter to the reply pump.
+ LLTempBoundListener temp(
+ pumps.obtain("reply").
+ listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+ // Now connect our target listener to the timeout filter.
+ watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+ // Kick off the request...
+ reply.clear();
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ // Set the timer
+ F32 timeout(10);
+ watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ // and pump "mainloop" until we get something, whether from
+ // LLXMLRPCListener or from the watchdog filter.
+ LLTimer timer;
+ F32 start = timer.getElapsedTimeF32();
+ LLEventPump& mainloop(pumps.obtain("mainloop"));
+ while (reply.isUndefined())
+ {
+ mainloop.post(LLSD());
+ }
+ ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+ ensure_equals(reply["responses"]["hi_there"].asString(), "Hello, world!");
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ set_test_name("bogus method");
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "goodbye";
+ request["reply"] = "reply";
+ LLSD& params(request["params"]);
+ params["who"] = "world";
+ // Set up a timeout filter so we don't spin forever waiting.
+ LLEventTimeout watchdog;
+ // Connect the timeout filter to the reply pump.
+ LLTempBoundListener temp(
+ pumps.obtain("reply").
+ listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+ // Now connect our target listener to the timeout filter.
+ watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+ // Kick off the request...
+ reply.clear();
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ // Set the timer
+ F32 timeout(10);
+ watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ // and pump "mainloop" until we get something, whether from
+ // LLXMLRPCListener or from the watchdog filter.
+ LLTimer timer;
+ F32 start = timer.getElapsedTimeF32();
+ LLEventPump& mainloop(pumps.obtain("mainloop"));
+ while (reply.isUndefined())
+ {
+ mainloop.post(LLSD());
+ }
+ ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+ ensure_equals("XMLRPC error", reply["status"].asString(), "XMLRPCError");
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ set_test_name("bad type");
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "getdict";
+ request["reply"] = "reply";
+ (void)request["params"];
+ // Set up a timeout filter so we don't spin forever waiting.
+ LLEventTimeout watchdog;
+ // Connect the timeout filter to the reply pump.
+ LLTempBoundListener temp(
+ pumps.obtain("reply").
+ listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+ // Now connect our target listener to the timeout filter.
+ watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+ // Kick off the request...
+ reply.clear();
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ // Set the timer
+ F32 timeout(10);
+ watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ // and pump "mainloop" until we get something, whether from
+ // LLXMLRPCListener or from the watchdog filter.
+ LLTimer timer;
+ F32 start = timer.getElapsedTimeF32();
+ LLEventPump& mainloop(pumps.obtain("mainloop"));
+ while (reply.isUndefined())
+ {
+ mainloop.post(LLSD());
+ }
+ ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+ ensure_equals(reply["status"].asString(), "BadType");
+ ensure_contains("bad type", reply["responses"]["nested_dict"].asString(), "bad XMLRPC type");
+ }
+} // namespace tut
+
+/*****************************************************************************
+* Resolve link errors: use real machinery here, since we intend to exchange
+* actual XML with a peer process.
+*****************************************************************************/
+// Including llxmlrpctransaction.cpp drags in the static LLXMLRPCListener
+// instantiated there. That's why it works to post requests to the LLEventPump
+// named "LLXMLRPCTransaction".
+#include "../llxmlrpctransaction.cpp"
+#include "llcontrol.cpp"
+#include "llxmltree.cpp"
+#include "llxmlparser.cpp"
diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py
new file mode 100644
index 0000000000..cb8f7d26c4
--- /dev/null
+++ b/indra/newview/tests/test_llxmlrpc_peer.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+"""\
+@file test_llxmlrpc_peer.py
+@author Nat Goodspeed
+@date 2008-10-09
+@brief This script asynchronously runs the executable (with args) specified on
+ the command line, returning its result code. While that executable is
+ running, we provide dummy local services for use by C++ tests.
+
+$LicenseInfo:firstyear=2008&license=viewergpl$
+Copyright (c) 2008, Linden Research, Inc.
+$/LicenseInfo$
+"""
+
+import os
+import sys
+from threading import Thread
+from SimpleXMLRPCServer import SimpleXMLRPCServer
+
+mydir = os.path.dirname(__file__) # expected to be .../indra/newview/tests/
+sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
+sys.path.insert(1, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests"))
+from testrunner import run, debug
+
+class TestServer(SimpleXMLRPCServer):
+ def _dispatch(self, method, params):
+ try:
+ func = getattr(self, method)
+ except AttributeError:
+ raise Exception('method "%s" is not supported' % method)
+ else:
+ # LLXMLRPCListener constructs XMLRPC parameters that arrive as a
+ # 1-tuple containing a dict.
+ return func(**(params[0]))
+
+ def hello(self, who):
+ # LLXMLRPCListener expects a dict return.
+ return {"hi_there": "Hello, %s!" % who}
+
+ def getdict(self):
+ return dict(nested_dict=dict(a=17, b=5))
+
+ def log_request(self, code, size=None):
+ # For present purposes, we don't want the request splattered onto
+ # stderr, as it would upset devs watching the test run
+ pass
+
+ def log_error(self, format, *args):
+ # Suppress error output as well
+ pass
+
+class ServerRunner(Thread):
+ def run(self):
+ server = TestServer(('127.0.0.1', 8000))
+ debug("Starting XMLRPC server...\n")
+ server.serve_forever()
+
+if __name__ == "__main__":
+ sys.exit(run(server=ServerRunner(name="xmlrpc"), *sys.argv[1:]))