diff options
Diffstat (limited to 'indra/test/test.cpp')
-rw-r--r-- | indra/test/test.cpp | 1090 |
1 files changed, 545 insertions, 545 deletions
diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 6b88553cbb..cbd1077306 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file test.cpp * @author Phoenix * @date 2005-09-26 @@ -7,26 +7,26 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -/** +/** * * You can add tests by creating a new cpp file in this directory, and * rebuilding. There are at most 50 tests per testgroup without a @@ -47,10 +47,10 @@ #include "apr_getopt.h" // the CTYPE_WORKAROUND is needed for linux dev stations that don't -// have the broken libc6 packages needed by our out-of-date static +// have the broken libc6 packages needed by our out-of-date static // libs (such as libcrypto and libcurl). -- Leviathan 20060113 #ifdef CTYPE_WORKAROUND -# include "ctype_workaround.h" +# include "ctype_workaround.h" #endif #if LL_MSVC @@ -74,254 +74,254 @@ void wouldHaveCrashed(const std::string& message); namespace tut { - std::string sSourceDir; + std::string sSourceDir; - test_runner_singleton runner; + test_runner_singleton runner; } class LLReplayLog { public: - LLReplayLog() {} - virtual ~LLReplayLog() {} + LLReplayLog() {} + virtual ~LLReplayLog() {} - virtual void reset() {} - virtual void replay(std::ostream&) {} + virtual void reset() {} + virtual void replay(std::ostream&) {} }; class RecordToTempFile : public LLError::Recorder, public boost::noncopyable { public: - RecordToTempFile() - : LLError::Recorder(), - boost::noncopyable(), - mTempFile("log", ""), - mFile(mTempFile.getName().c_str()) - { - } - - virtual ~RecordToTempFile() - { - mFile.close(); - } - - virtual void recordMessage(LLError::ELevel level, const std::string& message) - { + RecordToTempFile() + : LLError::Recorder(), + boost::noncopyable(), + mTempFile("log", ""), + mFile(mTempFile.getName().c_str()) + { + } + + virtual ~RecordToTempFile() + { + mFile.close(); + } + + virtual void recordMessage(LLError::ELevel level, const std::string& message) + { LL_PROFILE_ZONE_SCOPED - mFile << message << std::endl; - } - - void reset() - { - mFile.close(); - mFile.open(mTempFile.getName().c_str()); - } - - void replay(std::ostream& out) - { - mFile.close(); - std::ifstream inf(mTempFile.getName().c_str()); - std::string line; - while (std::getline(inf, line)) - { - out << line << std::endl; - } - } + mFile << message << std::endl; + } + + void reset() + { + mFile.close(); + mFile.open(mTempFile.getName().c_str()); + } + + void replay(std::ostream& out) + { + mFile.close(); + std::ifstream inf(mTempFile.getName().c_str()); + std::string line; + while (std::getline(inf, line)) + { + out << line << std::endl; + } + } private: - NamedTempFile mTempFile; - llofstream mFile; + NamedTempFile mTempFile; + llofstream mFile; }; class LLReplayLogReal: public LLReplayLog, public boost::noncopyable { public: - LLReplayLogReal(LLError::ELevel level) - : LLReplayLog(), - boost::noncopyable(), - mOldSettings(LLError::saveAndResetSettings()), - mRecorder(new RecordToTempFile()) - { - LLError::setFatalFunction(wouldHaveCrashed); - LLError::setDefaultLevel(level); - LLError::addRecorder(mRecorder); - } - - virtual ~LLReplayLogReal() - { - LLError::removeRecorder(mRecorder); - LLError::restoreSettings(mOldSettings); - } - - virtual void reset() - { - std::dynamic_pointer_cast<RecordToTempFile>(mRecorder)->reset(); - } - - virtual void replay(std::ostream& out) - { - std::dynamic_pointer_cast<RecordToTempFile>(mRecorder)->replay(out); - } + LLReplayLogReal(LLError::ELevel level) + : LLReplayLog(), + boost::noncopyable(), + mOldSettings(LLError::saveAndResetSettings()), + mRecorder(new RecordToTempFile()) + { + LLError::setFatalFunction(wouldHaveCrashed); + LLError::setDefaultLevel(level); + LLError::addRecorder(mRecorder); + } + + virtual ~LLReplayLogReal() + { + LLError::removeRecorder(mRecorder); + LLError::restoreSettings(mOldSettings); + } + + virtual void reset() + { + std::dynamic_pointer_cast<RecordToTempFile>(mRecorder)->reset(); + } + + virtual void replay(std::ostream& out) + { + std::dynamic_pointer_cast<RecordToTempFile>(mRecorder)->replay(out); + } private: - LLError::SettingsStoragePtr mOldSettings; - LLError::RecorderPtr mRecorder; + LLError::SettingsStoragePtr mOldSettings; + LLError::RecorderPtr mRecorder; }; class LLTestCallback : public chained_callback { - typedef chained_callback super; + typedef chained_callback super; public: - LLTestCallback(bool verbose_mode, std::ostream *stream, - std::shared_ptr<LLReplayLog> replayer) : - mVerboseMode(verbose_mode), - mTotalTests(0), - mPassedTests(0), - mFailedTests(0), - mSkippedTests(0), - // By default, capture a shared_ptr to std::cout, with a no-op "deleter" - // so that destroying the shared_ptr makes no attempt to delete std::cout. - mStream(std::shared_ptr<std::ostream>(&std::cout, [](std::ostream*){})), - mReplayer(replayer) - { - if (stream) - { - // We want a boost::iostreams::tee_device that will stream to two - // std::ostreams. - typedef boost::iostreams::tee_device<std::ostream, std::ostream> TeeDevice; - // More than that, though, we want an actual stream using that - // device. - typedef boost::iostreams::stream<TeeDevice> TeeStream; - // Allocate and assign in two separate steps, per Herb Sutter. - // (Until we turn on C++11 support, have to wrap *stream with - // boost::ref() due to lack of perfect forwarding.) - std::shared_ptr<std::ostream> pstream(new TeeStream(std::cout, boost::ref(*stream))); - mStream = pstream; - } - } - - ~LLTestCallback() - { - } - - virtual void run_started() - { - //std::cout << "run_started" << std::endl; - LL_INFOS("TestRunner")<<"Test Started"<< LL_ENDL; - super::run_started(); - } - - virtual void group_started(const std::string& name) { - LL_INFOS("TestRunner")<<"Unit test group_started name=" << name << LL_ENDL; - *mStream << "Unit test group_started name=" << name << std::endl; - super::group_started(name); - } - - virtual void group_completed(const std::string& name) { - LL_INFOS("TestRunner")<<"Unit test group_completed name=" << name << LL_ENDL; - *mStream << "Unit test group_completed name=" << name << std::endl; - super::group_completed(name); - } - - virtual void test_completed(const tut::test_result& tr) - { - ++mTotalTests; - - // If this test failed, dump requested log messages BEFORE stating the - // test result. - if (tr.result != tut::test_result::ok && tr.result != tut::test_result::skip) - { - mReplayer->replay(*mStream); - } - // Either way, clear stored messages in preparation for next test. - mReplayer->reset(); - - std::ostringstream out; - out << "[" << tr.group << ", " << tr.test; - if (! tr.name.empty()) - out << ": " << tr.name; - out << "] "; - switch(tr.result) - { - case tut::test_result::ok: - ++mPassedTests; - out << "ok"; - break; - case tut::test_result::fail: - ++mFailedTests; - out << "fail"; - break; - case tut::test_result::ex: - ++mFailedTests; - out << "exception: " << LLError::Log::demangle(tr.exception_typeid.c_str()); - break; - case tut::test_result::warn: - ++mFailedTests; - out << "test destructor throw"; - break; - case tut::test_result::term: - ++mFailedTests; - out << "abnormal termination"; - break; - case tut::test_result::skip: - ++mSkippedTests; - out << "skipped known failure"; - break; - default: - ++mFailedTests; - out << "unknown (tr.result == " << tr.result << ")"; - } - if(mVerboseMode || (tr.result != tut::test_result::ok)) - { - *mStream << out.str(); - if(!tr.message.empty()) - { - *mStream << ": '" << tr.message << "'"; - LL_WARNS("TestRunner") << "not ok : "<<tr.message << LL_ENDL; - } - *mStream << std::endl; - } - LL_INFOS("TestRunner")<<out.str()<<LL_ENDL; - super::test_completed(tr); - } - - virtual int getFailedTests() const { return mFailedTests; } - - virtual void run_completed() - { - *mStream << "\tTotal Tests:\t" << mTotalTests << std::endl; - *mStream << "\tPassed Tests:\t" << mPassedTests; - if (mPassedTests == mTotalTests) - { - *mStream << "\tYAY!! \\o/"; - } - *mStream << std::endl; - - if (mSkippedTests > 0) - { - *mStream << "\tSkipped known failures:\t" << mSkippedTests - << std::endl; - } - - if(mFailedTests > 0) - { - *mStream << "*********************************" << std::endl; - *mStream << "Failed Tests:\t" << mFailedTests << std::endl; - *mStream << "Please report or fix the problem." << std::endl; - *mStream << "*********************************" << std::endl; - } - super::run_completed(); - } + LLTestCallback(bool verbose_mode, std::ostream *stream, + std::shared_ptr<LLReplayLog> replayer) : + mVerboseMode(verbose_mode), + mTotalTests(0), + mPassedTests(0), + mFailedTests(0), + mSkippedTests(0), + // By default, capture a shared_ptr to std::cout, with a no-op "deleter" + // so that destroying the shared_ptr makes no attempt to delete std::cout. + mStream(std::shared_ptr<std::ostream>(&std::cout, [](std::ostream*){})), + mReplayer(replayer) + { + if (stream) + { + // We want a boost::iostreams::tee_device that will stream to two + // std::ostreams. + typedef boost::iostreams::tee_device<std::ostream, std::ostream> TeeDevice; + // More than that, though, we want an actual stream using that + // device. + typedef boost::iostreams::stream<TeeDevice> TeeStream; + // Allocate and assign in two separate steps, per Herb Sutter. + // (Until we turn on C++11 support, have to wrap *stream with + // boost::ref() due to lack of perfect forwarding.) + std::shared_ptr<std::ostream> pstream(new TeeStream(std::cout, boost::ref(*stream))); + mStream = pstream; + } + } + + ~LLTestCallback() + { + } + + virtual void run_started() + { + //std::cout << "run_started" << std::endl; + LL_INFOS("TestRunner")<<"Test Started"<< LL_ENDL; + super::run_started(); + } + + virtual void group_started(const std::string& name) { + LL_INFOS("TestRunner")<<"Unit test group_started name=" << name << LL_ENDL; + *mStream << "Unit test group_started name=" << name << std::endl; + super::group_started(name); + } + + virtual void group_completed(const std::string& name) { + LL_INFOS("TestRunner")<<"Unit test group_completed name=" << name << LL_ENDL; + *mStream << "Unit test group_completed name=" << name << std::endl; + super::group_completed(name); + } + + virtual void test_completed(const tut::test_result& tr) + { + ++mTotalTests; + + // If this test failed, dump requested log messages BEFORE stating the + // test result. + if (tr.result != tut::test_result::ok && tr.result != tut::test_result::skip) + { + mReplayer->replay(*mStream); + } + // Either way, clear stored messages in preparation for next test. + mReplayer->reset(); + + std::ostringstream out; + out << "[" << tr.group << ", " << tr.test; + if (! tr.name.empty()) + out << ": " << tr.name; + out << "] "; + switch(tr.result) + { + case tut::test_result::ok: + ++mPassedTests; + out << "ok"; + break; + case tut::test_result::fail: + ++mFailedTests; + out << "fail"; + break; + case tut::test_result::ex: + ++mFailedTests; + out << "exception: " << LLError::Log::demangle(tr.exception_typeid.c_str()); + break; + case tut::test_result::warn: + ++mFailedTests; + out << "test destructor throw"; + break; + case tut::test_result::term: + ++mFailedTests; + out << "abnormal termination"; + break; + case tut::test_result::skip: + ++mSkippedTests; + out << "skipped known failure"; + break; + default: + ++mFailedTests; + out << "unknown (tr.result == " << tr.result << ")"; + } + if(mVerboseMode || (tr.result != tut::test_result::ok)) + { + *mStream << out.str(); + if(!tr.message.empty()) + { + *mStream << ": '" << tr.message << "'"; + LL_WARNS("TestRunner") << "not ok : "<<tr.message << LL_ENDL; + } + *mStream << std::endl; + } + LL_INFOS("TestRunner")<<out.str()<<LL_ENDL; + super::test_completed(tr); + } + + virtual int getFailedTests() const { return mFailedTests; } + + virtual void run_completed() + { + *mStream << "\tTotal Tests:\t" << mTotalTests << std::endl; + *mStream << "\tPassed Tests:\t" << mPassedTests; + if (mPassedTests == mTotalTests) + { + *mStream << "\tYAY!! \\o/"; + } + *mStream << std::endl; + + if (mSkippedTests > 0) + { + *mStream << "\tSkipped known failures:\t" << mSkippedTests + << std::endl; + } + + if(mFailedTests > 0) + { + *mStream << "*********************************" << std::endl; + *mStream << "Failed Tests:\t" << mFailedTests << std::endl; + *mStream << "Please report or fix the problem." << std::endl; + *mStream << "*********************************" << std::endl; + } + super::run_completed(); + } protected: - bool mVerboseMode; - int mTotalTests; - int mPassedTests; - int mFailedTests; - int mSkippedTests; - std::shared_ptr<std::ostream> mStream; - std::shared_ptr<LLReplayLog> mReplayer; + bool mVerboseMode; + int mTotalTests; + int mPassedTests; + int mFailedTests; + int mSkippedTests; + std::shared_ptr<std::ostream> mStream; + std::shared_ptr<LLReplayLog> mReplayer; }; // TeamCity specific class which emits service messages @@ -330,352 +330,352 @@ protected: class LLTCTestCallback : public LLTestCallback { public: - LLTCTestCallback(bool verbose_mode, std::ostream *stream, - std::shared_ptr<LLReplayLog> replayer) : - LLTestCallback(verbose_mode, stream, replayer) - { - } - - ~LLTCTestCallback() - { - } - - virtual void group_started(const std::string& name) { - LLTestCallback::group_started(name); - std::cout << "\n##teamcity[testSuiteStarted name='" << escape(name) << "']" << std::endl; - } - - virtual void group_completed(const std::string& name) { - LLTestCallback::group_completed(name); - std::cout << "##teamcity[testSuiteFinished name='" << escape(name) << "']" << std::endl; - } - - virtual void test_completed(const tut::test_result& tr) - { - std::string testname(STRINGIZE(tr.group << "." << tr.test)); - if (! tr.name.empty()) - { - testname.append(":"); - testname.append(tr.name); - } - testname = escape(testname); - - // Sadly, tut::callback doesn't give us control at test start; have to - // backfill start message into TC output. - std::cout << "##teamcity[testStarted name='" << testname << "']" << std::endl; - - // now forward call to base class so any output produced there is in - // the right TC context - LLTestCallback::test_completed(tr); - - switch(tr.result) - { - case tut::test_result::ok: - break; - - case tut::test_result::fail: - case tut::test_result::ex: - case tut::test_result::warn: - case tut::test_result::term: - std::cout << "##teamcity[testFailed name='" << testname - << "' message='" << escape(tr.message) << "']" << std::endl; - break; - - case tut::test_result::skip: - std::cout << "##teamcity[testIgnored name='" << testname << "']" << std::endl; - break; - - default: - break; - } - - std::cout << "##teamcity[testFinished name='" << testname << "']" << std::endl; - } - - static std::string escape(const std::string& str) - { - // Per http://confluence.jetbrains.net/display/TCD65/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ServiceMessages - std::string result; - for (char c : str) - { - switch (c) - { - case '\'': - result.append("|'"); - break; - case '\n': - result.append("|n"); - break; - case '\r': - result.append("|r"); - break; + LLTCTestCallback(bool verbose_mode, std::ostream *stream, + std::shared_ptr<LLReplayLog> replayer) : + LLTestCallback(verbose_mode, stream, replayer) + { + } + + ~LLTCTestCallback() + { + } + + virtual void group_started(const std::string& name) { + LLTestCallback::group_started(name); + std::cout << "\n##teamcity[testSuiteStarted name='" << escape(name) << "']" << std::endl; + } + + virtual void group_completed(const std::string& name) { + LLTestCallback::group_completed(name); + std::cout << "##teamcity[testSuiteFinished name='" << escape(name) << "']" << std::endl; + } + + virtual void test_completed(const tut::test_result& tr) + { + std::string testname(STRINGIZE(tr.group << "." << tr.test)); + if (! tr.name.empty()) + { + testname.append(":"); + testname.append(tr.name); + } + testname = escape(testname); + + // Sadly, tut::callback doesn't give us control at test start; have to + // backfill start message into TC output. + std::cout << "##teamcity[testStarted name='" << testname << "']" << std::endl; + + // now forward call to base class so any output produced there is in + // the right TC context + LLTestCallback::test_completed(tr); + + switch(tr.result) + { + case tut::test_result::ok: + break; + + case tut::test_result::fail: + case tut::test_result::ex: + case tut::test_result::warn: + case tut::test_result::term: + std::cout << "##teamcity[testFailed name='" << testname + << "' message='" << escape(tr.message) << "']" << std::endl; + break; + + case tut::test_result::skip: + std::cout << "##teamcity[testIgnored name='" << testname << "']" << std::endl; + break; + + default: + break; + } + + std::cout << "##teamcity[testFinished name='" << testname << "']" << std::endl; + } + + static std::string escape(const std::string& str) + { + // Per http://confluence.jetbrains.net/display/TCD65/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ServiceMessages + std::string result; + for (char c : str) + { + switch (c) + { + case '\'': + result.append("|'"); + break; + case '\n': + result.append("|n"); + break; + case '\r': + result.append("|r"); + break; /*==========================================================================*| - // These are not possible 'char' values from a std::string. - case '\u0085': // next line - result.append("|x"); - break; - case '\u2028': // line separator - result.append("|l"); - break; - case '\u2029': // paragraph separator - result.append("|p"); - break; + // These are not possible 'char' values from a std::string. + case '\u0085': // next line + result.append("|x"); + break; + case '\u2028': // line separator + result.append("|l"); + break; + case '\u2029': // paragraph separator + result.append("|p"); + break; |*==========================================================================*/ - case '|': - result.append("||"); - break; - case '[': - result.append("|["); - break; - case ']': - result.append("|]"); - break; - default: - result.push_back(c); - break; - } - } - return result; - } + case '|': + result.append("||"); + break; + case '[': + result.append("|["); + break; + case ']': + result.append("|]"); + break; + default: + result.push_back(c); + break; + } + } + return result; + } }; static const apr_getopt_option_t TEST_CL_OPTIONS[] = { - {"help", 'h', 0, "Print the help message."}, - {"list", 'l', 0, "List available test groups."}, - {"verbose", 'v', 0, "Verbose output."}, - {"group", 'g', 1, "Run test group specified by option argument."}, - {"output", 'o', 1, "Write output to the named file."}, - {"sourcedir", 's', 1, "Project source file directory from CMake."}, - {"touch", 't', 1, "Touch the given file if all tests succeed"}, - {"wait", 'w', 0, "Wait for input before exit."}, - {"debug", 'd', 0, "Emit full debug logs."}, - {"suitename", 'x', 1, "Run tests using this suitename"}, - {0, 0, 0, 0} + {"help", 'h', 0, "Print the help message."}, + {"list", 'l', 0, "List available test groups."}, + {"verbose", 'v', 0, "Verbose output."}, + {"group", 'g', 1, "Run test group specified by option argument."}, + {"output", 'o', 1, "Write output to the named file."}, + {"sourcedir", 's', 1, "Project source file directory from CMake."}, + {"touch", 't', 1, "Touch the given file if all tests succeed"}, + {"wait", 'w', 0, "Wait for input before exit."}, + {"debug", 'd', 0, "Emit full debug logs."}, + {"suitename", 'x', 1, "Run tests using this suitename"}, + {0, 0, 0, 0} }; void stream_usage(std::ostream& s, const char* app) { - s << "Usage: " << app << " [OPTIONS]" << std::endl - << std::endl; - - s << "This application runs the unit tests." << std::endl << std::endl; - - s << "Options: " << std::endl; - const apr_getopt_option_t* option = &TEST_CL_OPTIONS[0]; - while(option->name) - { - s << " "; - s << " -" << (char)option->optch << ", --" << option->name - << std::endl; - s << "\t" << option->description << std::endl << std::endl; - ++option; - } - - s << app << " is also sensitive to environment variables:\n" - << "LOGTEST=level : for all tests, emit log messages at level 'level'\n" - << "LOGFAIL=level : only for failed tests, emit log messages at level 'level'\n" - << "where 'level' is one of ALL, DEBUG, INFO, WARN, ERROR, NONE.\n" - << "--debug is like LOGTEST=DEBUG, but --debug overrides LOGTEST,\n" - << "while LOGTEST overrides LOGFAIL.\n\n"; - - s << "Examples:" << std::endl; - s << " " << app << " --verbose" << std::endl; - s << "\tRun all the tests and report all results." << std::endl; - s << " " << app << " --list" << std::endl; - s << "\tList all available test groups." << std::endl; - s << " " << app << " --group=uuid" << std::endl; - s << "\tRun the test group 'uuid'." << std::endl; - - s << "\n\n" - << "In any event, logs are recorded in the build directory by appending\n" - << "the suffix '.log' to the full path name of this application.\n" - << "If no level is specified as described above, these log files are at\n" - << "DEBUG level.\n" - ; + s << "Usage: " << app << " [OPTIONS]" << std::endl + << std::endl; + + s << "This application runs the unit tests." << std::endl << std::endl; + + s << "Options: " << std::endl; + const apr_getopt_option_t* option = &TEST_CL_OPTIONS[0]; + while(option->name) + { + s << " "; + s << " -" << (char)option->optch << ", --" << option->name + << std::endl; + s << "\t" << option->description << std::endl << std::endl; + ++option; + } + + s << app << " is also sensitive to environment variables:\n" + << "LOGTEST=level : for all tests, emit log messages at level 'level'\n" + << "LOGFAIL=level : only for failed tests, emit log messages at level 'level'\n" + << "where 'level' is one of ALL, DEBUG, INFO, WARN, ERROR, NONE.\n" + << "--debug is like LOGTEST=DEBUG, but --debug overrides LOGTEST,\n" + << "while LOGTEST overrides LOGFAIL.\n\n"; + + s << "Examples:" << std::endl; + s << " " << app << " --verbose" << std::endl; + s << "\tRun all the tests and report all results." << std::endl; + s << " " << app << " --list" << std::endl; + s << "\tList all available test groups." << std::endl; + s << " " << app << " --group=uuid" << std::endl; + s << "\tRun the test group 'uuid'." << std::endl; + + s << "\n\n" + << "In any event, logs are recorded in the build directory by appending\n" + << "the suffix '.log' to the full path name of this application.\n" + << "If no level is specified as described above, these log files are at\n" + << "DEBUG level.\n" + ; } void stream_groups(std::ostream& s, const char* app) { - s << "Registered test groups:" << std::endl; - tut::groupnames gl = tut::runner.get().list_groups(); - tut::groupnames::const_iterator it = gl.begin(); - tut::groupnames::const_iterator end = gl.end(); - for(; it != end; ++it) - { - s << " " << *(it) << std::endl; - } + s << "Registered test groups:" << std::endl; + tut::groupnames gl = tut::runner.get().list_groups(); + tut::groupnames::const_iterator it = gl.begin(); + tut::groupnames::const_iterator end = gl.end(); + for(; it != end; ++it) + { + s << " " << *(it) << std::endl; + } } void wouldHaveCrashed(const std::string& message) { - tut::fail("llerrs message: " + message); + tut::fail("llerrs message: " + message); } static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; int main(int argc, char **argv) { - ll_init_apr(); - apr_getopt_t* os = NULL; - if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv)) - { - std::cerr << "apr_getopt_init() failed" << std::endl; - return 1; - } - - // values used for controlling application - bool verbose_mode = false; - bool wait_at_exit = false; - std::string test_group; - std::string suite_name; - - // LOGTEST overrides default, but can be overridden by --debug. - const char* LOGTEST = getenv("LOGTEST"); - - // values used for options parsing - apr_status_t apr_err; - const char* opt_arg = NULL; - int opt_id = 0; - std::unique_ptr<llofstream> output; - const char *touch = NULL; - - while(true) - { - apr_err = apr_getopt_long(os, TEST_CL_OPTIONS, &opt_id, &opt_arg); - if(APR_STATUS_IS_EOF(apr_err)) break; - if(apr_err) - { - char buf[255]; /* Flawfinder: ignore */ - std::cerr << "Error parsing options: " - << apr_strerror(apr_err, buf, 255) << std::endl; - return 1; - } - switch (opt_id) - { - case 'g': - test_group.assign(opt_arg); - break; - case 'h': - stream_usage(std::cout, argv[0]); - return 0; - break; - case 'l': - stream_groups(std::cout, argv[0]); - return 0; - case 'v': - verbose_mode = true; - break; - case 'o': - output.reset(new llofstream); - output->open(opt_arg); - break; - case 's': // --sourcedir - tut::sSourceDir = opt_arg; - // For convenience, so you can use tut::sSourceDir + "myfile" - tut::sSourceDir += '/'; - break; - case 't': - touch = opt_arg; - break; - case 'w': - wait_at_exit = true; - break; - case 'd': - LOGTEST = "DEBUG"; - break; - case 'x': - suite_name.assign(opt_arg); - break; - default: - stream_usage(std::cerr, argv[0]); - return 1; - break; - } - } - - // set up logging - const char* LOGFAIL = getenv("LOGFAIL"); - std::shared_ptr<LLReplayLog> replayer{std::make_shared<LLReplayLog>()}; - - // Testing environment variables for both 'set' and 'not empty' allows a - // user to suppress a pre-existing environment variable by forcing empty. - if (LOGTEST && *LOGTEST) - { - LLError::initForApplication(".", ".", true /* log to stderr */); - LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST)); - } - else - { - LLError::initForApplication(".", ".", false /* do not log to stderr */); - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - if (LOGFAIL && *LOGFAIL) - { - LLError::ELevel level = LLError::decodeLevel(LOGFAIL); - replayer.reset(new LLReplayLogReal(level)); - } - } - LLError::setFatalFunction(wouldHaveCrashed); - std::string test_app_name(argv[0]); - std::string test_log = test_app_name + ".log"; - LLFile::remove(test_log); - LLError::logToFile(test_log); + ll_init_apr(); + apr_getopt_t* os = NULL; + if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv)) + { + std::cerr << "apr_getopt_init() failed" << std::endl; + return 1; + } + + // values used for controlling application + bool verbose_mode = false; + bool wait_at_exit = false; + std::string test_group; + std::string suite_name; + + // LOGTEST overrides default, but can be overridden by --debug. + const char* LOGTEST = getenv("LOGTEST"); + + // values used for options parsing + apr_status_t apr_err; + const char* opt_arg = NULL; + int opt_id = 0; + std::unique_ptr<llofstream> output; + const char *touch = NULL; + + while(true) + { + apr_err = apr_getopt_long(os, TEST_CL_OPTIONS, &opt_id, &opt_arg); + if(APR_STATUS_IS_EOF(apr_err)) break; + if(apr_err) + { + char buf[255]; /* Flawfinder: ignore */ + std::cerr << "Error parsing options: " + << apr_strerror(apr_err, buf, 255) << std::endl; + return 1; + } + switch (opt_id) + { + case 'g': + test_group.assign(opt_arg); + break; + case 'h': + stream_usage(std::cout, argv[0]); + return 0; + break; + case 'l': + stream_groups(std::cout, argv[0]); + return 0; + case 'v': + verbose_mode = true; + break; + case 'o': + output.reset(new llofstream); + output->open(opt_arg); + break; + case 's': // --sourcedir + tut::sSourceDir = opt_arg; + // For convenience, so you can use tut::sSourceDir + "myfile" + tut::sSourceDir += '/'; + break; + case 't': + touch = opt_arg; + break; + case 'w': + wait_at_exit = true; + break; + case 'd': + LOGTEST = "DEBUG"; + break; + case 'x': + suite_name.assign(opt_arg); + break; + default: + stream_usage(std::cerr, argv[0]); + return 1; + break; + } + } + + // set up logging + const char* LOGFAIL = getenv("LOGFAIL"); + std::shared_ptr<LLReplayLog> replayer{std::make_shared<LLReplayLog>()}; + + // Testing environment variables for both 'set' and 'not empty' allows a + // user to suppress a pre-existing environment variable by forcing empty. + if (LOGTEST && *LOGTEST) + { + LLError::initForApplication(".", ".", true /* log to stderr */); + LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST)); + } + else + { + LLError::initForApplication(".", ".", false /* do not log to stderr */); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + if (LOGFAIL && *LOGFAIL) + { + LLError::ELevel level = LLError::decodeLevel(LOGFAIL); + replayer.reset(new LLReplayLogReal(level)); + } + } + LLError::setFatalFunction(wouldHaveCrashed); + std::string test_app_name(argv[0]); + std::string test_log = test_app_name + ".log"; + LLFile::remove(test_log); + LLError::logToFile(test_log); #ifdef CTYPE_WORKAROUND - ctype_workaround(); + ctype_workaround(); #endif - if (!sMasterThreadRecorder) - { - sMasterThreadRecorder = new LLTrace::ThreadRecorder(); - LLTrace::set_master_thread_recorder(sMasterThreadRecorder); - } - - // run the tests - - LLTestCallback* mycallback; - if (getenv("TEAMCITY_PROJECT_NAME")) - { - mycallback = new LLTCTestCallback(verbose_mode, output.get(), replayer); - } - else - { - mycallback = new LLTestCallback(verbose_mode, output.get(), replayer); - } - - // a chained_callback subclass must be linked with previous - mycallback->link(); - - if(test_group.empty()) - { - tut::runner.get().run_tests(); - } - else - { - tut::runner.get().run_tests(test_group); - } - - bool success = (mycallback->getFailedTests() == 0); - - if (wait_at_exit) - { - std::cerr << "Press return to exit..." << std::endl; - std::cin.get(); - } - - if (touch && success) - { - llofstream s; - s.open(touch); - s << "ok" << std::endl; - s.close(); - } - - ll_cleanup_apr(); - - int retval = (success ? 0 : 1); - return retval; - - //delete mycallback; + if (!sMasterThreadRecorder) + { + sMasterThreadRecorder = new LLTrace::ThreadRecorder(); + LLTrace::set_master_thread_recorder(sMasterThreadRecorder); + } + + // run the tests + + LLTestCallback* mycallback; + if (getenv("TEAMCITY_PROJECT_NAME")) + { + mycallback = new LLTCTestCallback(verbose_mode, output.get(), replayer); + } + else + { + mycallback = new LLTestCallback(verbose_mode, output.get(), replayer); + } + + // a chained_callback subclass must be linked with previous + mycallback->link(); + + if(test_group.empty()) + { + tut::runner.get().run_tests(); + } + else + { + tut::runner.get().run_tests(test_group); + } + + bool success = (mycallback->getFailedTests() == 0); + + if (wait_at_exit) + { + std::cerr << "Press return to exit..." << std::endl; + std::cin.get(); + } + + if (touch && success) + { + llofstream s; + s.open(touch); + s << "ok" << std::endl; + s.close(); + } + + ll_cleanup_apr(); + + int retval = (success ? 0 : 1); + return retval; + + //delete mycallback; } |