PageRenderTime 130ms CodeModel.GetById 15ms app.highlight 103ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/tests/llsdserialize_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1974 lines | 1555 code | 215 blank | 204 comment | 54 complexity | 24a6e7ad49ed66f108957dae41343cac MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llsdserialize_test.cpp
   3 * @date 2006-04
   4 * @brief LLSDSerialize unit tests
   5 *
   6 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 */
  27
  28
  29#include "linden_common.h"
  30
  31#if LL_WINDOWS
  32#include <winsock2.h>
  33typedef U32 uint32_t;
  34#include <process.h>
  35#include <io.h>
  36#else
  37#include <unistd.h>
  38#include <netinet/in.h>
  39#include <errno.h>
  40#include <fcntl.h>
  41#include <sys/stat.h>
  42#include <sys/wait.h>
  43#include "llprocesslauncher.h"
  44#endif
  45
  46#include <sstream>
  47
  48/*==========================================================================*|
  49// Whoops, seems Linden's Boost package and the viewer are built with
  50// different settings of VC's /Zc:wchar_t switch! Using Boost.Filesystem
  51// pathname operations produces Windows link errors:
  52// unresolved external symbol "private: static class std::codecvt<unsigned short,
  53// char,int> const * & __cdecl boost::filesystem3::path::wchar_t_codecvt_facet()"
  54// unresolved external symbol "void __cdecl boost::filesystem3::path_traits::convert()"
  55// See:
  56// http://boost.2283326.n4.nabble.com/filesystem-v3-unicode-and-std-codecvt-linker-error-td3455549.html
  57// which points to:
  58// http://msdn.microsoft.com/en-us/library/dh8che7s%28v=VS.100%29.aspx
  59
  60// As we're not trying to preserve compatibility with old Boost.Filesystem
  61// code, but rather writing brand-new code, use the newest available
  62// Filesystem API.
  63#define BOOST_FILESYSTEM_VERSION 3
  64#include "boost/filesystem.hpp"
  65#include "boost/filesystem/v3/fstream.hpp"
  66|*==========================================================================*/
  67#include "boost/range.hpp"
  68#include "boost/foreach.hpp"
  69#include "boost/function.hpp"
  70#include "boost/lambda/lambda.hpp"
  71#include "boost/lambda/bind.hpp"
  72namespace lambda = boost::lambda;
  73/*==========================================================================*|
  74// Aaaarrgh, Linden's Boost package doesn't even include Boost.Iostreams!
  75#include "boost/iostreams/stream.hpp"
  76#include "boost/iostreams/device/file_descriptor.hpp"
  77|*==========================================================================*/
  78
  79#include "../llsd.h"
  80#include "../llsdserialize.h"
  81#include "llsdutil.h"
  82#include "../llformat.h"
  83
  84#include "../test/lltut.h"
  85#include "stringize.h"
  86
  87std::vector<U8> string_to_vector(const std::string& str)
  88{
  89	return std::vector<U8>(str.begin(), str.end());
  90}
  91
  92#if ! LL_WINDOWS
  93// We want to call strerror_r(), but alarmingly, there are two different
  94// variants. The one that returns int always populates the passed buffer
  95// (except in case of error), whereas the other one always returns a valid
  96// char* but might or might not populate the passed buffer. How do we know
  97// which one we're getting? Define adapters for each and let the compiler
  98// select the applicable adapter.
  99
 100// strerror_r() returns char*
 101std::string message_from(int /*orig_errno*/, const char* /*buffer*/, const char* strerror_ret)
 102{
 103    return strerror_ret;
 104}
 105
 106// strerror_r() returns int
 107std::string message_from(int orig_errno, const char* buffer, int strerror_ret)
 108{
 109    if (strerror_ret == 0)
 110    {
 111        return buffer;
 112    }
 113    // Here strerror_r() has set errno. Since strerror_r() has already failed,
 114    // seems like a poor bet to call it again to diagnose its own error...
 115    int stre_errno = errno;
 116    if (stre_errno == ERANGE)
 117    {
 118        return STRINGIZE("strerror_r() can't explain errno " << orig_errno
 119                         << " (buffer too small)");
 120    }
 121    if (stre_errno == EINVAL)
 122    {
 123        return STRINGIZE("unknown errno " << orig_errno);
 124    }
 125    // Here we don't even understand the errno from strerror_r()!
 126    return STRINGIZE("strerror_r() can't explain errno " << orig_errno
 127                     << " (error " << stre_errno << ')');
 128}
 129#endif  // ! LL_WINDOWS
 130
 131// boost::filesystem::temp_directory_path() isn't yet in Boost 1.45! :-(
 132std::string temp_directory_path()
 133{
 134#if LL_WINDOWS
 135    char buffer[4096];
 136    GetTempPathA(sizeof(buffer), buffer);
 137    return buffer;
 138
 139#else  // LL_DARWIN, LL_LINUX
 140    static const char* vars[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR" };
 141    BOOST_FOREACH(const char* var, vars)
 142    {
 143        const char* found = getenv(var);
 144        if (found)
 145            return found;
 146    }
 147    return "/tmp";
 148#endif // LL_DARWIN, LL_LINUX
 149}
 150
 151// Windows presents a kinda sorta compatibility layer. Code to the yucky
 152// Windows names because they're less likely than the Posix names to collide
 153// with any other names in this source.
 154#if LL_WINDOWS
 155#define _remove   DeleteFileA
 156#else  // ! LL_WINDOWS
 157#define _open     open
 158#define _write    write
 159#define _close    close
 160#define _remove   remove
 161#endif  // ! LL_WINDOWS
 162
 163// Create a text file with specified content "somewhere in the
 164// filesystem," cleaning up when it goes out of scope.
 165class NamedTempFile
 166{
 167public:
 168    // Function that accepts an ostream ref and (presumably) writes stuff to
 169    // it, e.g.:
 170    // (lambda::_1 << "the value is " << 17 << '\n')
 171    typedef boost::function<void(std::ostream&)> Streamer;
 172
 173    NamedTempFile(const std::string& ext, const std::string& content):
 174        mPath(temp_directory_path())
 175    {
 176        createFile(ext, lambda::_1 << content);
 177    }
 178
 179    // Disambiguate when passing string literal
 180    NamedTempFile(const std::string& ext, const char* content):
 181        mPath(temp_directory_path())
 182    {
 183        createFile(ext, lambda::_1 << content);
 184    }
 185
 186    NamedTempFile(const std::string& ext, const Streamer& func):
 187        mPath(temp_directory_path())
 188    {
 189        createFile(ext, func);
 190    }
 191
 192    ~NamedTempFile()
 193    {
 194        _remove(mPath.c_str());
 195    }
 196
 197    std::string getName() const { return mPath; }
 198
 199private:
 200    void createFile(const std::string& ext, const Streamer& func)
 201    {
 202        // Silly maybe, but use 'ext' as the name prefix. Strip off a leading
 203        // '.' if present.
 204        int pfx_offset = ((! ext.empty()) && ext[0] == '.')? 1 : 0;
 205
 206#if ! LL_WINDOWS
 207        // Make sure mPath ends with a directory separator, if it doesn't already.
 208        if (mPath.empty() ||
 209            ! (mPath[mPath.length() - 1] == '\\' || mPath[mPath.length() - 1] == '/'))
 210        {
 211            mPath.append("/");
 212        }
 213
 214        // mkstemp() accepts and modifies a char* template string. Generate
 215        // the template string, then copy to modifiable storage.
 216        // mkstemp() requires its template string to end in six X's.
 217        mPath += ext.substr(pfx_offset) + "XXXXXX";
 218        // Copy to vector<char>
 219        std::vector<char> pathtemplate(mPath.begin(), mPath.end());
 220        // append a nul byte for classic-C semantics
 221        pathtemplate.push_back('\0');
 222        // std::vector promises that a pointer to the 0th element is the same
 223        // as a pointer to a contiguous classic-C array
 224        int fd(mkstemp(&pathtemplate[0]));
 225        if (fd == -1)
 226        {
 227            // The documented errno values (http://linux.die.net/man/3/mkstemp)
 228            // are used in a somewhat unusual way, so provide context-specific
 229            // errors.
 230            if (errno == EEXIST)
 231            {
 232                LL_ERRS("NamedTempFile") << "mkstemp(\"" << mPath
 233                                         << "\") could not create unique file " << LL_ENDL;
 234            }
 235            if (errno == EINVAL)
 236            {
 237                LL_ERRS("NamedTempFile") << "bad mkstemp() file path template '"
 238                                         << mPath << "'" << LL_ENDL;
 239            }
 240            // Shrug, something else
 241            int mkst_errno = errno;
 242            char buffer[256];
 243            LL_ERRS("NamedTempFile") << "mkstemp(\"" << mPath << "\") failed: "
 244                                     << message_from(mkst_errno, buffer,
 245                                                     strerror_r(mkst_errno, buffer, sizeof(buffer)))
 246                                     << LL_ENDL;
 247        }
 248        // mkstemp() seems to have worked! Capture the modified filename.
 249        // Avoid the nul byte we appended.
 250        mPath.assign(pathtemplate.begin(), (pathtemplate.end()-1));
 251
 252/*==========================================================================*|
 253        // Define an ostream on the open fd. Tell it to close fd on destruction.
 254        boost::iostreams::stream<boost::iostreams::file_descriptor_sink>
 255            out(fd, boost::iostreams::close_handle);
 256|*==========================================================================*/
 257
 258        // Write desired content.
 259        std::ostringstream out;
 260        // Stream stuff to it.
 261        func(out);
 262
 263        std::string data(out.str());
 264        int written(_write(fd, data.c_str(), data.length()));
 265        int closed(_close(fd));
 266        llassert_always(written == data.length() && closed == 0);
 267
 268#else // LL_WINDOWS
 269        // GetTempFileName() is documented to require a MAX_PATH buffer.
 270        char tempname[MAX_PATH];
 271        // Use 'ext' as filename prefix, but skip leading '.' if any.
 272        // The 0 param is very important: requests iterating until we get a
 273        // unique name.
 274        if (0 == GetTempFileNameA(mPath.c_str(), ext.c_str() + pfx_offset, 0, tempname))
 275        {
 276            // I always have to look up this call...  :-P
 277            LPSTR msgptr;
 278            FormatMessageA(
 279                FORMAT_MESSAGE_ALLOCATE_BUFFER | 
 280                FORMAT_MESSAGE_FROM_SYSTEM |
 281                FORMAT_MESSAGE_IGNORE_INSERTS,
 282                NULL,
 283                GetLastError(),
 284                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 285                LPSTR(&msgptr),     // have to cast (char**) to (char*)
 286                0, NULL );
 287            LL_ERRS("NamedTempFile") << "GetTempFileName(\"" << mPath << "\", \""
 288                                     << (ext.c_str() + pfx_offset) << "\") failed: "
 289                                     << msgptr << LL_ENDL;
 290            LocalFree(msgptr);
 291        }
 292        // GetTempFileName() appears to have worked! Capture the actual
 293        // filename.
 294        mPath = tempname;
 295        // Open the file and stream content to it. Destructor will close.
 296        std::ofstream out(tempname);
 297        func(out);
 298
 299#endif  // LL_WINDOWS
 300    }
 301
 302    void peep()
 303    {
 304        std::cout << "File '" << mPath << "' contains:\n";
 305        std::ifstream reader(mPath.c_str());
 306        std::string line;
 307        while (std::getline(reader, line))
 308            std::cout << line << '\n';
 309        std::cout << "---\n";
 310    }
 311
 312    std::string mPath;
 313};
 314
 315namespace tut
 316{
 317	struct sd_xml_data
 318	{
 319		sd_xml_data()
 320		{
 321			mFormatter = new LLSDXMLFormatter;
 322		}
 323		LLSD mSD;
 324		LLPointer<LLSDXMLFormatter> mFormatter;
 325		void xml_test(const char* name, const std::string& expected)
 326		{
 327			std::ostringstream ostr;
 328			mFormatter->format(mSD, ostr);
 329			ensure_equals(name, ostr.str(), expected);
 330		}
 331	};
 332
 333	typedef test_group<sd_xml_data> sd_xml_test;
 334	typedef sd_xml_test::object sd_xml_object;
 335	tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter");
 336
 337	template<> template<>
 338	void sd_xml_object::test<1>()
 339	{
 340		// random atomic tests
 341		std::string expected;
 342
 343		expected = "<llsd><undef /></llsd>\n";
 344		xml_test("undef", expected);
 345
 346		mSD = 3463;
 347		expected = "<llsd><integer>3463</integer></llsd>\n";
 348		xml_test("integer", expected);
 349
 350		mSD = "";
 351		expected = "<llsd><string /></llsd>\n";
 352		xml_test("empty string", expected);
 353
 354		mSD = "foobar";
 355		expected = "<llsd><string>foobar</string></llsd>\n";
 356		xml_test("string", expected);
 357
 358		mSD = LLUUID::null;
 359		expected = "<llsd><uuid /></llsd>\n";
 360		xml_test("null uuid", expected);
 361		
 362		mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed");
 363		expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n";
 364		xml_test("uuid", expected);
 365
 366		mSD = LLURI("https://secondlife.com/login");
 367		expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n";
 368		xml_test("uri", expected);
 369
 370		mSD = LLDate("2006-04-24T16:11:33Z");
 371		expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n";
 372		xml_test("date", expected);
 373
 374		// Generated by: echo -n 'hello' | openssl enc -e -base64
 375		std::vector<U8> hello;
 376		hello.push_back('h');
 377		hello.push_back('e');
 378		hello.push_back('l');
 379		hello.push_back('l');
 380		hello.push_back('o');
 381		mSD = hello;
 382		expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
 383		xml_test("binary", expected);
 384	}
 385	
 386	template<> template<>
 387	void sd_xml_object::test<2>()
 388	{
 389		// tests with boolean values.
 390		std::string expected;
 391
 392		mFormatter->boolalpha(true);
 393		mSD = true;
 394		expected = "<llsd><boolean>true</boolean></llsd>\n";
 395		xml_test("bool alpha true", expected);
 396		mSD = false;
 397		expected = "<llsd><boolean>false</boolean></llsd>\n";
 398		xml_test("bool alpha false", expected);
 399
 400		mFormatter->boolalpha(false);
 401		mSD = true;
 402		expected = "<llsd><boolean>1</boolean></llsd>\n";
 403		xml_test("bool true", expected);
 404		mSD = false;
 405		expected = "<llsd><boolean>0</boolean></llsd>\n";
 406		xml_test("bool false", expected);
 407	}
 408
 409
 410	template<> template<>
 411	void sd_xml_object::test<3>()
 412	{
 413		// tests with real values.
 414		std::string expected;
 415
 416		mFormatter->realFormat("%.2f");
 417		mSD = 1.0;
 418		expected = "<llsd><real>1.00</real></llsd>\n";
 419		xml_test("real 1", expected);
 420
 421		mSD = -34379.0438;
 422		expected = "<llsd><real>-34379.04</real></llsd>\n";
 423		xml_test("real reduced precision", expected);
 424		mFormatter->realFormat("%.4f");
 425		expected = "<llsd><real>-34379.0438</real></llsd>\n";
 426		xml_test("higher precision", expected);
 427
 428		mFormatter->realFormat("%.0f");
 429		mSD = 0.0;
 430		expected = "<llsd><real>0</real></llsd>\n";
 431		xml_test("no decimal 0", expected);
 432		mSD = 3287.4387;
 433		expected = "<llsd><real>3287</real></llsd>\n";
 434		xml_test("no decimal real number", expected);
 435	}
 436
 437	template<> template<>
 438	void sd_xml_object::test<4>()
 439	{
 440		// tests with arrays
 441		std::string expected;
 442
 443		mSD = LLSD::emptyArray();
 444		expected = "<llsd><array /></llsd>\n";
 445		xml_test("empty array", expected);
 446
 447		mSD.append(LLSD());
 448		expected = "<llsd><array><undef /></array></llsd>\n";
 449		xml_test("1 element array", expected);
 450
 451		mSD.append(1);
 452		expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n";
 453		xml_test("2 element array", expected);
 454	}
 455
 456	template<> template<>
 457	void sd_xml_object::test<5>()
 458	{
 459		// tests with arrays
 460		std::string expected;
 461
 462		mSD = LLSD::emptyMap();
 463		expected = "<llsd><map /></llsd>\n";
 464		xml_test("empty map", expected);
 465
 466		mSD["foo"] = "bar";
 467		expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n";
 468		xml_test("1 element map", expected);
 469
 470		mSD["baz"] = LLSD();
 471		expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n";
 472		xml_test("2 element map", expected);
 473	}
 474	
 475	template<> template<>
 476	void sd_xml_object::test<6>()
 477	{
 478		// tests with binary
 479		std::string expected;
 480
 481		// Generated by: echo -n 'hello' | openssl enc -e -base64
 482		mSD = string_to_vector("hello");
 483		expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
 484		xml_test("binary", expected);
 485
 486		mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
 487		expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
 488		xml_test("binary", expected);
 489	}
 490	
 491	class TestLLSDSerializeData
 492	{
 493	public:
 494		TestLLSDSerializeData();
 495		~TestLLSDSerializeData();
 496
 497		void doRoundTripTests(const std::string&);
 498		void checkRoundTrip(const std::string&, const LLSD& v);
 499		
 500		LLPointer<LLSDFormatter> mFormatter;
 501		LLPointer<LLSDParser> mParser;
 502	};
 503
 504	TestLLSDSerializeData::TestLLSDSerializeData()
 505	{
 506	}
 507
 508	TestLLSDSerializeData::~TestLLSDSerializeData()
 509	{
 510	}
 511
 512	void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v)
 513	{
 514		std::stringstream stream;	
 515		mFormatter->format(v, stream);
 516		//llinfos << "checkRoundTrip: length " << stream.str().length() << llendl;
 517		LLSD w;
 518		mParser->reset();	// reset() call is needed since test code re-uses mParser
 519		mParser->parse(stream, w, stream.str().size());
 520		
 521		try
 522		{
 523			ensure_equals(msg.c_str(), w, v);
 524		}
 525		catch (...)
 526		{
 527			std::cerr << "the serialized string was:" << std::endl;
 528			std::cerr << stream.str() << std::endl;
 529			throw;
 530		}
 531	}
 532
 533	static void fillmap(LLSD& root, U32 width, U32 depth)
 534	{
 535		if(depth == 0)
 536		{
 537			root["foo"] = "bar";
 538			return;
 539		}
 540
 541		for(U32 i = 0; i < width; ++i)
 542		{
 543			std::string key = llformat("child %d", i);
 544			root[key] = LLSD::emptyMap();
 545			fillmap(root[key], width, depth - 1);
 546		}
 547	}
 548	
 549	void TestLLSDSerializeData::doRoundTripTests(const std::string& msg)
 550	{
 551		LLSD v;
 552		checkRoundTrip(msg + " undefined", v);
 553		
 554		v = true;
 555		checkRoundTrip(msg + " true bool", v);
 556		
 557		v = false;
 558		checkRoundTrip(msg + " false bool", v);
 559		
 560		v = 1;
 561		checkRoundTrip(msg + " positive int", v);
 562		
 563		v = 0;
 564		checkRoundTrip(msg + " zero int", v);
 565		
 566		v = -1;
 567		checkRoundTrip(msg + " negative int", v);
 568		
 569		v = 1234.5f;
 570		checkRoundTrip(msg + " positive float", v);
 571		
 572		v = 0.0f;
 573		checkRoundTrip(msg + " zero float", v);
 574		
 575		v = -1234.5f;
 576		checkRoundTrip(msg + " negative float", v);
 577		
 578		// FIXME: need a NaN test
 579		
 580		v = LLUUID::null;
 581		checkRoundTrip(msg + " null uuid", v);
 582		
 583		LLUUID newUUID;
 584		newUUID.generate();
 585		v = newUUID;
 586		checkRoundTrip(msg + " new uuid", v);
 587		
 588		v = "";
 589		checkRoundTrip(msg + " empty string", v);
 590		
 591		v = "some string";
 592		checkRoundTrip(msg + " non-empty string", v);
 593		
 594		v =
 595"Second Life is a 3-D virtual world entirely built and owned by its residents. "
 596"Since opening to the public in 2003, it has grown explosively and today is "
 597"inhabited by nearly 100,000 people from around the globe.\n"
 598"\n"
 599"From the moment you enter the World you'll discover a vast digital continent, "
 600"teeming with people, entertainment, experiences and opportunity. Once you've "
 601"explored a bit, perhaps you'll find a perfect parcel of land to build your "
 602"house or business.\n"
 603"\n"
 604"You'll also be surrounded by the Creations of your fellow residents. Because "
 605"residents retain the rights to their digital creations, they can buy, sell "
 606"and trade with other residents.\n"
 607"\n"
 608"The Marketplace currently supports millions of US dollars in monthly "
 609"transactions. This commerce is handled with the in-world currency, the Linden "
 610"dollar, which can be converted to US dollars at several thriving online "
 611"currency exchanges.\n"
 612"\n"
 613"Welcome to Second Life. We look forward to seeing you in-world!\n"
 614		;
 615		checkRoundTrip(msg + " long string", v);
 616
 617		static const U32 block_size = 0x000020;
 618		for (U32 block = 0x000000; block <= 0x10ffff; block += block_size)
 619		{
 620			std::ostringstream out;
 621			
 622			for (U32 c = block; c < block + block_size; ++c)
 623			{
 624				if (c <= 0x000001f
 625					&& c != 0x000009
 626					&& c != 0x00000a)
 627				{
 628					// see XML standard, sections 2.2 and 4.1
 629					continue;
 630				}
 631				if (0x00d800 <= c  &&  c <= 0x00dfff) { continue; }
 632				if (0x00fdd0 <= c  &&  c <= 0x00fdef) { continue; }
 633				if ((c & 0x00fffe) == 0x00fffe) { continue; }		
 634					// see Unicode standard, section 15.8 
 635				
 636				if (c <= 0x00007f)
 637				{
 638					out << (char)(c & 0x7f);
 639				}
 640				else if (c <= 0x0007ff)
 641				{
 642					out << (char)(0xc0 | ((c >> 6) & 0x1f));
 643					out << (char)(0x80 | ((c >> 0) & 0x3f));
 644				}
 645				else if (c <= 0x00ffff)
 646				{
 647					out << (char)(0xe0 | ((c >> 12) & 0x0f));
 648					out << (char)(0x80 | ((c >>  6) & 0x3f));
 649					out << (char)(0x80 | ((c >>  0) & 0x3f));
 650				}
 651				else
 652				{
 653					out << (char)(0xf0 | ((c >> 18) & 0x07));
 654					out << (char)(0x80 | ((c >> 12) & 0x3f));
 655					out << (char)(0x80 | ((c >>  6) & 0x3f));
 656					out << (char)(0x80 | ((c >>  0) & 0x3f));
 657				}
 658			}
 659			
 660			v = out.str();
 661
 662			std::ostringstream blockmsg;
 663			blockmsg << msg << " unicode string block 0x" << std::hex << block; 
 664			checkRoundTrip(blockmsg.str(), v);
 665		}
 666		
 667		LLDate epoch;
 668		v = epoch;
 669		checkRoundTrip(msg + " epoch date", v);
 670		
 671		LLDate aDay("2002-12-07T05:07:15.00Z");
 672		v = aDay;
 673		checkRoundTrip(msg + " date", v);
 674		
 675		LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/");
 676		v = path;
 677		checkRoundTrip(msg + " url", v);
 678		
 679		const char source[] = "it must be a blue moon again";
 680		std::vector<U8> data;
 681		copy(&source[0], &source[sizeof(source)], back_inserter(data));
 682		
 683		v = data;
 684		checkRoundTrip(msg + " binary", v);
 685		
 686		v = LLSD::emptyMap();
 687		checkRoundTrip(msg + " empty map", v);
 688		
 689		v = LLSD::emptyMap();
 690		v["name"] = "luke";		//v.insert("name", "luke");
 691		v["age"] = 3;			//v.insert("age", 3);
 692		checkRoundTrip(msg + " map", v);
 693		
 694		v.clear();
 695		v["a"]["1"] = true;
 696		v["b"]["0"] = false;
 697		checkRoundTrip(msg + " nested maps", v);
 698		
 699		v = LLSD::emptyArray();
 700		checkRoundTrip(msg + " empty array", v);
 701		
 702		v = LLSD::emptyArray();
 703		v.append("ali");
 704		v.append(28);
 705		checkRoundTrip(msg + " array", v);
 706		
 707		v.clear();
 708		v[0][0] = true;
 709		v[1][0] = false;
 710		checkRoundTrip(msg + " nested arrays", v);
 711
 712		v = LLSD::emptyMap();
 713		fillmap(v, 10, 3); // 10^6 maps
 714		checkRoundTrip(msg + " many nested maps", v);
 715	}
 716	
 717	typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerialzeGroup;
 718	typedef TestLLSDSerialzeGroup::object TestLLSDSerializeObject;
 719	TestLLSDSerialzeGroup gTestLLSDSerializeGroup("llsd serialization");
 720
 721	template<> template<> 
 722	void TestLLSDSerializeObject::test<1>()
 723	{
 724		mFormatter = new LLSDNotationFormatter();
 725		mParser = new LLSDNotationParser();
 726		doRoundTripTests("notation serialization");
 727	}
 728	
 729	template<> template<> 
 730	void TestLLSDSerializeObject::test<2>()
 731	{
 732		mFormatter = new LLSDXMLFormatter();
 733		mParser = new LLSDXMLParser();
 734		doRoundTripTests("xml serialization");
 735	}
 736	
 737	template<> template<> 
 738	void TestLLSDSerializeObject::test<3>()
 739	{
 740		mFormatter = new LLSDBinaryFormatter();
 741		mParser = new LLSDBinaryParser();
 742		doRoundTripTests("binary serialization");
 743	}
 744
 745
 746	/**
 747	 * @class TestLLSDParsing
 748	 * @brief Base class for of a parse tester.
 749	 */
 750	template <class parser_t>
 751	class TestLLSDParsing
 752	{
 753	public:
 754		TestLLSDParsing()
 755		{
 756			mParser = new parser_t;
 757		}
 758
 759		void ensureParse(
 760			const std::string& msg,
 761			const std::string& in,
 762			const LLSD& expected_value,
 763			S32 expected_count)
 764		{
 765			std::stringstream input;
 766			input.str(in);
 767
 768			LLSD parsed_result;
 769			mParser->reset();	// reset() call is needed since test code re-uses mParser
 770			S32 parsed_count = mParser->parse(input, parsed_result, in.size());
 771			ensure_equals(msg.c_str(), parsed_result, expected_value);
 772
 773			// This count check is really only useful for expected
 774			// parse failures, since the ensures equal will already
 775			// require eqality.
 776			std::string count_msg(msg);
 777			count_msg += " (count)";
 778			ensure_equals(count_msg, parsed_count, expected_count);
 779		}
 780
 781		LLPointer<parser_t> mParser;
 782	};
 783
 784
 785	/**
 786	 * @class TestLLSDXMLParsing
 787	 * @brief Concrete instance of a parse tester.
 788	 */
 789	class TestLLSDXMLParsing : public TestLLSDParsing<LLSDXMLParser>
 790	{
 791	public:
 792		TestLLSDXMLParsing() {}
 793	};
 794	
 795	typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup;
 796	typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject;
 797	TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing");
 798
 799	template<> template<> 
 800	void TestLLSDXMLParsingObject::test<1>()
 801	{
 802		// test handling of xml not recognized as llsd results in an
 803		// LLSD Undefined
 804		ensureParse(
 805			"malformed xml",
 806			"<llsd><string>ha ha</string>",
 807			LLSD(),
 808			LLSDParser::PARSE_FAILURE);
 809		ensureParse(
 810			"not llsd",
 811			"<html><body><p>ha ha</p></body></html>",
 812			LLSD(),
 813			LLSDParser::PARSE_FAILURE);
 814		ensureParse(
 815			"value without llsd",
 816			"<string>ha ha</string>",
 817			LLSD(),
 818			LLSDParser::PARSE_FAILURE);
 819		ensureParse(
 820			"key without llsd",
 821			"<key>ha ha</key>",
 822			LLSD(),
 823			LLSDParser::PARSE_FAILURE);
 824	}
 825	
 826	
 827	template<> template<> 
 828	void TestLLSDXMLParsingObject::test<2>()
 829	{
 830		// test handling of unrecognized or unparseable llsd values
 831		LLSD v;
 832		v["amy"] = 23;
 833		v["bob"] = LLSD();
 834		v["cam"] = 1.23;
 835		
 836		ensureParse(
 837			"unknown data type",
 838			"<llsd><map>"
 839				"<key>amy</key><integer>23</integer>"
 840				"<key>bob</key><bigint>99999999999999999</bigint>"
 841				"<key>cam</key><real>1.23</real>"
 842			"</map></llsd>",
 843			v,
 844			v.size() + 1);
 845	}
 846	
 847	template<> template<> 
 848	void TestLLSDXMLParsingObject::test<3>()
 849	{
 850		// test handling of nested bad data
 851		
 852		LLSD v;
 853		v["amy"] = 23;
 854		v["cam"] = 1.23;
 855		
 856		ensureParse(
 857			"map with html",
 858			"<llsd><map>"
 859				"<key>amy</key><integer>23</integer>"
 860				"<html><body>ha ha</body></html>"
 861				"<key>cam</key><real>1.23</real>"
 862			"</map></llsd>",
 863			v,
 864			v.size() + 1);
 865			
 866		v.clear();
 867		v["amy"] = 23;
 868		v["cam"] = 1.23;
 869		ensureParse(
 870			"map with value for key",
 871			"<llsd><map>"
 872				"<key>amy</key><integer>23</integer>"
 873				"<string>ha ha</string>"
 874				"<key>cam</key><real>1.23</real>"
 875			"</map></llsd>",
 876			v,
 877			v.size() + 1);
 878			
 879		v.clear();
 880		v["amy"] = 23;
 881		v["bob"] = LLSD::emptyMap();
 882		v["cam"] = 1.23;
 883		ensureParse(
 884			"map with map of html",
 885			"<llsd><map>"
 886				"<key>amy</key><integer>23</integer>"
 887				"<key>bob</key>"
 888				"<map>"
 889					"<html><body>ha ha</body></html>"
 890				"</map>"
 891				"<key>cam</key><real>1.23</real>"
 892			"</map></llsd>",
 893			v,
 894			v.size() + 1);
 895
 896		v.clear();
 897		v[0] = 23;
 898		v[1] = LLSD();
 899		v[2] = 1.23;
 900		
 901		ensureParse(
 902			"array value of html",
 903			"<llsd><array>"
 904				"<integer>23</integer>"
 905				"<html><body>ha ha</body></html>"
 906				"<real>1.23</real>"
 907			"</array></llsd>",
 908			v,
 909			v.size() + 1);
 910			
 911		v.clear();
 912		v[0] = 23;
 913		v[1] = LLSD::emptyMap();
 914		v[2] = 1.23;
 915		ensureParse(
 916			"array with map of html",
 917			"<llsd><array>"
 918				"<integer>23</integer>"
 919				"<map>"
 920					"<html><body>ha ha</body></html>"
 921				"</map>"
 922				"<real>1.23</real>"
 923			"</array></llsd>",
 924			v,
 925			v.size() + 1);
 926	}
 927
 928	template<> template<> 
 929	void TestLLSDXMLParsingObject::test<4>()
 930	{
 931		// test handling of binary object in XML
 932		std::string xml;
 933		LLSD expected;
 934
 935		// Generated by: echo -n 'hello' | openssl enc -e -base64
 936		expected = string_to_vector("hello");
 937		xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n";
 938		ensureParse(
 939			"the word 'hello' packed in binary encoded base64",
 940			xml,
 941			expected,
 942			1);
 943
 944		expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
 945		xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
 946		ensureParse(
 947			"a common binary blob for object -> agent offline inv transfer",
 948			xml,
 949			expected,
 950			1);
 951
 952		expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0");
 953		xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n";
 954		xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n";
 955		xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n";
 956		xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n";
 957		xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n";
 958		ensureParse(
 959			"a common binary blob for object -> agent offline inv transfer",
 960			xml,
 961			expected,
 962			1);
 963	}
 964	/*
 965	TODO:
 966		test XML parsing
 967			binary with unrecognized encoding
 968			nested LLSD tags
 969			multiple values inside an LLSD
 970	*/
 971
 972
 973	/**
 974	 * @class TestLLSDNotationParsing
 975	 * @brief Concrete instance of a parse tester.
 976	 */
 977	class TestLLSDNotationParsing : public TestLLSDParsing<LLSDNotationParser>
 978	{
 979	public:
 980		TestLLSDNotationParsing() {}
 981	};
 982
 983	typedef tut::test_group<TestLLSDNotationParsing> TestLLSDNotationParsingGroup;
 984	typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject;
 985	TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup(
 986		"llsd notation parsing");
 987
 988	template<> template<> 
 989	void TestLLSDNotationParsingObject::test<1>()
 990	{
 991		// test handling of xml not recognized as llsd results in an
 992		// LLSD Undefined
 993		ensureParse(
 994			"malformed notation map",
 995			"{'ha ha'",
 996			LLSD(),
 997			LLSDParser::PARSE_FAILURE);
 998		ensureParse(
 999			"malformed notation array",
1000			"['ha ha'",
1001			LLSD(),
1002			LLSDParser::PARSE_FAILURE);
1003		ensureParse(
1004			"malformed notation string",
1005			"'ha ha",
1006			LLSD(),
1007			LLSDParser::PARSE_FAILURE);
1008		ensureParse(
1009			"bad notation noise",
1010			"g48ejlnfr",
1011			LLSD(),
1012			LLSDParser::PARSE_FAILURE);
1013	}
1014
1015	template<> template<> 
1016	void TestLLSDNotationParsingObject::test<2>()
1017	{
1018		ensureParse("valid undef", "!", LLSD(), 1);
1019	}
1020
1021	template<> template<> 
1022	void TestLLSDNotationParsingObject::test<3>()
1023	{
1024		LLSD val = false;
1025		ensureParse("valid boolean false 0", "false", val, 1);
1026		ensureParse("valid boolean false 1", "f", val, 1);
1027		ensureParse("valid boolean false 2", "0", val, 1);
1028		ensureParse("valid boolean false 3", "F", val, 1);
1029		ensureParse("valid boolean false 4", "FALSE", val, 1);
1030		val = true;
1031		ensureParse("valid boolean true 0", "true", val, 1);
1032		ensureParse("valid boolean true 1", "t", val, 1);
1033		ensureParse("valid boolean true 2", "1", val, 1);
1034		ensureParse("valid boolean true 3", "T", val, 1);
1035		ensureParse("valid boolean true 4", "TRUE", val, 1);
1036
1037		val.clear();
1038		ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE);
1039		ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE);
1040	}
1041
1042	template<> template<> 
1043	void TestLLSDNotationParsingObject::test<4>()
1044	{
1045		LLSD val = 123;
1046		ensureParse("valid integer", "i123", val, 1);
1047		val.clear();
1048		ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE);
1049	}
1050
1051	template<> template<> 
1052	void TestLLSDNotationParsingObject::test<5>()
1053	{
1054		LLSD val = 456.7;
1055		ensureParse("valid real", "r456.7", val, 1);
1056		val.clear();
1057		ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE);
1058	}
1059
1060	template<> template<> 
1061	void TestLLSDNotationParsingObject::test<6>()
1062	{
1063		LLUUID id;
1064		LLSD val = id;
1065		ensureParse(
1066			"unparseable uuid",
1067			"u123",
1068			LLSD(),
1069			LLSDParser::PARSE_FAILURE);
1070		id.generate();
1071		val = id;
1072		std::string uuid_str("u");
1073		uuid_str += id.asString();
1074		ensureParse("valid uuid", uuid_str.c_str(), val, 1);
1075	}
1076
1077	template<> template<> 
1078	void TestLLSDNotationParsingObject::test<7>()
1079	{
1080		LLSD val = std::string("foolish");
1081		ensureParse("valid string 1", "\"foolish\"", val, 1);
1082		val = std::string("g'day");
1083		ensureParse("valid string 2", "\"g'day\"", val, 1);
1084		val = std::string("have a \"nice\" day");
1085		ensureParse("valid string 3", "'have a \"nice\" day'", val, 1);
1086		val = std::string("whatever");
1087		ensureParse("valid string 4", "s(8)\"whatever\"", val, 1);
1088	}
1089
1090	template<> template<> 
1091	void TestLLSDNotationParsingObject::test<8>()
1092	{
1093		ensureParse(
1094			"invalid string 1",
1095			"s(7)\"whatever\"",
1096			LLSD(),
1097			LLSDParser::PARSE_FAILURE);
1098		ensureParse(
1099			"invalid string 2",
1100			"s(9)\"whatever\"",
1101			LLSD(),
1102			LLSDParser::PARSE_FAILURE);
1103	}
1104
1105	template<> template<> 
1106	void TestLLSDNotationParsingObject::test<9>()
1107	{
1108		LLSD val = LLURI("http://www.google.com");
1109		ensureParse("valid uri", "l\"http://www.google.com\"", val, 1);
1110	}
1111
1112	template<> template<> 
1113	void TestLLSDNotationParsingObject::test<10>()
1114	{
1115		LLSD val = LLDate("2007-12-28T09:22:53.10Z");
1116		ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1);
1117	}
1118
1119	template<> template<> 
1120	void TestLLSDNotationParsingObject::test<11>()
1121	{
1122		std::vector<U8> vec;
1123		vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c');
1124		vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1');
1125		LLSD val = vec;
1126		ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1);
1127		ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1);
1128		ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1);
1129	}
1130
1131	template<> template<> 
1132	void TestLLSDNotationParsingObject::test<12>()
1133	{
1134		ensureParse(
1135			"invalid -- binary length specified too long",
1136			"b(7)\"abc321\"",
1137			LLSD(),
1138			LLSDParser::PARSE_FAILURE);
1139		ensureParse(
1140			"invalid -- binary length specified way too long",
1141			"b(1000000)\"abc321\"",
1142			LLSD(),
1143			LLSDParser::PARSE_FAILURE);
1144	}
1145
1146	template<> template<> 
1147	void TestLLSDNotationParsingObject::test<13>()
1148	{
1149		LLSD val;
1150		val["amy"] = 23;
1151		val["bob"] = LLSD();
1152		val["cam"] = 1.23;
1153		ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4);
1154
1155		val["bob"] = LLSD::emptyMap();
1156		val["bob"]["vehicle"] = std::string("bicycle");
1157		ensureParse(
1158			"nested map",
1159			"{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}",
1160			val,
1161			5);
1162	}
1163
1164	template<> template<> 
1165	void TestLLSDNotationParsingObject::test<14>()
1166	{
1167		LLSD val;
1168		val.append(23);
1169		val.append(LLSD());
1170		val.append(1.23);
1171		ensureParse("simple array", "[i23,!,r1.23]", val, 4);
1172		val[1] = LLSD::emptyArray();
1173		val[1].append("bicycle");
1174		ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5);
1175	}
1176
1177	template<> template<> 
1178	void TestLLSDNotationParsingObject::test<15>()
1179	{
1180		LLSD val;
1181		val["amy"] = 23;
1182		val["bob"]["dogs"] = LLSD::emptyArray();
1183		val["bob"]["dogs"].append(LLSD::emptyMap());
1184		val["bob"]["dogs"][0]["name"] = std::string("groove");
1185		val["bob"]["dogs"][0]["breed"] = std::string("samoyed");
1186		val["bob"]["dogs"].append(LLSD::emptyMap());
1187		val["bob"]["dogs"][1]["name"] = std::string("greyley");
1188		val["bob"]["dogs"][1]["breed"] = std::string("chow/husky");
1189		val["cam"] = 1.23;
1190		ensureParse(
1191			"nested notation",
1192			"{'amy':i23,"
1193			" 'bob':{'dogs':["
1194			         "{'name':'groove', 'breed':'samoyed'},"
1195			         "{'name':'greyley', 'breed':'chow/husky'}]},"
1196			" 'cam':r1.23}",
1197			val,
1198			11);
1199	}
1200
1201	template<> template<> 
1202	void TestLLSDNotationParsingObject::test<16>()
1203	{
1204		// text to make sure that incorrect sizes bail because 
1205		std::string bad_str("s(5)\"hi\"");
1206		ensureParse(
1207			"size longer than bytes left",
1208			bad_str,
1209			LLSD(),
1210			LLSDParser::PARSE_FAILURE);
1211	}
1212
1213	template<> template<> 
1214	void TestLLSDNotationParsingObject::test<17>()
1215	{
1216		// text to make sure that incorrect sizes bail because 
1217		std::string bad_bin("b(5)\"hi\"");
1218		ensureParse(
1219			"size longer than bytes left",
1220			bad_bin,
1221			LLSD(),
1222			LLSDParser::PARSE_FAILURE);
1223	}
1224
1225	/**
1226	 * @class TestLLSDBinaryParsing
1227	 * @brief Concrete instance of a parse tester.
1228	 */
1229	class TestLLSDBinaryParsing : public TestLLSDParsing<LLSDBinaryParser>
1230	{
1231	public:
1232		TestLLSDBinaryParsing() {}
1233	};
1234
1235	typedef tut::test_group<TestLLSDBinaryParsing> TestLLSDBinaryParsingGroup;
1236	typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject;
1237	TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup(
1238		"llsd binary parsing");
1239
1240	template<> template<> 
1241	void TestLLSDBinaryParsingObject::test<1>()
1242	{
1243		std::vector<U8> vec;
1244		vec.resize(6);
1245		vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c';
1246		vec[3] = '3'; vec[4] = '2'; vec[5] = '1';
1247		std::string string_expected((char*)&vec[0], vec.size());
1248		LLSD value = string_expected;
1249
1250		vec.resize(11);
1251		vec[0] = 's'; // for string
1252		vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c';
1253		vec[8] = '3'; vec[9] = '2'; vec[10] = '1';
1254
1255		uint32_t size = htonl(6);
1256		memcpy(&vec[1], &size, sizeof(uint32_t));
1257		std::string str_good((char*)&vec[0], vec.size());
1258		ensureParse("correct string parse", str_good, value, 1);
1259
1260		size = htonl(7);
1261		memcpy(&vec[1], &size, sizeof(uint32_t));
1262		std::string str_bad_1((char*)&vec[0], vec.size());
1263		ensureParse(
1264			"incorrect size string parse",
1265			str_bad_1,
1266			LLSD(),
1267			LLSDParser::PARSE_FAILURE);
1268
1269		size = htonl(100000);
1270		memcpy(&vec[1], &size, sizeof(uint32_t));
1271		std::string str_bad_2((char*)&vec[0], vec.size());
1272		ensureParse(
1273			"incorrect size string parse",
1274			str_bad_2,
1275			LLSD(),
1276			LLSDParser::PARSE_FAILURE);
1277	}
1278
1279	template<> template<> 
1280	void TestLLSDBinaryParsingObject::test<2>()
1281	{
1282		std::vector<U8> vec;
1283		vec.resize(6);
1284		vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c';
1285		vec[3] = '3'; vec[4] = '2'; vec[5] = '1';
1286		LLSD value = vec;
1287		
1288		vec.resize(11);
1289		vec[0] = 'b';  // for binary
1290		vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c';
1291		vec[8] = '3'; vec[9] = '2'; vec[10] = '1';
1292
1293		uint32_t size = htonl(6);
1294		memcpy(&vec[1], &size, sizeof(uint32_t));
1295		std::string str_good((char*)&vec[0], vec.size());
1296		ensureParse("correct binary parse", str_good, value, 1);
1297
1298		size = htonl(7);
1299		memcpy(&vec[1], &size, sizeof(uint32_t));
1300		std::string str_bad_1((char*)&vec[0], vec.size());
1301		ensureParse(
1302			"incorrect size binary parse 1",
1303			str_bad_1,
1304			LLSD(),
1305			LLSDParser::PARSE_FAILURE);
1306
1307		size = htonl(100000);
1308		memcpy(&vec[1], &size, sizeof(uint32_t));
1309		std::string str_bad_2((char*)&vec[0], vec.size());
1310		ensureParse(
1311			"incorrect size binary parse 2",
1312			str_bad_2,
1313			LLSD(),
1314			LLSDParser::PARSE_FAILURE);
1315	}
1316
1317	template<> template<> 
1318	void TestLLSDBinaryParsingObject::test<3>()
1319	{
1320		// test handling of xml not recognized as llsd results in an
1321		// LLSD Undefined
1322		ensureParse(
1323			"malformed binary map",
1324			"{'ha ha'",
1325			LLSD(),
1326			LLSDParser::PARSE_FAILURE);
1327		ensureParse(
1328			"malformed binary array",
1329			"['ha ha'",
1330			LLSD(),
1331			LLSDParser::PARSE_FAILURE);
1332		ensureParse(
1333			"malformed binary string",
1334			"'ha ha",
1335			LLSD(),
1336			LLSDParser::PARSE_FAILURE);
1337		ensureParse(
1338			"bad noise",
1339			"g48ejlnfr",
1340			LLSD(),
1341			LLSDParser::PARSE_FAILURE);
1342	}
1343	template<> template<> 
1344	void TestLLSDBinaryParsingObject::test<4>()
1345	{
1346		ensureParse("valid undef", "!", LLSD(), 1);
1347	}
1348
1349	template<> template<> 
1350	void TestLLSDBinaryParsingObject::test<5>()
1351	{
1352		LLSD val = false;
1353		ensureParse("valid boolean false 2", "0", val, 1);
1354		val = true;
1355		ensureParse("valid boolean true 2", "1", val, 1);
1356
1357		val.clear();
1358		ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE);
1359		ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE);
1360	}
1361
1362	template<> template<> 
1363	void TestLLSDBinaryParsingObject::test<6>()
1364	{
1365		std::vector<U8> vec;
1366		vec.push_back('{');
1367		vec.resize(vec.size() + 4);
1368		uint32_t size = htonl(1);
1369		memcpy(&vec[1], &size, sizeof(uint32_t));
1370		vec.push_back('k');
1371		int key_size_loc = vec.size();
1372		size = htonl(1); // 1 too short
1373		vec.resize(vec.size() + 4);
1374		memcpy(&vec[key_size_loc], &size, sizeof(uint32_t));
1375		vec.push_back('a'); vec.push_back('m'); vec.push_back('y');
1376		vec.push_back('i');
1377		int integer_loc = vec.size();
1378		vec.resize(vec.size() + 4);
1379		uint32_t val_int = htonl(23);
1380		memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t));
1381		std::string str_bad_1((char*)&vec[0], vec.size());
1382		ensureParse(
1383			"invalid key size",
1384			str_bad_1,
1385			LLSD(),
1386			LLSDParser::PARSE_FAILURE);
1387
1388		// check with correct size, but unterminated map (missing '}')
1389		size = htonl(3); // correct size
1390		memcpy(&vec[key_size_loc], &size, sizeof(uint32_t));
1391		std::string str_bad_2((char*)&vec[0], vec.size());
1392		ensureParse(
1393			"valid key size, unterminated map",
1394			str_bad_2,
1395			LLSD(),
1396			LLSDParser::PARSE_FAILURE);
1397
1398		// check w/ correct size and correct map termination
1399		LLSD val;
1400		val["amy"] = 23;
1401		vec.push_back('}');
1402		std::string str_good((char*)&vec[0], vec.size());
1403		ensureParse(
1404			"valid map",
1405			str_good,
1406			val,
1407			2);
1408
1409		// check w/ incorrect sizes and correct map termination
1410		size = htonl(0); // 1 too few (for the map entry)
1411		memcpy(&vec[1], &size, sizeof(uint32_t));
1412		std::string str_bad_3((char*)&vec[0], vec.size());
1413		ensureParse(
1414			"invalid map too long",
1415			str_bad_3,
1416			LLSD(),
1417			LLSDParser::PARSE_FAILURE);
1418
1419		size = htonl(2); // 1 too many
1420		memcpy(&vec[1], &size, sizeof(uint32_t));
1421		std::string str_bad_4((char*)&vec[0], vec.size());
1422		ensureParse(
1423			"invalid map too short",
1424			str_bad_4,
1425			LLSD(),
1426			LLSDParser::PARSE_FAILURE);
1427	}
1428
1429	template<> template<> 
1430	void TestLLSDBinaryParsingObject::test<7>()
1431	{
1432		std::vector<U8> vec;
1433		vec.push_back('[');
1434		vec.resize(vec.size() + 4);
1435		uint32_t size = htonl(1); // 1 too short
1436		memcpy(&vec[1], &size, sizeof(uint32_t));
1437		vec.push_back('"'); vec.push_back('a'); vec.push_back('m');
1438		vec.push_back('y'); vec.push_back('"'); vec.push_back('i');
1439		int integer_loc = vec.size();
1440		vec.resize(vec.size() + 4);
1441		uint32_t val_int = htonl(23);
1442		memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t));
1443
1444		std::string str_bad_1((char*)&vec[0], vec.size());
1445		ensureParse(
1446			"invalid array size",
1447			str_bad_1,
1448			LLSD(),
1449			LLSDParser::PARSE_FAILURE);
1450
1451		// check with correct size, but unterminated map (missing ']')
1452		size = htonl(2); // correct size
1453		memcpy(&vec[1], &size, sizeof(uint32_t));
1454		std::string str_bad_2((char*)&vec[0], vec.size());
1455		ensureParse(
1456			"unterminated array",
1457			str_bad_2,
1458			LLSD(),
1459			LLSDParser::PARSE_FAILURE);
1460
1461		// check w/ correct size and correct map termination
1462		LLSD val;
1463		val.append("amy");
1464		val.append(23);
1465		vec.push_back(']');
1466		std::string str_good((char*)&vec[0], vec.size());
1467		ensureParse(
1468			"valid array",
1469			str_good,
1470			val,
1471			3);
1472
1473		// check with too many elements
1474		size = htonl(3); // 1 too long
1475		memcpy(&vec[1], &size, sizeof(uint32_t));
1476		std::string str_bad_3((char*)&vec[0], vec.size());
1477		ensureParse(
1478			"array too short",
1479			str_bad_3,
1480			LLSD(),
1481			LLSDParser::PARSE_FAILURE);
1482	}
1483
1484	template<> template<> 
1485	void TestLLSDBinaryParsingObject::test<8>()
1486	{
1487		std::vector<U8> vec;
1488		vec.push_back('{');
1489		vec.resize(vec.size() + 4);
1490		memset(&vec[1], 0, 4);
1491		vec.push_back('}');
1492		std::string str_good((char*)&vec[0], vec.size());
1493		LLSD val = LLSD::emptyMap();
1494		ensureParse(
1495			"empty map",
1496			str_good,
1497			val,
1498			1);
1499	}
1500
1501	template<> template<> 
1502	void TestLLSDBinaryParsingObject::test<9>()
1503	{
1504		std::vector<U8> vec;
1505		vec.push_back('[');
1506		vec.resize(vec.size() + 4);
1507		memset(&vec[1], 0, 4);
1508		vec.push_back(']');
1509		std::string str_good((char*)&vec[0], vec.size());
1510		LLSD val = LLSD::emptyArray();
1511		ensureParse(
1512			"empty array",
1513			str_good,
1514			val,
1515			1);
1516	}
1517
1518	template<> template<> 
1519	void TestLLSDBinaryParsingObject::test<10>()
1520	{
1521		std::vector<U8> vec;
1522		vec.push_back('l');
1523		vec.resize(vec.size() + 4);
1524		uint32_t size = htonl(14); // 1 too long
1525		memcpy(&vec[1], &size, sizeof(uint32_t));
1526		vec.push_back('h'); vec.push_back('t'); vec.push_back('t');
1527		vec.push_back('p'); vec.push_back(':'); vec.push_back('/');
1528		vec.push_back('/'); vec.push_back('s'); vec.push_back('l');
1529		vec.push_back('.'); vec.push_back('c'); vec.push_back('o');
1530		vec.push_back('m');
1531		std::string str_bad((char*)&vec[0], vec.size());
1532		ensureParse(
1533			"invalid uri length size",
1534			str_bad,
1535			LLSD(),
1536			LLSDParser::PARSE_FAILURE);
1537
1538		LLSD val;
1539		val = LLURI("http://sl.com");
1540		size = htonl(13); // correct length
1541		memcpy(&vec[1], &size, sizeof(uint32_t));
1542		std::string str_good((char*)&vec[0], vec.size());
1543		ensureParse(
1544			"valid key size",
1545			str_good,
1546			val,
1547			1);
1548	}
1549
1550/*
1551	template<> template<> 
1552	void TestLLSDBinaryParsingObject::test<11>()
1553	{
1554	}
1555*/
1556
1557   /**
1558	 * @class TestLLSDCrossCompatible
1559	 * @brief Miscellaneous serialization and parsing tests
1560	 */
1561	class TestLLSDCrossCompatible
1562	{
1563	public:
1564		TestLLSDCrossCompatible() {}
1565
1566		void ensureBinaryAndNotation(
1567			const std::string& msg,
1568			const LLSD& input)
1569		{
1570			// to binary, and back again
1571			std::stringstream str1;
1572			S32 count1 = LLSDSerialize::toBinary(input, str1);
1573			LLSD actual_value_bin;
1574			S32 count2 = LLSDSerialize::fromBinary(
1575				actual_value_bin,
1576				str1,
1577				LLSDSerialize::SIZE_UNLIMITED);
1578			ensure_equals(
1579				"ensureBinaryAndNotation binary count",
1580				count2,
1581				count1);
1582
1583			// to notation and back again
1584			std::stringstream str2;
1585			S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2);
1586			ensure_equals(
1587				"ensureBinaryAndNotation notation count1",
1588				count3,
1589				count2);
1590			LLSD actual_value_notation;
1591			S32 count4 = LLSDSerialize::fromNotation(
1592				actual_value_notation,
1593				str2,
1594				LLSDSerialize::SIZE_UNLIMITED);
1595			ensure_equals(
1596				"ensureBinaryAndNotation notation count2",
1597				count4,
1598				count3);
1599			ensure_equals(
1600				(msg + " (binaryandnotation)").c_str(),
1601				actual_value_notation,
1602				input);
1603		}
1604
1605		void ensureBinaryAndXML(
1606			const std::string& msg,
1607			const LLSD& input)
1608		{
1609			// to binary, and back again
1610			std::stringstream str1;
1611			S32 count1 = LLSDSerialize::toBinary(input, str1);
1612			LLSD actual_value_bin;
1613			S32 count2 = LLSDSerialize::fromBinary(
1614				actual_value_bin,
1615				str1,
1616				LLSDSerialize::SIZE_UNLIMITED);
1617			ensure_equals(
1618				"ensureBinaryAndXML binary count",
1619				count2,
1620				count1);
1621
1622			// to xml and back again
1623			std::stringstream str2;
1624			S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2);
1625			ensure_equals(
1626				"ensureBinaryAndXML xml count1",
1627				count3,
1628				count2);
1629			LLSD actual_value_xml;
1630			S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2);
1631			ensure_equals(
1632				"ensureBinaryAndXML xml count2",
1633				count4,
1634				count3);
1635			ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input);
1636		}
1637	};
1638
1639	typedef tut::test_group<TestLLSDCrossCompatible> TestLLSDCompatibleGroup;
1640	typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject;
1641	TestLLSDCompatibleGroup gTestLLSDCompatibleGroup(
1642		"llsd serialize compatible");
1643
1644	template<> template<> 
1645	void TestLLSDCompatibleObject::test<1>()
1646	{
1647		LLSD test;
1648		ensureBinaryAndNotation("undef", test);
1649		ensureBinaryAndXML("undef", test);
1650		test = true;
1651		ensureBinaryAndNotation("boolean true", test);
1652		ensureBinaryAndXML("boolean true", test);
1653		test = false;
1654		ensureBinaryAndNotation("boolean false", test);
1655		ensureBinaryAndXML("boolean false", test);
1656		test = 0;
1657		ensureBinaryAndNotation("integer zero", test);
1658		ensureBinaryAndXML("integer zero", test);
1659		test = 1;
1660		ensureBinaryAndNotation("integer positive", test);
1661		ensureBinaryAndXML("integer positive", test);
1662		test = -234567;
1663		ensureBinaryAndNotation("integer negative", test);
1664		ensureBinaryAndXML("integer negative", test);
1665		test = 0.0;
1666		ensureBinaryAndNotation("real zero", test);
1667		ensureBinaryAndXML("real zero", test);
1668		test = 1.0;
1669		ensureBinaryAndNotation("real positive", test);
1670		ensureBinaryAndXML("real positive", test);
1671		test = -1.0;
1672		ensureBinaryAndNotation("real negative", test);
1673		ensureBinaryAndXML("real negative", test);
1674	}
1675
1676	template<> template<> 
1677	void TestLLSDCompatibleObject::test<2>()
1678	{
1679		LLSD test;
1680		test = "foobar";
1681		ensureBinaryAndNotation("string", test);
1682		ensureBinaryAndXML("string", test);
1683	}
1684
1685	template<> template<> 
1686	void TestLLSDCompatibleObject::test<3>()
1687	{
1688		LLSD test;
1689		LLUUID id;
1690		id.generate();
1691		test = id;
1692		ensureBinaryAndNotation("uuid", test);
1693		ensureBinaryAndXML("uuid", test);
1694	}
1695
1696	template<> template<> 
1697	void TestLLSDCompatibleObject::test<4>()
1698	{
1699		LLSD test;
1700		test = LLDate(12345.0);
1701		ensureBinaryAndNotation("date", test);
1702		ensureBinaryAndXML("date", test);
1703	}
1704
1705	template<> template<> 
1706	void TestLLSDCompatibleObject::test<5>()
1707	{
1708		LLSD test;
1709		test = LLURI("http://www.secondlife.com/");
1710		ensureBinaryAndNotation("uri", test);
1711		ensureBinaryAndXML("uri", test);
1712	}
1713
1714	template<> template<> 
1715	void TestLLSDCompatibleObject::test<6>()
1716	{
1717		LLSD test;
1718		typedef std::vector<U8> buf_t;
1719		buf_t val;
1720		for(int ii = 0; ii < 100; ++ii)
1721		{
1722			srand(ii);		/* Flawfinder: ignore */
1723			S32 size = rand() % 100 + 10;
1724			std::generate_n(
1725				std::back_insert_iterator<buf_t>(val),
1726				size,
1727				rand);
1728		}
1729		test = val;
1730		ensureBinaryAndNotation("binary", test);
1731		ensureBinaryAndXML("binary", test);
1732	}
1733
1734	template<> template<> 
1735	void TestLLSDCompatibleObject::test<7>()
1736	{
1737		LLSD test;
1738		test = LLSD::emptyArray();
1739		test.append(1);
1740		test.append("hello");
1741		ensureBinaryAndNotation("array", test);
1742		ensureBinaryAndXML("array", test);
1743	}
1744
1745	template<> template<> 
1746	void TestLLSDCompatibleObject::test<8>()
1747	{
1748		LLSD test;
1749		test = LLSD::emptyArray();
1750		test["foo"] = "bar";
1751		test["baz"] = 100;
1752		ensureBinaryAndNotation("map", test);
1753		ensureBinaryAndXML("map", test);
1754	}
1755
1756    struct TestPythonCompatible
1757    {
1758        TestPythonCompatible():
1759            // Note the peculiar insertion of __FILE__ into this string. Since
1760            // this script is being written into a platform-dependent temp
1761            // directory, we can't locate indra/lib/python relative to
1762            // Python's __file__. Use __FILE__ instead, navigating relative
1763            // to this C++ source file. Use Python raw-string syntax so
1764            // Windows pathname backslashes won't mislead Python's string
1765            // scanner.
1766            import_llsd("import os.path\n"
1767                    

Large files files are truncated, but you can click here to view the full file