llsdserialize_tut.cpp

Go to the documentation of this file.
00001 
00033 #include <tut/tut.h>
00034 
00035 #include "linden_common.h"
00036 #include "llsd.h"
00037 #include "llsdserialize.h"
00038 #include "lltut.h"
00039 #include "llformat.h"
00040 
00041 // These tests take too long to run on Windows. JC
00042 #if !LL_WINDOWS
00043 
00044 namespace tut
00045 {
00046         struct sd_xml_data
00047         {
00048                 sd_xml_data()
00049                 {
00050                         mFormatter = new LLSDXMLFormatter;
00051                 }
00052                 LLSD mSD;
00053                 LLPointer<LLSDXMLFormatter> mFormatter;
00054                 void xml_test(const char* name, const std::string& expected)
00055                 {
00056                         std::ostringstream ostr;
00057                         mFormatter->format(mSD, ostr);
00058                         ensure_equals(name, ostr.str(), expected);
00059                 }
00060         };
00061 
00062         typedef test_group<sd_xml_data> sd_xml_test;
00063         typedef sd_xml_test::object sd_xml_object;
00064         tut::sd_xml_test sd_xml_stream("sd_xml_serialization");
00065 
00066         template<> template<>
00067         void sd_xml_object::test<1>()
00068         {
00069                 // random atomic tests
00070                 std::string expected;
00071 
00072                 expected = "<llsd><undef /></llsd>\n";
00073                 xml_test("undef", expected);
00074 
00075                 mSD = 3463;
00076                 expected = "<llsd><integer>3463</integer></llsd>\n";
00077                 xml_test("integer", expected);
00078 
00079                 mSD = "";
00080                 expected = "<llsd><string /></llsd>\n";
00081                 xml_test("empty string", expected);
00082 
00083                 mSD = "foobar";
00084                 expected = "<llsd><string>foobar</string></llsd>\n";
00085                 xml_test("string", expected);
00086 
00087                 mSD = LLUUID::null;
00088                 expected = "<llsd><uuid /></llsd>\n";
00089                 xml_test("null uuid", expected);
00090                 
00091                 mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed");
00092                 expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n";
00093                 xml_test("uuid", expected);
00094 
00095                 mSD = LLURI("https://secondlife.com/login");
00096                 expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n";
00097                 xml_test("uri", expected);
00098 
00099                 mSD = LLDate("2006-04-24T16:11:33Z");
00100                 expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n";
00101                 xml_test("date", expected);
00102 
00103                 // *FIX: test binary
00104         }
00105         
00106         template<> template<>
00107         void sd_xml_object::test<2>()
00108         {
00109                 // tests with boolean values.
00110                 std::string expected;
00111 
00112                 mFormatter->boolalpha(true);
00113                 mSD = true;
00114                 expected = "<llsd><boolean>true</boolean></llsd>\n";
00115                 xml_test("bool alpha true", expected);
00116                 mSD = false;
00117                 expected = "<llsd><boolean>false</boolean></llsd>\n";
00118                 xml_test("bool alpha false", expected);
00119 
00120                 mFormatter->boolalpha(false);
00121                 mSD = true;
00122                 expected = "<llsd><boolean>1</boolean></llsd>\n";
00123                 xml_test("bool true", expected);
00124                 mSD = false;
00125                 expected = "<llsd><boolean>0</boolean></llsd>\n";
00126                 xml_test("bool false", expected);
00127         }
00128 
00129 
00130         template<> template<>
00131         void sd_xml_object::test<3>()
00132         {
00133                 // tests with real values.
00134                 std::string expected;
00135 
00136                 mFormatter->realFormat("%.2f");
00137                 mSD = 1.0;
00138                 expected = "<llsd><real>1.00</real></llsd>\n";
00139                 xml_test("real 1", expected);
00140 
00141                 mSD = -34379.0438;
00142                 expected = "<llsd><real>-34379.04</real></llsd>\n";
00143                 xml_test("real reduced precision", expected);
00144                 mFormatter->realFormat("%.4f");
00145                 expected = "<llsd><real>-34379.0438</real></llsd>\n";
00146                 xml_test("higher precision", expected);
00147 
00148                 mFormatter->realFormat("%.0f");
00149                 mSD = 0.0;
00150                 expected = "<llsd><real>0</real></llsd>\n";
00151                 xml_test("no decimal 0", expected);
00152                 mSD = 3287.4387;
00153                 expected = "<llsd><real>3287</real></llsd>\n";
00154                 xml_test("no decimal real number", expected);
00155         }
00156 
00157         template<> template<>
00158         void sd_xml_object::test<4>()
00159         {
00160                 // tests with arrays
00161                 std::string expected;
00162 
00163                 mSD = LLSD::emptyArray();
00164                 expected = "<llsd><array /></llsd>\n";
00165                 xml_test("empty array", expected);
00166 
00167                 mSD.append(LLSD());
00168                 expected = "<llsd><array><undef /></array></llsd>\n";
00169                 xml_test("1 element array", expected);
00170 
00171                 mSD.append(1);
00172                 expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n";
00173                 xml_test("2 element array", expected);
00174         }
00175 
00176         template<> template<>
00177         void sd_xml_object::test<5>()
00178         {
00179                 // tests with arrays
00180                 std::string expected;
00181 
00182                 mSD = LLSD::emptyMap();
00183                 expected = "<llsd><map /></llsd>\n";
00184                 xml_test("empty map", expected);
00185 
00186                 mSD["foo"] = "bar";
00187                 expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n";
00188                 xml_test("1 element map", expected);
00189 
00190                 mSD["baz"] = LLSD();
00191                 expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n";
00192                 xml_test("2 element map", expected);
00193         }
00194         
00195         
00196         class TestLLSDSerializeData
00197         {
00198         public:
00199                 TestLLSDSerializeData();
00200                 ~TestLLSDSerializeData();
00201 
00202                 void doRoundTripTests(const std::string&);
00203                 void checkRoundTrip(const std::string&, const LLSD& v);
00204                 
00205                 LLPointer<LLSDFormatter> mFormatter;
00206                 LLPointer<LLSDParser> mParser;
00207         };
00208 
00209         TestLLSDSerializeData::TestLLSDSerializeData()
00210         {
00211         }
00212 
00213         TestLLSDSerializeData::~TestLLSDSerializeData()
00214         {
00215         }
00216 
00217         void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v)
00218         {
00219                 std::stringstream stream;       
00220                 mFormatter->format(v, stream);
00221                 //llinfos << "checkRoundTrip: length " << stream.str().length() << llendl;
00222                 LLSD w;
00223                 mParser->parse(stream, w);
00224                 
00225                 try
00226                 {
00227                         ensure_equals(msg, w, v);
00228                 }
00229                 catch (...)
00230                 {
00231                         std::cerr << "the serialized string was:" << std::endl;
00232                         std::cerr << stream.str() << std::endl;
00233                         throw;
00234                 }
00235         }
00236 
00237         static void fillmap(LLSD& root, U32 width, U32 depth)
00238         {
00239                 if(depth == 0)
00240                 {
00241                         root["foo"] = "bar";
00242                         return;
00243                 }
00244 
00245                 for(U32 i = 0; i < width; ++i)
00246                 {
00247                         std::string key = llformat("child %d", i);
00248                         root[key] = LLSD::emptyMap();
00249                         fillmap(root[key], width, depth - 1);
00250                 }
00251         }
00252         
00253         void TestLLSDSerializeData::doRoundTripTests(const std::string& msg)
00254         {
00255                 LLSD v;
00256                 checkRoundTrip(msg + " undefined", v);
00257                 
00258                 v = true;
00259                 checkRoundTrip(msg + " true bool", v);
00260                 
00261                 v = false;
00262                 checkRoundTrip(msg + " false bool", v);
00263                 
00264                 v = 1;
00265                 checkRoundTrip(msg + " positive int", v);
00266                 
00267                 v = 0;
00268                 checkRoundTrip(msg + " zero int", v);
00269                 
00270                 v = -1;
00271                 checkRoundTrip(msg + " negative int", v);
00272                 
00273                 v = 1234.5f;
00274                 checkRoundTrip(msg + " positive float", v);
00275                 
00276                 v = 0.0f;
00277                 checkRoundTrip(msg + " zero float", v);
00278                 
00279                 v = -1234.5f;
00280                 checkRoundTrip(msg + " negative float", v);
00281                 
00282                 // FIXME: need a NaN test
00283                 
00284                 v = LLUUID::null;
00285                 checkRoundTrip(msg + " null uuid", v);
00286                 
00287                 LLUUID newUUID;
00288                 newUUID.generate();
00289                 v = newUUID;
00290                 checkRoundTrip(msg + " new uuid", v);
00291                 
00292                 v = "";
00293                 checkRoundTrip(msg + " empty string", v);
00294                 
00295                 v = "some string";
00296                 checkRoundTrip(msg + " non-empty string", v);
00297                 
00298                 v =
00299 "Second Life is a 3-D virtual world entirely built and owned by its residents. "
00300 "Since opening to the public in 2003, it has grown explosively and today is "
00301 "inhabited by nearly 100,000 people from around the globe.\n"
00302 "\n"
00303 "From the moment you enter the World you'll discover a vast digital continent, "
00304 "teeming with people, entertainment, experiences and opportunity. Once you've "
00305 "explored a bit, perhaps you'll find a perfect parcel of land to build your "
00306 "house or business.\n"
00307 "\n"
00308 "You'll also be surrounded by the Creations of your fellow residents. Because "
00309 "residents retain the rights to their digital creations, they can buy, sell "
00310 "and trade with other residents.\n"
00311 "\n"
00312 "The Marketplace currently supports millions of US dollars in monthly "
00313 "transactions. This commerce is handled with the in-world currency, the Linden "
00314 "dollar, which can be converted to US dollars at several thriving online "
00315 "currency exchanges.\n"
00316 "\n"
00317 "Welcome to Second Life. We look forward to seeing you in-world!\n"
00318                 ;
00319                 checkRoundTrip(msg + " long string", v);
00320 
00321                 static const U32 block_size = 0x000020;
00322                 for (U32 block = 0x000000; block <= 0x10ffff; block += block_size)
00323                 {
00324                         std::ostringstream out;
00325                         
00326                         for (U32 c = block; c < block + block_size; ++c)
00327                         {
00328                                 if (c <= 0x000001f
00329                                         && c != 0x000009
00330                                         && c != 0x00000a)
00331                                 {
00332                                         // see XML standard, sections 2.2 and 4.1
00333                                         continue;
00334                                 }
00335                                 if (0x00d800 <= c  &&  c <= 0x00dfff) { continue; }
00336                                 if (0x00fdd0 <= c  &&  c <= 0x00fdef) { continue; }
00337                                 if ((c & 0x00fffe) == 0x00fffe) { continue; }           
00338                                         // see Unicode standard, section 15.8 
00339                                 
00340                                 if (c <= 0x00007f)
00341                                 {
00342                                         out << (char)(c & 0x7f);
00343                                 }
00344                                 else if (c <= 0x0007ff)
00345                                 {
00346                                         out << (char)(0xc0 | ((c >> 6) & 0x1f));
00347                                         out << (char)(0x80 | ((c >> 0) & 0x3f));
00348                                 }
00349                                 else if (c <= 0x00ffff)
00350                                 {
00351                                         out << (char)(0xe0 | ((c >> 12) & 0x0f));
00352                                         out << (char)(0x80 | ((c >>  6) & 0x3f));
00353                                         out << (char)(0x80 | ((c >>  0) & 0x3f));
00354                                 }
00355                                 else
00356                                 {
00357                                         out << (char)(0xf0 | ((c >> 18) & 0x07));
00358                                         out << (char)(0x80 | ((c >> 12) & 0x3f));
00359                                         out << (char)(0x80 | ((c >>  6) & 0x3f));
00360                                         out << (char)(0x80 | ((c >>  0) & 0x3f));
00361                                 }
00362                         }
00363                         
00364                         v = out.str();
00365 
00366                         std::ostringstream blockmsg;
00367                         blockmsg << msg << " unicode string block 0x" << std::hex << block; 
00368                         checkRoundTrip(blockmsg.str(), v);
00369                 }
00370                 
00371                 LLDate epoch;
00372                 v = epoch;
00373                 checkRoundTrip(msg + " epoch date", v);
00374                 
00375                 LLDate aDay("2002-12-07T05:07:15.00Z");
00376                 v = aDay;
00377                 checkRoundTrip(msg + " date", v);
00378                 
00379                 LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/");
00380                 v = path;
00381                 checkRoundTrip(msg + " url", v);
00382                 
00383                 const char source[] = "it must be a blue moon again";
00384                 std::vector<U8> data;
00385                 copy(&source[0], &source[sizeof(source)], back_inserter(data));
00386                 
00387                 v = data;
00388                 checkRoundTrip(msg + " binary", v);
00389                 
00390                 v = LLSD::emptyMap();
00391                 checkRoundTrip(msg + " empty map", v);
00392                 
00393                 v = LLSD::emptyMap();
00394                 v["name"] = "luke";             //v.insert("name", "luke");
00395                 v["age"] = 3;                   //v.insert("age", 3);
00396                 checkRoundTrip(msg + " map", v);
00397                 
00398                 v.clear();
00399                 v["a"]["1"] = true;
00400                 v["b"]["0"] = false;
00401                 checkRoundTrip(msg + " nested maps", v);
00402                 
00403                 v = LLSD::emptyArray();
00404                 checkRoundTrip(msg + " empty array", v);
00405                 
00406                 v = LLSD::emptyArray();
00407                 v.append("ali");
00408                 v.append(28);
00409                 checkRoundTrip(msg + " array", v);
00410                 
00411                 v.clear();
00412                 v[0][0] = true;
00413                 v[1][0] = false;
00414                 checkRoundTrip(msg + " nested arrays", v);
00415 
00416                 v = LLSD::emptyMap();
00417                 fillmap(v, 10, 6); // 10^6 maps
00418                 checkRoundTrip(msg + " many nested maps", v);
00419         }
00420         
00421         typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerialzeGroup;
00422         typedef TestLLSDSerialzeGroup::object TestLLSDSerializeObject;
00423         TestLLSDSerialzeGroup gTestLLSDSerializeGroup("llsd serialization");
00424 
00425         template<> template<> 
00426         void TestLLSDSerializeObject::test<1>()
00427         {
00428                 mFormatter = new LLSDNotationFormatter();
00429                 mParser = new LLSDNotationParser();
00430                 doRoundTripTests("notation serialization");
00431         }
00432         
00433         template<> template<> 
00434         void TestLLSDSerializeObject::test<2>()
00435         {
00436                 mFormatter = new LLSDXMLFormatter();
00437                 mParser = new LLSDXMLParser();
00438                 doRoundTripTests("xml serialization");
00439         }
00440         
00441         template<> template<> 
00442         void TestLLSDSerializeObject::test<3>()
00443         {
00444                 mFormatter = new LLSDBinaryFormatter();
00445                 mParser = new LLSDBinaryParser();
00446                 doRoundTripTests("binary serialization");
00447         }
00448 
00449         
00450         
00451         
00452         class TestLLSDXMLParsing
00453         {
00454         public:
00455                 TestLLSDXMLParsing()
00456                 {
00457                         mParser = new LLSDXMLParser;
00458                 }
00459                 void ensureParse(const std::string& msg, const char* xml, const LLSD& expected);
00460                 
00461                 LLPointer<LLSDXMLParser> mParser;
00462         };
00463         
00464         void TestLLSDXMLParsing::ensureParse(
00465                 const std::string& msg, const char* xmlstring, const LLSD& expected)
00466         {
00467                 std::stringstream input;
00468                 input.str(xmlstring);
00469                 
00470                 LLSD parsedResult;
00471                 mParser->parse(input, parsedResult);
00472                 
00473                 ensure_equals(msg, parsedResult, expected);
00474         }
00475         
00476 
00477         typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup;
00478         typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject;
00479         TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing");
00480 
00481         template<> template<> 
00482         void TestLLSDXMLParsingObject::test<1>()
00483         {
00484                 // test handling of xml not recognized as llsd results in an LLSD Undefined"
00485                 
00486                 ensureParse("malformed xml", "<llsd><string>ha ha</string>", LLSD());
00487                 ensureParse("not llsd", "<html><body><p>ha ha</p></body></html>", LLSD());
00488                 ensureParse("value without llsd", "<string>ha ha</string>", LLSD());
00489                 ensureParse("key without llsd", "<key>ha ha</key>", LLSD());
00490         }
00491         
00492         
00493         template<> template<> 
00494         void TestLLSDXMLParsingObject::test<2>()
00495         {
00496                 // test handling of unrecognized or unparseable llsd values
00497                 
00498                 LLSD v;
00499                 v["amy"] = 23;
00500                 v["bob"] = LLSD();
00501                 v["cam"] = 1.23;
00502                 
00503                 ensureParse("unknown data type",
00504                         "<llsd><map>"
00505                                 "<key>amy</key><integer>23</integer>"
00506                                 "<key>bob</key><bigint>99999999999999999</bigint>"
00507                                 "<key>cam</key><real>1.23</real>"
00508                         "</map></llsd>", v);
00509         }
00510         
00511         template<> template<> 
00512         void TestLLSDXMLParsingObject::test<3>()
00513         {
00514                 // test handling of nested bad data
00515                 
00516                 LLSD v;
00517                 v["amy"] = 23;
00518                 v["cam"] = 1.23;
00519                 
00520                 ensureParse("map with html",
00521                         "<llsd><map>"
00522                                 "<key>amy</key><integer>23</integer>"
00523                                 "<html><body>ha ha</body></html>"
00524                                 "<key>cam</key><real>1.23</real>"
00525                         "</map></llsd>", v);
00526                         
00527                 v.clear();
00528                 v["amy"] = 23;
00529                 v["cam"] = 1.23;
00530                 ensureParse("map with value for key",
00531                         "<llsd><map>"
00532                                 "<key>amy</key><integer>23</integer>"
00533                                 "<string>ha ha</string>"
00534                                 "<key>cam</key><real>1.23</real>"
00535                         "</map></llsd>", v);
00536                         
00537                 v.clear();
00538                 v["amy"] = 23;
00539                 v["bob"] = LLSD::emptyMap();
00540                 v["cam"] = 1.23;
00541                 ensureParse("map with map of html",
00542                         "<llsd><map>"
00543                                 "<key>amy</key><integer>23</integer>"
00544                                 "<key>bob</key>"
00545                                 "<map>"
00546                                         "<html><body>ha ha</body></html>"
00547                                 "</map>"
00548                                 "<key>cam</key><real>1.23</real>"
00549                         "</map></llsd>", v);
00550 
00551                 v.clear();
00552                 v[0] = 23;
00553                 v[1] = LLSD();
00554                 v[2] = 1.23;
00555                 
00556                 ensureParse("array value of html",
00557                         "<llsd><array>"
00558                                 "<integer>23</integer>"
00559                                 "<html><body>ha ha</body></html>"
00560                                 "<real>1.23</real>"
00561                         "</array></llsd>", v);
00562                         
00563                 v.clear();
00564                 v[0] = 23;
00565                 v[1] = LLSD::emptyMap();
00566                 v[2] = 1.23;
00567                 ensureParse("array with map of html",
00568                         "<llsd><array>"
00569                                 "<integer>23</integer>"
00570                                 "<map>"
00571                                         "<html><body>ha ha</body></html>"
00572                                 "</map>"
00573                                 "<real>1.23</real>"
00574                         "</array></llsd>", v);
00575         }
00576 
00577         /*
00578         TODO:
00579                 test XML parsing
00580                         binary with unrecognized encoding
00581                         nested LLSD tags
00582                         multiple values inside an LLSD
00583         */
00584 }
00585 
00586 #endif

Generated on Thu Jul 1 06:09:09 2010 for Second Life Viewer by  doxygen 1.4.7