/** * @file llmediaentry_test.cpp * @brief llmediaentry unit tests * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "lltut.h" #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4702) // boost::lexical_cast generates this warning #endif #include #if LL_WINDOWS #pragma warning (pop) #endif #include "llstring.h" #include "llsdutil.h" #include "llsdserialize.h" #include "../llmediaentry.h" #include "lllslconstants.h" #define DEFAULT_MEDIA_ENTRY "\n\ \n\ alt_image_enable\n\ 0\n\ auto_loop\n\ 0\n\ auto_play\n\ 0\n\ auto_scale\n\ 0\n\ auto_zoom\n\ 0\n\ controls\n\ 0\n\ current_url\n\ \n\ first_click_interact\n\ 0\n\ height_pixels\n\ 0\n\ home_url\n\ \n\ perms_control\n\ 7\n\ perms_interact\n\ 7\n\ whitelist_enable\n\ 0\n\ width_pixels\n\ 0\n\ \n\ " #define EMPTY_MEDIA_ENTRY "\n\ \n\ alt_image_enable\n\ 0\n\ auto_loop\n\ 0\n\ auto_play\n\ 0\n\ auto_scale\n\ 0\n\ auto_zoom\n\ 0\n\ controls\n\ 0\n\ current_url\n\ \n\ first_click_interact\n\ 0\n\ height_pixels\n\ 0\n\ home_url\n\ \n\ perms_control\n\ 0\n\ perms_interact\n\ 0\n\ whitelist_enable\n\ 0\n\ width_pixels\n\ 0\n\ \n\ " #define PARTIAL_MEDIA_ENTRY(CURRENT_URL) "\n\ \n\ alt_image_enable\n\ 0\n\ auto_loop\n\ 0\n\ auto_play\n\ 0\n\ auto_scale\n\ 0\n\ auto_zoom\n\ 0\n\ controls\n\ 0\n\ current_url\n\ " CURRENT_URL "\n\ first_click_interact\n\ 0\n\ height_pixels\n\ 0\n\ home_url\n\ \n\ perms_control\n\ 0\n\ perms_interact\n\ 0\n\ whitelist_enable\n\ 0\n\ width_pixels\n\ 0\n\ \n\ " namespace tut { // this is fixture data that gets created before each test and destroyed // after each test. this is where we put all of the setup/takedown code // and data needed for each test. struct MediaEntry_test { MediaEntry_test() { emptyMediaEntryStr = EMPTY_MEDIA_ENTRY; std::istringstream e(EMPTY_MEDIA_ENTRY); LLSDSerialize::fromXML(emptyMediaEntryLLSD, e); defaultMediaEntryStr = DEFAULT_MEDIA_ENTRY; std::istringstream d(DEFAULT_MEDIA_ENTRY); LLSDSerialize::fromXML(defaultMediaEntryLLSD, d); } std::string emptyMediaEntryStr; LLSD emptyMediaEntryLLSD; std::string defaultMediaEntryStr; LLSD defaultMediaEntryLLSD; }; typedef test_group factory; typedef factory::object object; } namespace { // this is for naming our tests to make pretty output tut::factory tf("MediaEntry Test"); } namespace tut { void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual) { if (!llsd_equals(expected, actual)) { std::string message = msg; message += ": actual: "; message += ll_pretty_print_sd(actual); message += "\n expected: "; message += ll_pretty_print_sd(expected); message += "\n"; ensure(message, false); } } void ensure_string_equals(const std::string& msg, const std::string& expected, const std::string& actual) { if ( expected != actual ) { std::string message = msg; message += ": actual: "; message += actual; message += "\n expected: "; message += expected; message += "\n"; ensure(message, false); } } void set_whitelist(LLMediaEntry &entry, const char *str) { std::vector tokens; LLStringUtil::getTokens(std::string(str), tokens, ","); entry.setWhiteList(tokens); } void whitelist_test(int num, bool enable, const char *whitelist, const char *candidate_url, bool expected_pass) { std::string message = "Whitelist test " + boost::lexical_cast(num); LLMediaEntry entry; entry.setWhiteListEnable(enable); set_whitelist(entry, whitelist); bool passed_whitelist = entry.checkCandidateUrl(candidate_url); if (passed_whitelist != expected_pass) { message += " failed: expected "; message += (expected_pass) ? "" : "NOT "; message += "to match\nwhitelist = "; message += whitelist; message += "\ncandidate_url = "; message += candidate_url; } ensure(message, expected_pass == passed_whitelist); } void whitelist_test(int num, const char *whitelist, const char *candidate_url, bool expected_pass) { whitelist_test(num, true, whitelist, candidate_url, expected_pass); } void whitelist_test(int num, const char *whitelist, const char *candidate_url) { whitelist_test(num, true, whitelist, candidate_url, true); } template<> template<> void object::test<1>() { set_test_name("Test LLMediaEntry Instantiation"); LLMediaEntry entry; ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, entry.asLLSD()); } template<> template<> void object::test<2>() { set_test_name("Test LLMediaEntry Instantiation from LLSD"); LLMediaEntry entry; LLSD sd; entry.fromLLSD(sd); ensure_llsd_equals(get_test_name() + " failed", emptyMediaEntryLLSD, entry.asLLSD()); } template<> template<> void object::test<3>() { set_test_name("Test LLMediaEntry Partial Instantiation from LLSD"); LLMediaEntry entry; LLSD sd; sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com"; entry.fromLLSD(sd); LLSD golden; std::istringstream p(PARTIAL_MEDIA_ENTRY("http://www.example.com")); LLSDSerialize::fromXML(golden,p); ensure_llsd_equals(get_test_name() + " failed", golden, entry.asLLSD()); } template<> template<> void object::test<4>() { set_test_name("Test LLMediaEntry::asLLSD()"); LLMediaEntry entry; LLSD sd; // Put some cruft in the LLSD sd[LLMediaEntry::CURRENT_URL_KEY] = "http://www.example.com"; LLSD whitelist; whitelist.append("*.example.com"); sd[LLMediaEntry::WHITELIST_KEY] = whitelist; entry.asLLSD(sd); ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, sd); } template<> template<> void object::test<5>() { set_test_name("Test LLMediaEntry::asLLSD() -> LLMediaEntry::fromLLSD()"); LLMediaEntry entry1, entry2; // Add a whitelist to entry2 std::vector whitelist; whitelist.push_back("*.example.com"); entry2.setWhiteList(whitelist); // Render entry1 (which has no whitelist) as an LLSD LLSD sd; entry1.asLLSD(sd); // "read" that LLSD into entry 2 entry2.fromLLSD(sd); ensure_llsd_equals(get_test_name() + " failed", defaultMediaEntryLLSD, entry2.asLLSD()); } // limit tests const char *URL_OK = "http://www.example.com"; const char *URL_TOO_BIG = "http://www.example.com.qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; template<> template<> void object::test<6>() { set_test_name("Test Limits on setting current URL"); LLMediaEntry entry; U32 status = entry.setCurrentURL(URL_OK); ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); status = entry.setCurrentURL(URL_TOO_BIG); ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); } template<> template<> void object::test<7>() { set_test_name("Test Limits on setting home URL"); LLMediaEntry entry; U32 status = entry.setHomeURL(URL_OK); ensure(get_test_name() + " ok failed", status == LSL_STATUS_OK); status = entry.setHomeURL(URL_TOO_BIG); ensure(get_test_name() + " ok failed", status == LSL_STATUS_BOUNDS_ERROR); } template<> template<> void object::test<8>() { set_test_name("Test Limits on setting whitelist"); // Test a valid list LLMediaEntry entry; std::vector whitelist; whitelist.push_back(std::string(URL_OK)); S32 status = entry.setWhiteList(whitelist); ensure(get_test_name() + " invalid result", status == LSL_STATUS_OK); ensure(get_test_name() + " failed", whitelist == entry.getWhiteList()); } template<> template<> void object::test<9>() { set_test_name("Test Limits on setting whitelist too big"); // Test an invalid list LLMediaEntry entry; std::vector whitelist, empty; whitelist.push_back(std::string(URL_OK)); whitelist.push_back(std::string(URL_TOO_BIG)); S32 status = entry.setWhiteList(whitelist); ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); ensure(get_test_name() + " failed", empty == entry.getWhiteList()); } template<> template<> void object::test<10>() { set_test_name("Test Limits on setting whitelist too many"); // Test an invalid list LLMediaEntry entry; std::vector whitelist, empty; for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { whitelist.push_back("Q"); } S32 status = entry.setWhiteList(whitelist); ensure(get_test_name() + " invalid result", status == LSL_STATUS_BOUNDS_ERROR); ensure(get_test_name() + " failed", empty == entry.getWhiteList()); } template<> template<> void object::test<11>() { set_test_name("Test to make sure both setWhiteList() functions behave the same"); // Test a valid list std::vector whitelist, empty; LLSD whitelist_llsd; whitelist.push_back(std::string(URL_OK)); whitelist_llsd.append(std::string(URL_OK)); LLMediaEntry entry1, entry2; ensure(get_test_name() + " setWhiteList(s) don't match", entry1.setWhiteList(whitelist) == LSL_STATUS_OK && entry2.setWhiteList(whitelist_llsd)== LSL_STATUS_OK ); ensure(get_test_name() + " failed", entry1.getWhiteList() == entry2.getWhiteList()); } template<> template<> void object::test<12>() { set_test_name("Test to make sure both setWhiteList() functions behave the same"); // Test an invalid list std::vector whitelist, empty; LLSD whitelist_llsd; whitelist.push_back(std::string(URL_OK)); whitelist.push_back(std::string(URL_TOO_BIG)); whitelist_llsd.append(std::string(URL_OK)); whitelist_llsd.append(std::string(URL_TOO_BIG)); LLMediaEntry entry1, entry2; ensure(get_test_name() + " setWhiteList(s) don't match", entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); ensure(get_test_name() + " failed", empty == entry1.getWhiteList() && empty == entry2.getWhiteList()); } template<> template<> void object::test<13>() { set_test_name("Test to make sure both setWhiteList() functions behave the same"); // Test an invalid list, too many std::vector whitelist, empty; LLSD whitelist_llsd; for (int i=0; i < LLMediaEntry::MAX_WHITELIST_SIZE+1; i++) { whitelist.push_back("Q"); whitelist_llsd.append("Q"); } LLMediaEntry entry1, entry2; ensure(get_test_name() + " invalid result", entry1.setWhiteList(whitelist) == LSL_STATUS_BOUNDS_ERROR && entry2.setWhiteList(whitelist_llsd) == LSL_STATUS_BOUNDS_ERROR); ensure(get_test_name() + " failed", empty == entry1.getWhiteList() && empty == entry2.getWhiteList()); } template<> template<> void object::test<14>() { // Whitelist check tests int n=0; // Check the "empty whitelist" case whitelist_test(++n, "", "http://www.example.com", true); // Check the "missing scheme" case whitelist_test(++n, "www.example.com", "http://www.example.com", true); // Check the "exactly the same" case whitelist_test(++n, "http://example.com", "http://example.com", true); // Check the enable flag whitelist_test(++n, false, "www.example.com", "http://www.secondlife.com", true); whitelist_test(++n, true, "www.example.com", "http://www.secondlife.com", false); // Check permutations of trailing slash: whitelist_test(++n, "http://www.example.com", "http://www.example.com/", true); whitelist_test(++n, "http://www.example.com/", "http://www.example.com/", true); whitelist_test(++n, "http://www.example.com/", "http://www.example.com", false); whitelist_test(++n, "http://www.example.com", "http://www.example.com/foobar", true); whitelist_test(++n, "http://www.example.com/", "http://www.example.com/foobar", false); // More cases... whitelist_test(++n, "http://example.com", "http://example.com/wiki", true); whitelist_test(++n, "www.example.com", "http://www.example.com/help", true); whitelist_test(++n, "http://www.example.com", "http://wwwexample.com", false); whitelist_test(++n, "http://www.example.com", "http://www.example.com/wiki", true); whitelist_test(++n, "example.com", "http://wwwexample.com", false); whitelist_test(++n, "http://www.example.com/", "http://www.amazon.com/wiki", false); whitelist_test(++n, "www.example.com", "http://www.amazon.com", false); // regexp cases whitelist_test(++n, "*.example.com", "http://www.example.com", true); whitelist_test(++n, "*.example.com", "http://www.amazon.com", false); whitelist_test(++n, "*.example.com", "http://www.example.com/foo/bar", true); whitelist_test(++n, "*.example.com", "http:/example.com/foo/bar", false); whitelist_test(++n, "*example.com", "http://example.com/foo/bar", true); whitelist_test(++n, "*example.com", "http://my.virus.com/foo/bar?example.com", false); whitelist_test(++n, "example.com", "http://my.virus.com/foo/bar?example.com", false); whitelist_test(++n, "*example.com", "http://my.virus.com/foo/bar?*example.com", false); whitelist_test(++n, "http://*example.com", "http://www.example.com", true); whitelist_test(++n, "http://*.example.com", "http://www.example.com", true); whitelist_test(++n, "http://*.e$?^.com", "http://www.e$?^.com", true); whitelist_test(++n, "*.example.com/foo/bar", "http://www.example.com/", false); whitelist_test(++n, "*.example.com/foo/bar", "http://example.com/foo/bar", false); whitelist_test(++n, "http://*.example.com/foo/bar", "http://www.example.com", false); whitelist_test(++n, "http://*.example.com", "https://www.example.com", false); whitelist_test(++n, "http*://*.example.com", "rtsp://www.example.com", false); whitelist_test(++n, "http*://*.example.com", "https://www.example.com", true); whitelist_test(++n, "example.com", "http://www.example.com", false); whitelist_test(++n, "www.example.com", "http://www.example.com:80", false); whitelist_test(++n, "www.example.com", "http://www.example.com", true); whitelist_test(++n, "www.example.com/", "http://www.example.com", false); whitelist_test(++n, "www.example.com/foo/bar/*", "http://www.example.com/foo/bar/baz", true); // Path only whitelist_test(++n, "/foo/*/baz", "http://www.example.com/foo/bar/baz", true); whitelist_test(++n, "/foo/*/baz", "http://www.example.com/foo/bar/", false); } }