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