From c33cf379f25e9a1a3780a73805749616fa07de66 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 15 Jul 2011 11:53:05 -0400
Subject: [PATCH] Add test to verify C++-to-Python LLSD notation sequence.
 Write a sequence of LLSDSerialize::toNotation() calls separated by newlines
 to a data file, then read lines and parse using llbase.llsd.parse(). Verify
 that this produces expected data even when one item is a string containing
 newlines. Generalize python() helper function to allow using any of the
 NamedTempFile constructor forms. Allow specifying expected Python rc (default
 0) and use this to verify an intentional sys.exit(17). This is better than
 previous sys.exit(0) test because when, at one point, NamedTempFile failed to
 write file data, running Python on an empty script file still terminates with
 rc 0. A nonzero rc verifies that we've written the file, that Python is
 running it and that we're retrieving its rc.

---
 indra/llcommon/tests/llsdserialize_test.cpp | 65 +++++++++++++++++++--
 1 file changed, 61 insertions(+), 4 deletions(-)

diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index 8b59e99b241..aaf3740b075 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -68,6 +68,7 @@ typedef U32 uint32_t;
 #include "boost/foreach.hpp"
 #include "boost/function.hpp"
 #include "boost/lambda/lambda.hpp"
+#include "boost/lambda/bind.hpp"
 namespace lambda = boost::lambda;
 /*==========================================================================*|
 // Aaaarrgh, Linden's Boost package doesn't even include Boost.Iostreams!
@@ -77,6 +78,7 @@ namespace lambda = boost::lambda;
 
 #include "../llsd.h"
 #include "../llsdserialize.h"
+#include "llsdutil.h"
 #include "../llformat.h"
 
 #include "../test/lltut.h"
@@ -140,6 +142,13 @@ class NamedTempFile
         createFile(ext, lambda::_1 << content);
     }
 
+    // Disambiguate when passing string literal
+    NamedTempFile(const std::string& ext, const char* content):
+        mPath(temp_directory_path())
+    {
+        createFile(ext, lambda::_1 << content);
+    }
+
     NamedTempFile(const std::string& ext, const Streamer& func):
         mPath(temp_directory_path())
     {
@@ -1667,7 +1676,8 @@ namespace tut
         TestPythonCompatible() {}
         ~TestPythonCompatible() {}
 
-        void python(const std::string& desc, const std::string& script /*, F32 timeout=5 */)
+        template <typename CONTENT>
+        void python(const std::string& desc, const CONTENT& script, int expect=0)
         {
             const char* PYTHON(getenv("PYTHON"));
             ensure("Set $PYTHON to the Python interpreter", PYTHON);
@@ -1687,7 +1697,7 @@ namespace tut
             }
             else
             {
-                ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, 0);
+                ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, expect);
             }
 
 #else  // LL_DARWIN, LL_LINUX
@@ -1710,7 +1720,8 @@ namespace tut
                 if (WIFEXITED(status))
                 {
                     int rc(WEXITSTATUS(status));
-                    ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, 0);
+                    ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc),
+                                  rc, expect);
                 }
                 else if (WIFSIGNALED(status))
                 {
@@ -1737,7 +1748,8 @@ namespace tut
         set_test_name("verify python()");
         python("hello",
                "import sys\n"
-               "sys.exit(0)");
+               "sys.exit(17)",
+               17);                 // expect nonzero rc
     }
 
     template<> template<>
@@ -1748,4 +1760,49 @@ namespace tut
                "import sys\n"
                "print 'Running on', sys.platform");
     }
+
+    template<> template<>
+    void TestPythonCompatibleObject::test<3>()
+    {
+        set_test_name("verify sequence to Python");
+
+        LLSD cdata(LLSDArray(17)(3.14)
+                  ("This string\n"
+                   "has several\n"
+                   "lines."));
+
+        const char pydata[] =
+            "def verify(iterable):\n"
+            "    it = iter(iterable)\n"
+            "    assert it.next() == 17\n"
+            "    assert abs(it.next() - 3.14) < 0.01\n"
+            "    assert it.next() == '''\\\n"
+            "This string\n"
+            "has several\n"
+            "lines.'''\n"
+            "    try:\n"
+            "        it.next()\n"
+            "    except StopIteration:\n"
+            "        pass\n"
+            "    else:\n"
+            "        assert False, 'Too many data items'\n";
+
+        // Create a something.llsd file containing 'data' serialized to notation.
+        // Avoid final newline because NamedTempFile implicitly adds one.
+        NamedTempFile file(".llsd",
+                           (lambda::bind(LLSDSerialize::toNotation, cdata[0], lambda::_1),
+                            lambda::_1 << '\n',
+                            lambda::bind(LLSDSerialize::toNotation, cdata[1], lambda::_1),
+                            lambda::_1 << '\n',
+                            lambda::bind(LLSDSerialize::toNotation, cdata[2], lambda::_1)));
+
+        python("read C++ notation",
+               lambda::_1 <<
+               "from llbase import llsd\n"
+               "def parse_each(iterable):\n"
+               "    for item in iterable:\n"
+               "        yield llsd.parse(item)\n" <<
+               pydata <<
+               "verify(parse_each(open('" << file.getName() << "')))\n");
+    }
 }
-- 
GitLab