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
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
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
00104 }
00105
00106 template<> template<>
00107 void sd_xml_object::test<2>()
00108 {
00109
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
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
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
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
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
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
00333 continue;
00334 }
00335 if (0x00d800 <= c && c <= 0x00dfff) { continue; }
00336 if (0x00fdd0 <= c && c <= 0x00fdef) { continue; }
00337 if ((c & 0x00fffe) == 0x00fffe) { continue; }
00338
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";
00395 v["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);
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
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
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
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
00579
00580
00581
00582
00583
00584 }
00585
00586 #endif