diff options
| author | Oz Linden <oz@lindenlab.com> | 2012-03-09 12:57:51 -0500 | 
|---|---|---|
| committer | Oz Linden <oz@lindenlab.com> | 2012-03-09 12:57:51 -0500 | 
| commit | 35dd27d5e57b2957aaa904cce841fccd4cfff850 (patch) | |
| tree | a85efe74bdb66b1ccdeb98dd2d04efb6af323a11 /indra | |
| parent | 0a873715677ef3fb28e8dab161acbe05ed8bd537 (diff) | |
| parent | 0fe14d9d70e247156f98991a484de4f5ece9ae8a (diff) | |
merge changes for vmrg-223
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/test/test.cpp | 212 | 
1 files changed, 128 insertions, 84 deletions
| diff --git a/indra/test/test.cpp b/indra/test/test.cpp index ffdb0cb976..e58e7293fb 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -37,6 +37,7 @@  #include "linden_common.h"  #include "llerrorcontrol.h"  #include "lltut.h" +#include "stringize.h"  #include "apr_pools.h"  #include "apr_getopt.h" @@ -53,6 +54,22 @@  #include <gtest/gtest.h>  #endif +#if LL_MSVC +#pragma warning (push) +#pragma warning (disable : 4702) // warning C4702: unreachable code +#endif +#include <boost/iostreams/tee.hpp> +#include <boost/iostreams/stream.hpp> +#if LL_MSVC +#pragma warning (pop) +#endif + +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> +#include <boost/foreach.hpp> +#include <boost/lambda/lambda.hpp> +  namespace tut  {  	std::string sSourceDir; @@ -69,8 +86,24 @@ public:  	mPassedTests(0),  	mFailedTests(0),  	mSkippedTests(0), -	mStream(stream) +	// 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(boost::shared_ptr<std::ostream>(&std::cout, boost::lambda::_1))  	{ +		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.) +			boost::shared_ptr<std::ostream> pstream(new TeeStream(std::cout, boost::ref(*stream))); +			mStream = pstream; +		}  	}  	~LLTestCallback() @@ -83,18 +116,21 @@ public:  	}  	virtual void group_started(const std::string& name) { -		std::cout << "Unit test group_started name=" << name << std::endl; +		*mStream << "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; +		*mStream << "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 << "] "; +		out << "[" << tr.group << ", " << tr.test; +		if (! tr.name.empty()) +			out << ": " << tr.name; +		out << "] ";  		switch(tr.result)  		{  			case tut::test_result::ok: @@ -123,56 +159,43 @@ public:  				break;  			default:  				++mFailedTests; -				out << "unknown"; +				out << "unknown (tr.result == " << tr.result << ")";  		}  		if(mVerboseMode || (tr.result != tut::test_result::ok))  		{ +			*mStream << out.str();  			if(!tr.message.empty())  			{ -				out << ": '" << tr.message << "'"; -			} -			if (mStream) -			{ -				*mStream << out.str() << std::endl; +				*mStream << ": '" << tr.message << "'";  			} -			 -			std::cout << out.str() << std::endl; -		} -	} - -	virtual void run_completed() -	{ -		if (mStream) -		{ -			run_completed_(*mStream); +			*mStream << std::endl;  		} -		run_completed_(std::cout);  	}  	virtual int getFailedTests() const { return mFailedTests; } -	virtual void run_completed_(std::ostream &stream) +	virtual void run_completed()  	{ -		stream << "\tTotal Tests:\t" << mTotalTests << std::endl; -		stream << "\tPassed Tests:\t" << mPassedTests; +		*mStream << "\tTotal Tests:\t" << mTotalTests << std::endl; +		*mStream << "\tPassed Tests:\t" << mPassedTests;  		if (mPassedTests == mTotalTests)  		{ -			stream << "\tYAY!! \\o/"; +			*mStream << "\tYAY!! \\o/";  		} -		stream << std::endl; +		*mStream << std::endl;  		if (mSkippedTests > 0)  		{ -			stream << "\tSkipped known failures:\t" << mSkippedTests +			*mStream << "\tSkipped known failures:\t" << mSkippedTests  			<< std::endl;  		}  		if(mFailedTests > 0)  		{ -			stream << "*********************************" << std::endl; -			stream << "Failed Tests:\t" << mFailedTests << std::endl; -			stream << "Please report or fix the problem." << std::endl; -			stream << "*********************************" << std::endl; +			*mStream << "*********************************" << std::endl; +			*mStream << "Failed Tests:\t" << mFailedTests << std::endl; +			*mStream << "Please report or fix the problem." << std::endl; +			*mStream << "*********************************" << std::endl;  		}  	} @@ -182,7 +205,7 @@ protected:  	int mPassedTests;  	int mFailedTests;  	int mSkippedTests; -	std::ostream *mStream; +	boost::shared_ptr<std::ostream> mStream;  };  // TeamCity specific class which emits service messages @@ -192,84 +215,111 @@ class LLTCTestCallback : public LLTestCallback  {  public:  	LLTCTestCallback(bool verbose_mode, std::ostream *stream) : -		LLTestCallback(verbose_mode, stream), -		mTCStream() +		LLTestCallback(verbose_mode, stream)  	{  	}  	~LLTCTestCallback()  	{ -	}	 +	}  	virtual void group_started(const std::string& name) {  		LLTestCallback::group_started(name); -		mTCStream << "\n##teamcity[testSuiteStarted name='" << name << "']" << std::endl; +		std::cout << "\n##teamcity[testSuiteStarted name='" << escape(name) << "']" << std::endl;  	}  	virtual void group_completed(const std::string& name) {  		LLTestCallback::group_completed(name); -		mTCStream << "##teamcity[testSuiteFinished name='" << name << "']" << std::endl; +		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: -				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; +				std::cout << "##teamcity[testFailed name='" << testname +						  << "' message='" << escape(tr.message) << "']" << 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; +				std::cout << "##teamcity[testIgnored name='" << testname << "']" << std::endl;  				break; +  			default:  				break;  		} +		std::cout << "##teamcity[testFinished name='" << testname << "']" << std::endl;  	} -	virtual void run_completed() +	static std::string escape(const std::string& str)  	{ -		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; +		// Per http://confluence.jetbrains.net/display/TCD65/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ServiceMessages +		std::string result; +		BOOST_FOREACH(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; +|*==========================================================================*/ +			case '|': +				result.append("||"); +				break; +			case '[': +				result.append("|["); +				break; +			case ']': +				result.append("|]"); +				break; +			default: +				result.push_back(c); +				break; +			} +		} +		return result;  	} -	 -protected: -	std::ostringstream mTCStream; -  }; @@ -359,7 +409,7 @@ int main(int argc, char **argv)  	apr_getopt_t* os = NULL;  	if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv))  	{ -		std::cerr << "Unable to  pool" << std::endl; +		std::cerr << "apr_getopt_init() failed" << std::endl;  		return 1;  	} @@ -373,7 +423,7 @@ int main(int argc, char **argv)  	apr_status_t apr_err;  	const char* opt_arg = NULL;  	int opt_id = 0; -	std::ofstream *output = NULL; +	boost::scoped_ptr<std::ofstream> output;  	const char *touch = NULL;  	while(true) @@ -403,7 +453,7 @@ int main(int argc, char **argv)  				verbose_mode = true;  				break;  			case 'o': -				output = new std::ofstream; +				output.reset(new std::ofstream);  				output->open(opt_arg);  				break;  			case 's':	// --sourcedir @@ -437,11 +487,11 @@ int main(int argc, char **argv)  	LLTestCallback* mycallback;  	if (getenv("TEAMCITY_PROJECT_NAME"))  	{ -		mycallback = new LLTCTestCallback(verbose_mode, output);		 +		mycallback = new LLTCTestCallback(verbose_mode, output.get());		  	}  	else  	{ -		mycallback = new LLTestCallback(verbose_mode, output); +		mycallback = new LLTestCallback(verbose_mode, output.get());  	}  	tut::runner.get().set_callback(mycallback); @@ -463,12 +513,6 @@ int main(int argc, char **argv)  		std::cin.get();  	} -	if (output) -	{ -		output->close(); -		delete output; -	} -  	if (touch && success)  	{  		std::ofstream s; | 
