summaryrefslogtreecommitdiff
path: root/indra/llui/tests
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/tests')
-rw-r--r--indra/llui/tests/llurlentry_stub.cpp64
-rw-r--r--indra/llui/tests/llurlentry_test.cpp535
-rw-r--r--indra/llui/tests/llurlmatch_test.cpp177
3 files changed, 776 insertions, 0 deletions
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
new file mode 100644
index 0000000000..05bd5d8bb3
--- /dev/null
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -0,0 +1,64 @@
+/**
+ * @file llurlentry_stub.cpp
+ * @author Martin Reddy
+ * @brief Stub implementations for LLUrlEntry unit test dependencies
+ *
+ * $LicenseInfo:firstyear=2009&license=internal$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
+ * this source code is governed by the Linden Lab Source Code Disclosure
+ * Agreement ("Agreement") previously entered between you and Linden
+ * Lab. By accessing, using, copying, modifying or distributing this
+ * software, you acknowledge that you have been informed of your
+ * obligations under the Agreement 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 "llstring.h"
+#include "llfile.h"
+#include "llcachename.h"
+#include "lluuid.h"
+
+#include <string>
+
+//
+// Stub implementation for LLCacheName
+//
+BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
+{
+ fullname = "Lynx Linden";
+ return TRUE;
+}
+
+BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
+{
+ group = "My Group";
+ return TRUE;
+}
+
+boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback)
+{
+ return boost::signals2::connection();
+}
+
+LLCacheName* gCacheName = NULL;
+
+//
+// Stub implementation for LLTrans
+//
+class LLTrans
+{
+public:
+ static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args);
+};
+
+std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args)
+{
+ return std::string();
+}
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
new file mode 100644
index 0000000000..f8e6aa65d0
--- /dev/null
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -0,0 +1,535 @@
+/**
+ * @file llurlentry_test.cpp
+ * @author Martin Reddy
+ * @brief Unit tests for LLUrlEntry objects
+ *
+ * $LicenseInfo:firstyear=2009&license=internal$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
+ * this source code is governed by the Linden Lab Source Code Disclosure
+ * Agreement ("Agreement") previously entered between you and Linden
+ * Lab. By accessing, using, copying, modifying or distributing this
+ * software, you acknowledge that you have been informed of your
+ * obligations under the Agreement 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 "../llurlentry.h"
+#include "llurlentry_stub.cpp"
+#include "lltut.h"
+
+#include <boost/regex.hpp>
+
+namespace tut
+{
+ struct LLUrlEntryData
+ {
+ };
+
+ typedef test_group<LLUrlEntryData> factory;
+ typedef factory::object object;
+}
+
+namespace
+{
+ tut::factory tf("LLUrlEntry");
+}
+
+namespace tut
+{
+ void testRegex(const std::string &testname, boost::regex regex,
+ const char *text, const std::string &expected)
+ {
+ std::string url = "";
+ boost::cmatch result;
+ bool found = boost::regex_search(text, result, regex);
+ if (found)
+ {
+ S32 start = static_cast<U32>(result[0].first - text);
+ S32 end = static_cast<U32>(result[0].second - text);
+ url = std::string(text+start, end-start);
+ }
+ ensure_equals(testname, url, expected);
+ }
+
+ template<> template<>
+ void object::test<1>()
+ {
+ //
+ // test LLUrlEntryHTTP - standard http Urls
+ //
+ LLUrlEntryHTTP url;
+ boost::regex r = url.getPattern();
+
+ testRegex("no valid url", r,
+ "htp://slurl.com/",
+ "");
+
+ testRegex("simple http (1)", r,
+ "http://slurl.com/",
+ "http://slurl.com/");
+
+ testRegex("simple http (2)", r,
+ "http://slurl.com",
+ "http://slurl.com");
+
+ testRegex("simple http (3)", r,
+ "http://slurl.com/about.php",
+ "http://slurl.com/about.php");
+
+ testRegex("simple https", r,
+ "https://slurl.com/about.php",
+ "https://slurl.com/about.php");
+
+ testRegex("http in text (1)", r,
+ "XX http://slurl.com/ XX",
+ "http://slurl.com/");
+
+ testRegex("http in text (2)", r,
+ "XX http://slurl.com/about.php XX",
+ "http://slurl.com/about.php");
+
+ testRegex("https in text", r,
+ "XX https://slurl.com/about.php XX",
+ "https://slurl.com/about.php");
+
+ testRegex("two http urls", r,
+ "XX http://slurl.com/about.php http://secondlife.com/ XX",
+ "http://slurl.com/about.php");
+
+ testRegex("http url with port and username", r,
+ "XX http://nobody@slurl.com:80/about.php http://secondlife.com/ XX",
+ "http://nobody@slurl.com:80/about.php");
+
+ testRegex("http url with port, username, and query string", r,
+ "XX http://nobody@slurl.com:80/about.php?title=hi%20there http://secondlife.com/ XX",
+ "http://nobody@slurl.com:80/about.php?title=hi%20there");
+
+ // note: terminating commas will be removed by LLUrlRegistry:findUrl()
+ testRegex("http url with commas in middle and terminating", r,
+ "XX http://slurl.com/?title=Hi,There, XX",
+ "http://slurl.com/?title=Hi,There,");
+
+ // note: terminating periods will be removed by LLUrlRegistry:findUrl()
+ testRegex("http url with periods in middle and terminating", r,
+ "XX http://slurl.com/index.php. XX",
+ "http://slurl.com/index.php.");
+
+ // DEV-19842: Closing parenthesis ")" breaks urls
+ testRegex("http url with brackets (1)", r,
+ "XX http://en.wikipedia.org/wiki/JIRA_(software) XX",
+ "http://en.wikipedia.org/wiki/JIRA_(software)");
+
+ // DEV-19842: Closing parenthesis ")" breaks urls
+ testRegex("http url with brackets (2)", r,
+ "XX http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg XX",
+ "http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg");
+
+ // DEV-10353: URLs in chat log terminated incorrectly when newline in chat
+ testRegex("http url with newlines", r,
+ "XX\nhttp://www.secondlife.com/\nXX",
+ "http://www.secondlife.com/");
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ //
+ // test LLUrlEntryHTTPLabel - wiki-style http Urls with labels
+ //
+ LLUrlEntryHTTPLabel url;
+ boost::regex r = url.getPattern();
+
+ testRegex("invalid wiki url [1]", r,
+ "[http://www.example.org]",
+ "");
+
+ testRegex("invalid wiki url [2]", r,
+ "[http://www.example.org",
+ "");
+
+ testRegex("invalid wiki url [3]", r,
+ "[http://www.example.org Label",
+ "");
+
+ testRegex("example.org with label (spaces)", r,
+ "[http://www.example.org Text]",
+ "[http://www.example.org Text]");
+
+ testRegex("example.org with label (tabs)", r,
+ "[http://www.example.org\t Text]",
+ "[http://www.example.org\t Text]");
+
+ testRegex("SL http URL with label", r,
+ "[http://www.secondlife.com/ Second Life]",
+ "[http://www.secondlife.com/ Second Life]");
+
+ testRegex("SL https URL with label", r,
+ "XXX [https://www.secondlife.com/ Second Life] YYY",
+ "[https://www.secondlife.com/ Second Life]");
+
+ testRegex("SL http URL with label", r,
+ "[http://www.secondlife.com/?test=Hi%20There Second Life]",
+ "[http://www.secondlife.com/?test=Hi%20There Second Life]");
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ //
+ // test LLUrlEntrySLURL - second life URLs
+ //
+ LLUrlEntrySLURL url;
+ boost::regex r = url.getPattern();
+
+ testRegex("no valid slurl [1]", r,
+ "htp://slurl.com/secondlife/Ahern/50/50/50/",
+ "");
+
+ testRegex("no valid slurl [2]", r,
+ "http://slurl.com/secondlife/",
+ "");
+
+ testRegex("no valid slurl [3]", r,
+ "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/",
+ "");
+
+ testRegex("Ahern (50,50,50) [1]", r,
+ "http://slurl.com/secondlife/Ahern/50/50/50/",
+ "http://slurl.com/secondlife/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [2]", r,
+ "XXX http://slurl.com/secondlife/Ahern/50/50/50/ XXX",
+ "http://slurl.com/secondlife/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [3]", r,
+ "XXX http://slurl.com/secondlife/Ahern/50/50/50 XXX",
+ "http://slurl.com/secondlife/Ahern/50/50/50");
+
+ testRegex("Ahern (50,50,50) multicase", r,
+ "XXX http://SLUrl.com/SecondLife/Ahern/50/50/50/ XXX",
+ "http://SLUrl.com/SecondLife/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50) [1]", r,
+ "XXX http://slurl.com/secondlife/Ahern/50/50/ XXX",
+ "http://slurl.com/secondlife/Ahern/50/50/");
+
+ testRegex("Ahern (50,50) [2]", r,
+ "XXX http://slurl.com/secondlife/Ahern/50/50 XXX",
+ "http://slurl.com/secondlife/Ahern/50/50");
+
+ testRegex("Ahern (50)", r,
+ "XXX http://slurl.com/secondlife/Ahern/50 XXX",
+ "http://slurl.com/secondlife/Ahern/50");
+
+ testRegex("Ahern", r,
+ "XXX http://slurl.com/secondlife/Ahern/ XXX",
+ "http://slurl.com/secondlife/Ahern/");
+
+ testRegex("Ahern SLURL with title", r,
+ "XXX http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX",
+ "http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!");
+
+ testRegex("Ahern SLURL with msg", r,
+ "XXX http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here. XXX",
+ "http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here.");
+
+ // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat
+ testRegex("SLURL with brackets", r,
+ "XXX http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30 XXX",
+ "http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30");
+
+ // DEV-35459: SLURLs and teleport Links not parsed properly
+ testRegex("SLURL with quote", r,
+ "XXX http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701 XXX",
+ "http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701");
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ //
+ // test LLUrlEntryAgent - secondlife://app/agent Urls
+ //
+ LLUrlEntryAgent url;
+ boost::regex r = url.getPattern();
+
+ testRegex("Invalid Agent Url", r,
+ "secondlife:///app/agent/0e346d8b-4433-4d66-XXXX-fd37083abc4c/about",
+ "");
+
+ testRegex("Agent Url ", r,
+ "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about",
+ "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
+
+ testRegex("Agent Url in text", r,
+ "XXX secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about XXX",
+ "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about");
+
+ testRegex("Agent Url multicase", r,
+ "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About XXX",
+ "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About");
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ //
+ // test LLUrlEntryGroup - secondlife://app/group Urls
+ //
+ LLUrlEntryGroup url;
+ boost::regex r = url.getPattern();
+
+ testRegex("Invalid Group Url", r,
+ "secondlife:///app/group/00005ff3-4044-c79f-XXXX-fb28ae0df991/about",
+ "");
+
+ testRegex("Group Url ", r,
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about",
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about");
+
+ testRegex("Group Url in text", r,
+ "XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX",
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about");
+
+ testRegex("Group Url multicase", r,
+ "XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX",
+ "secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About");
+ }
+
+ template<> template<>
+ void object::test<6>()
+ {
+ //
+ // test LLUrlEntryEvent - secondlife://app/event Urls
+ //
+ LLUrlEntryEvent url;
+ boost::regex r = url.getPattern();
+
+ testRegex("Invalid Event Url", r,
+ "secondlife:///app/event/FOO/about",
+ "");
+
+ testRegex("Event Url ", r,
+ "secondlife:///app/event/700727/about",
+ "secondlife:///app/event/700727/about");
+
+ testRegex("Event Url in text", r,
+ "XXX secondlife:///app/event/700727/about XXX",
+ "secondlife:///app/event/700727/about");
+
+ testRegex("Event Url multicase", r,
+ "XXX secondlife:///APP/Event/700727/about XXX",
+ "secondlife:///APP/Event/700727/about");
+ }
+
+ template<> template<>
+ void object::test<7>()
+ {
+ //
+ // test LLUrlEntryClassified - secondlife://app/classified Urls
+ //
+ LLUrlEntryClassified url;
+ boost::regex r = url.getPattern();
+
+ testRegex("Invalid Classified Url", r,
+ "secondlife:///app/classified/00128854-XXXX-5649-7ca6-5dfaa7514ab2/about",
+ "");
+
+ testRegex("Classified Url ", r,
+ "secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about",
+ "secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about");
+
+ testRegex("Classified Url in text", r,
+ "XXX secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about XXX",
+ "secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about");
+
+ testRegex("Classified Url multicase", r,
+ "XXX secondlife:///APP/Classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/About XXX",
+ "secondlife:///APP/Classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/About");
+ }
+
+ template<> template<>
+ void object::test<8>()
+ {
+ //
+ // test LLUrlEntryParcel - secondlife://app/parcel Urls
+ //
+ LLUrlEntryParcel url;
+ boost::regex r = url.getPattern();
+
+ testRegex("Invalid Classified Url", r,
+ "secondlife:///app/parcel/0000060e-4b39-e00b-XXXX-d98b1934e3a8/about",
+ "");
+
+ testRegex("Classified Url ", r,
+ "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about",
+ "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about");
+
+ testRegex("Classified Url in text", r,
+ "XXX secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about XXX",
+ "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about");
+
+ testRegex("Classified Url multicase", r,
+ "XXX secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About XXX",
+ "secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About");
+ }
+ template<> template<>
+ void object::test<9>()
+ {
+ //
+ // test LLUrlEntryTeleport - secondlife://app/teleport URLs
+ //
+ LLUrlEntryTeleport url;
+ boost::regex r = url.getPattern();
+
+ testRegex("no valid teleport [1]", r,
+ "http://slurl.com/secondlife/Ahern/50/50/50/",
+ "");
+
+ testRegex("no valid teleport [2]", r,
+ "secondlife:///app/teleport/",
+ "");
+
+ testRegex("no valid teleport [3]", r,
+ "second-life:///app/teleport/Ahern/50/50/50/",
+ "");
+
+ testRegex("no valid teleport [3]", r,
+ "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/",
+ "");
+
+ testRegex("Ahern (50,50,50) [1]", r,
+ "secondlife:///app/teleport/Ahern/50/50/50/",
+ "secondlife:///app/teleport/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [2]", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX",
+ "secondlife:///app/teleport/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50,50) [3]", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50/50 XXX",
+ "secondlife:///app/teleport/Ahern/50/50/50");
+
+ testRegex("Ahern (50,50,50) multicase", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX",
+ "secondlife:///app/teleport/Ahern/50/50/50/");
+
+ testRegex("Ahern (50,50) [1]", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50/ XXX",
+ "secondlife:///app/teleport/Ahern/50/50/");
+
+ testRegex("Ahern (50,50) [2]", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50 XXX",
+ "secondlife:///app/teleport/Ahern/50/50");
+
+ testRegex("Ahern (50)", r,
+ "XXX secondlife:///app/teleport/Ahern/50 XXX",
+ "secondlife:///app/teleport/Ahern/50");
+
+ testRegex("Ahern", r,
+ "XXX secondlife:///app/teleport/Ahern/ XXX",
+ "secondlife:///app/teleport/Ahern/");
+
+ testRegex("Ahern teleport with title", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX",
+ "secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!");
+
+ testRegex("Ahern teleport with msg", r,
+ "XXX secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here. XXX",
+ "secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here.");
+
+ // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat
+ testRegex("Teleport with brackets", r,
+ "XXX secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30 XXX",
+ "secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30");
+
+ // DEV-35459: SLURLs and teleport Links not parsed properly
+ testRegex("Teleport url with quote", r,
+ "XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX",
+ "secondlife:///app/teleport/A'ksha%20Oasis/41/166/701");
+ }
+
+ template<> template<>
+ void object::test<10>()
+ {
+ //
+ // test LLUrlEntrySL - general secondlife:// URLs
+ //
+ LLUrlEntrySL url;
+ boost::regex r = url.getPattern();
+
+ testRegex("no valid slapp [1]", r,
+ "http:///app/",
+ "");
+
+ testRegex("valid slapp [1]", r,
+ "secondlife:///app/",
+ "secondlife:///app/");
+
+ testRegex("valid slapp [2]", r,
+ "secondlife:///app/teleport/Ahern/50/50/50/",
+ "secondlife:///app/teleport/Ahern/50/50/50/");
+
+ testRegex("valid slapp [3]", r,
+ "secondlife:///app/foo",
+ "secondlife:///app/foo");
+
+ testRegex("valid slapp [4]", r,
+ "secondlife:///APP/foo?title=Hi%20There",
+ "secondlife:///APP/foo?title=Hi%20There");
+
+ testRegex("valid slapp [5]", r,
+ "secondlife://host/app/",
+ "secondlife://host/app/");
+
+ testRegex("valid slapp [6]", r,
+ "secondlife://host:8080/foo/bar",
+ "secondlife://host:8080/foo/bar");
+ }
+
+ template<> template<>
+ void object::test<11>()
+ {
+ //
+ // test LLUrlEntrySLLabel - general secondlife:// URLs with labels
+ //
+ LLUrlEntrySLLabel url;
+ boost::regex r = url.getPattern();
+
+ testRegex("invalid wiki url [1]", r,
+ "[secondlife:///app/]",
+ "");
+
+ testRegex("invalid wiki url [2]", r,
+ "[secondlife:///app/",
+ "");
+
+ testRegex("invalid wiki url [3]", r,
+ "[secondlife:///app/ Label",
+ "");
+
+ testRegex("agent slurl with label (spaces)", r,
+ "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about Text]",
+ "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about Text]");
+
+ testRegex("agent slurl with label (tabs)", r,
+ "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]",
+ "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]");
+
+ testRegex("agent slurl with label", r,
+ "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]",
+ "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]");
+
+ testRegex("teleport slurl with label", r,
+ "XXX [secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern] YYY",
+ "[secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern]");
+ }
+}
diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp
new file mode 100644
index 0000000000..fcf8f4d62f
--- /dev/null
+++ b/indra/llui/tests/llurlmatch_test.cpp
@@ -0,0 +1,177 @@
+/**
+ * @file llurlmatch_test.cpp
+ * @author Martin Reddy
+ * @brief Unit tests for LLUrlMatch
+ *
+ * $LicenseInfo:firstyear=2009&license=internal$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of
+ * this source code is governed by the Linden Lab Source Code Disclosure
+ * Agreement ("Agreement") previously entered between you and Linden
+ * Lab. By accessing, using, copying, modifying or distributing this
+ * software, you acknowledge that you have been informed of your
+ * obligations under the Agreement 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 "../llurlmatch.h"
+#include "lltut.h"
+
+namespace tut
+{
+ struct LLUrlMatchData
+ {
+ };
+
+ typedef test_group<LLUrlMatchData> factory;
+ typedef factory::object object;
+}
+
+namespace
+{
+ tut::factory tf("LLUrlMatch");
+}
+
+namespace tut
+{
+ template<> template<>
+ void object::test<1>()
+ {
+ //
+ // test the empty() method
+ //
+ LLUrlMatch match;
+ ensure("empty()", match.empty());
+
+ match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", "", "");
+ ensure("! empty()", ! match.empty());
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ //
+ // test the getStart() method
+ //
+ LLUrlMatch match;
+ ensure_equals("getStart() == 0", match.getStart(), 0);
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure_equals("getStart() == 10", match.getStart(), 10);
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ //
+ // test the getEnd() method
+ //
+ LLUrlMatch match;
+ ensure_equals("getEnd() == 0", match.getEnd(), 0);
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure_equals("getEnd() == 20", match.getEnd(), 20);
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ //
+ // test the getUrl() method
+ //
+ LLUrlMatch match;
+ ensure_equals("getUrl() == ''", match.getUrl(), "");
+
+ match.setValues(10, 20, "http://slurl.com/", "", "", "", "", "");
+ ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/");
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure_equals("getUrl() == '' (2)", match.getUrl(), "");
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ //
+ // test the getLabel() method
+ //
+ LLUrlMatch match;
+ ensure_equals("getLabel() == ''", match.getLabel(), "");
+
+ match.setValues(10, 20, "", "Label", "", "", "", "");
+ ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label");
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure_equals("getLabel() == '' (2)", match.getLabel(), "");
+ }
+
+ template<> template<>
+ void object::test<6>()
+ {
+ //
+ // test the getTooltip() method
+ //
+ LLUrlMatch match;
+ ensure_equals("getTooltip() == ''", match.getTooltip(), "");
+
+ match.setValues(10, 20, "", "", "Info", "", "", "");
+ ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info");
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");
+ }
+
+ template<> template<>
+ void object::test<7>()
+ {
+ //
+ // test the getIcon() method
+ //
+ LLUrlMatch match;
+ ensure_equals("getIcon() == ''", match.getIcon(), "");
+
+ match.setValues(10, 20, "", "", "", "Icon", "", "");
+ ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon");
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure_equals("getIcon() == '' (2)", match.getIcon(), "");
+ }
+
+ template<> template<>
+ void object::test<8>()
+ {
+ //
+ // test the getMenuName() method
+ //
+ LLUrlMatch match;
+ ensure("getMenuName() empty", match.getMenuName().empty());
+
+ match.setValues(10, 20, "", "", "", "Icon", "xui_file.xml", "");
+ ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml");
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure("getMenuName() empty (2)", match.getMenuName().empty());
+ }
+
+ template<> template<>
+ void object::test<9>()
+ {
+ //
+ // test the getLocation() method
+ //
+ LLUrlMatch match;
+ ensure("getLocation() empty", match.getLocation().empty());
+
+ match.setValues(10, 20, "", "", "", "Icon", "xui_file.xml", "Paris");
+ ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris");
+
+ match.setValues(10, 20, "", "", "", "", "", "");
+ ensure("getLocation() empty (2)", match.getLocation().empty());
+ }
+}