diff options
-rw-r--r-- | indra/llcommon/tests/llsdserialize_test.cpp | 102 |
1 files changed, 75 insertions, 27 deletions
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 41d2fcc696..8b59e99b24 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -43,6 +43,7 @@ typedef U32 uint32_t; #include <fcntl.h> #include <sys/stat.h> +#include <sstream> /*==========================================================================*| // Whoops, seems Linden's Boost package and the viewer are built with @@ -65,6 +66,14 @@ typedef U32 uint32_t; |*==========================================================================*/ #include "boost/range.hpp" #include "boost/foreach.hpp" +#include "boost/function.hpp" +#include "boost/lambda/lambda.hpp" +namespace lambda = boost::lambda; +/*==========================================================================*| +// Aaaarrgh, Linden's Boost package doesn't even include Boost.Iostreams! +#include "boost/iostreams/stream.hpp" +#include "boost/iostreams/device/file_descriptor.hpp" +|*==========================================================================*/ #include "../llsd.h" #include "../llsdserialize.h" @@ -115,14 +124,38 @@ std::string temp_directory_path() #define _S_IREAD S_IRUSR #endif // ! LL_WINDOWS -// Create a Python script file with specified content "somewhere in the +// Create a text file with specified content "somewhere in the // filesystem," cleaning up when it goes out of scope. -class NamedTempScript +class NamedTempFile { public: - NamedTempScript(const std::string& content): + // Function that accepts an ostream ref and (presumably) writes stuff to + // it, e.g.: + // (lambda::_1 << "the value is " << 17 << '\n') + typedef boost::function<void(std::ostream&)> Streamer; + + NamedTempFile(const std::string& ext, const std::string& content): + mPath(temp_directory_path()) + { + createFile(ext, lambda::_1 << content); + } + + NamedTempFile(const std::string& ext, const Streamer& func): mPath(temp_directory_path()) { + createFile(ext, func); + } + + ~NamedTempFile() + { + _remove(mPath.c_str()); + } + + std::string getName() const { return mPath; } + +private: + void createFile(const std::string& ext, const Streamer& func) + { // Make sure mPath ends with a directory separator, if it doesn't already. if (mPath.empty() || ! (mPath[mPath.length() - 1] == '\\' || mPath[mPath.length() - 1] == '/')) @@ -138,11 +171,11 @@ public: // but I think it's neater that way. std::string testname(STRINGIZE(mPath << std::setw(8) << std::setfill('0') << i - << ".py")); + << ext)); // The key to this whole loop is the _O_CREAT | _O_EXCL bitmask, - // which requests an error if the file already exists. A proper - // implementation will check atomically, ensuring that racing - // processes will end up with two different filenames. + // which requests error EEXIST if the file already exists. A + // proper implementation will check atomically, ensuring that + // racing processes will end up with two different filenames. fd = _open(testname.c_str(), _O_WRONLY | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE); @@ -151,29 +184,40 @@ public: mPath = testname; // remember its actual name break; } - // it's a problem if the open() failed for any other reason but - // the existence of a file by the same name - assert(errno == EEXIST); + // This loop is specifically coded to handle EEXIST. Any other + // error is a problem. + llassert_always(errno == EEXIST); // loop back to try another filename } - // File is open, its name is in mPath: write it and close it. - // Truthfully, we'd just as soon ignore the return value from - // _write(), but Linux gcc generates fatal warnings if we do. - bool ok(true); - ok = ok && (content.length() == _write(fd, content.c_str(), content.length())); - ok = ok && (1 == _write(fd, "\n", 1)); - assert(ok); - _close(fd); + // fd is open, its name is in mPath: write it and close it. + +/*==========================================================================*| + // Define an ostream on the open fd. Tell it to close fd on destruction. + boost::iostreams::stream<boost::iostreams::file_descriptor_sink> + out(fd, boost::iostreams::close_handle); +|*==========================================================================*/ + std::ostringstream out; + // Stream stuff to it. + func(out); + // toss in a final newline for good measure + out << '\n'; + + std::string data(out.str()); + int written(_write(fd, data.c_str(), data.length())); + int closed(_close(fd)); + llassert_always(written == data.length() && closed == 0); } - ~NamedTempScript() + void peep() { - _remove(mPath.c_str()); + std::cout << "File '" << mPath << "' contains:\n"; + std::ifstream reader(mPath.c_str()); + std::string line; + while (std::getline(reader, line)) + std::cout << line << '\n'; + std::cout << "---\n"; } - std::string getName() const { return mPath; } - -private: std::string mPath; }; @@ -1628,7 +1672,7 @@ namespace tut const char* PYTHON(getenv("PYTHON")); ensure("Set $PYTHON to the Python interpreter", PYTHON); - NamedTempScript scriptfile(script); + NamedTempFile scriptfile(".py", script); #if LL_WINDOWS std::string q("\""); @@ -1690,14 +1734,18 @@ namespace tut template<> template<> void TestPythonCompatibleObject::test<1>() { - python("hello", "print 'Hello, world!'"); + set_test_name("verify python()"); + python("hello", + "import sys\n" + "sys.exit(0)"); } template<> template<> void TestPythonCompatibleObject::test<2>() { + set_test_name("verify NamedTempFile"); python("platform", -"import sys\n" -"print 'Running on', sys.platform"); + "import sys\n" + "print 'Running on', sys.platform"); } } |