diff options
Diffstat (limited to 'indra/test/test.cpp')
-rw-r--r-- | indra/test/test.cpp | 408 |
1 files changed, 285 insertions, 123 deletions
diff --git a/indra/test/test.cpp b/indra/test/test.cpp index f573d53ba8..ffdb0cb976 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -4,30 +4,25 @@ * @date 2005-09-26 * @brief Entry point for the test app. * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,8 +38,8 @@ #include "llerrorcontrol.h" #include "lltut.h" -#include <apr-1/apr_pools.h> -#include <apr-1/apr_getopt.h> +#include "apr_pools.h" +#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 @@ -53,68 +48,82 @@ # include "ctype_workaround.h" #endif +#ifndef LL_WINDOWS +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#endif namespace tut { + std::string sSourceDir; + test_runner_singleton runner; } class LLTestCallback : public tut::callback { public: - LLTestCallback(bool verbose_mode) : - mVerboseMode(verbose_mode), - mTotalTests(0), - mPassedTests(0), - mFailedTests(0), - mSkippedTests(0), - mSkipedFailTests(0) + LLTestCallback(bool verbose_mode, std::ostream *stream) : + mVerboseMode(verbose_mode), + mTotalTests(0), + mPassedTests(0), + mFailedTests(0), + mSkippedTests(0), + mStream(stream) { } - void run_started() + ~LLTestCallback() + { + } + + virtual void run_started() { //std::cout << "run_started" << std::endl; } - void test_completed(const tut::test_result& tr) + virtual void group_started(const std::string& name) { + std::cout << "Unit test group_started name=" << name << std::endl; + } + + virtual void group_completed(const std::string& name) { + std::cout << "Unit test group_completed name=" << name << std::endl; + } + + virtual void test_completed(const tut::test_result& tr) { ++mTotalTests; std::ostringstream out; out << "[" << tr.group << ", " << tr.test << "] "; 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"; - 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"; - break; - case tut::test_result::skip_fail: - ++mSkipedFailTests; - out << "skipped known failure"; - break; - default: - ++mFailedTests; - out << "unknown"; + 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"; + 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"; } if(mVerboseMode || (tr.result != tut::test_result::ok)) { @@ -122,34 +131,48 @@ public: { out << ": '" << tr.message << "'"; } + if (mStream) + { + *mStream << out.str() << std::endl; + } + std::cout << out.str() << std::endl; } } - void run_completed() + virtual void run_completed() { - std::cout << std::endl; - std::cout << "Total Tests: " << mTotalTests << std::endl; - std::cout << "Passed Tests: " << mPassedTests << std::endl; - - if (mSkippedTests > 0) + if (mStream) + { + run_completed_(*mStream); + } + run_completed_(std::cout); + } + + virtual int getFailedTests() const { return mFailedTests; } + + virtual void run_completed_(std::ostream &stream) + { + stream << "\tTotal Tests:\t" << mTotalTests << std::endl; + stream << "\tPassed Tests:\t" << mPassedTests; + if (mPassedTests == mTotalTests) { - std::cout << "Skipped Tests: " << mSkippedTests << std::endl; + stream << "\tYAY!! \\o/"; } + stream << std::endl; - if (mSkipedFailTests > 0) + if (mSkippedTests > 0) { - std::cout << "Skipped known failures: " << mSkipedFailTests - << std::endl; + stream << "\tSkipped known failures:\t" << mSkippedTests + << std::endl; } if(mFailedTests > 0) { - std::cout << "*********************************" << std::endl; - std::cout << "Failed Tests: " << mFailedTests << std::endl; - std::cout << "Please report or fix the problem." << std::endl; - std::cout << "*********************************" << std::endl; - exit(1); + stream << "*********************************" << std::endl; + stream << "Failed Tests:\t" << mFailedTests << std::endl; + stream << "Please report or fix the problem." << std::endl; + stream << "*********************************" << std::endl; } } @@ -159,25 +182,116 @@ protected: int mPassedTests; int mFailedTests; int mSkippedTests; - int mSkipedFailTests; + std::ostream *mStream; +}; + +// TeamCity specific class which emits service messages +// http://confluence.jetbrains.net/display/TCD3/Build+Script+Interaction+with+TeamCity;#BuildScriptInteractionwithTeamCity-testReporting + +class LLTCTestCallback : public LLTestCallback +{ +public: + LLTCTestCallback(bool verbose_mode, std::ostream *stream) : + LLTestCallback(verbose_mode, stream), + mTCStream() + { + } + + ~LLTCTestCallback() + { + } + + virtual void group_started(const std::string& name) { + LLTestCallback::group_started(name); + mTCStream << "\n##teamcity[testSuiteStarted name='" << name << "']" << std::endl; + } + + virtual void group_completed(const std::string& name) { + LLTestCallback::group_completed(name); + mTCStream << "##teamcity[testSuiteFinished name='" << name << "']" << std::endl; + } + + virtual void test_completed(const tut::test_result& tr) + { + LLTestCallback::test_completed(tr); + + switch(tr.result) + { + case tut::test_result::ok: + mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl; + break; + case tut::test_result::fail: + mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl; + mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl; + break; + case tut::test_result::ex: + mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl; + mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl; + break; + case tut::test_result::warn: + mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl; + mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl; + break; + case tut::test_result::term: + mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl; + mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl; + break; + case tut::test_result::skip: + mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testIgnored name='" << tr.group << "." << tr.test << "']" << std::endl; + mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl; + break; + default: + break; + } + + } + + virtual void run_completed() + { + LLTestCallback::run_completed(); + + // dump the TC reporting results to cout + tc_run_completed_(std::cout); + } + + virtual void tc_run_completed_(std::ostream &stream) + { + + // dump the TC reporting results to cout + stream << mTCStream.str() << std::endl; + } + +protected: + std::ostringstream mTCStream; + }; + 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."}, - {"skip", 's', 1, "Skip test number specified by option argument. Only works when a specific group is being tested"}, + {"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; + << std::endl; s << "This application runs the unit tests." << std::endl << std::endl; @@ -187,7 +301,7 @@ void stream_usage(std::ostream& s, const char* app) { s << " "; s << " -" << (char)option->optch << ", --" << option->name - << std::endl; + << std::endl; s << "\t" << option->description << std::endl << std::endl; ++option; } @@ -199,8 +313,6 @@ void stream_usage(std::ostream& s, const char* app) s << "\tList all available test groups." << std::endl; s << " " << app << " --group=uuid" << std::endl; s << "\tRun the test group 'uuid'." << std::endl; - s << " " << app << " --skip=2" << std::endl; - s << "\tSkip test case 2." << std::endl; } void stream_groups(std::ostream& s, const char* app) @@ -222,12 +334,17 @@ void wouldHaveCrashed(const std::string& message) int main(int argc, char **argv) { + // The following line must be executed to initialize Google Mock + // (and Google Test) before running the tests. +#ifndef LL_WINDOWS + ::testing::InitGoogleMock(&argc, argv); +#endif LLError::initForApplication("."); LLError::setFatalFunction(wouldHaveCrashed); LLError::setDefaultLevel(LLError::LEVEL_ERROR); - //< *TODO: should come from error config file. Note that we - // have a command line option that sets this to debug. - + //< *TODO: should come from error config file. Note that we + // have a command line option that sets this to debug. + #ifdef CTYPE_WORKAROUND ctype_workaround(); #endif @@ -249,13 +366,16 @@ int main(int argc, char **argv) // values used for controlling application bool verbose_mode = false; bool wait_at_exit = false; - int skip_test_id = 0; std::string test_group; + std::string suite_name; // values use for options parsing apr_status_t apr_err; const char* opt_arg = NULL; int opt_id = 0; + std::ofstream *output = NULL; + const char *touch = NULL; + while(true) { apr_err = apr_getopt_long(os, TEST_CL_OPTIONS, &opt_id, &opt_arg); @@ -264,61 +384,103 @@ int main(int argc, char **argv) { char buf[255]; /* Flawfinder: ignore */ std::cerr << "Error parsing options: " - << apr_strerror(apr_err, buf, 255) << std::endl; + << apr_strerror(apr_err, buf, 255) << std::endl; return 1; } switch (opt_id) { - case 'g': - test_group.assign(opt_arg); - break; - case 's': - skip_test_id = atoi(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 'w': - wait_at_exit = true; - break; - case 'd': - // *TODO: should come from error config file. We set it to - // ERROR by default, so this allows full debug levels. - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - break; - default: - stream_usage(std::cerr, argv[0]); - return 1; - break; + 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 = new std::ofstream; + 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': + // *TODO: should come from error config file. We set it to + // ERROR by default, so this allows full debug levels. + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + break; + case 'x': + suite_name.assign(opt_arg); + break; + default: + stream_usage(std::cerr, argv[0]); + return 1; + break; } } // run the tests - LLTestCallback callback(verbose_mode); - tut::runner.get().set_callback(&callback); - + + LLTestCallback* mycallback; + if (getenv("TEAMCITY_PROJECT_NAME")) + { + mycallback = new LLTCTestCallback(verbose_mode, output); + } + else + { + mycallback = new LLTestCallback(verbose_mode, output); + } + + tut::runner.get().set_callback(mycallback); + if(test_group.empty()) { tut::runner.get().run_tests(); } else { - tut::runner.get().run_tests(test_group, skip_test_id); + tut::runner.get().run_tests(test_group); } + bool success = (mycallback->getFailedTests() == 0); + if (wait_at_exit) { - std::cerr << "Waiting for input before exiting..." << std::endl; + std::cerr << "Press return to exit..." << std::endl; std::cin.get(); } - + + if (output) + { + output->close(); + delete output; + } + + if (touch && success) + { + std::ofstream s; + s.open(touch); + s << "ok" << std::endl; + s.close(); + } + apr_terminate(); - return 0; + + int retval = (success ? 0 : 1); + return retval; + + //delete mycallback; } |