summaryrefslogtreecommitdiff
path: root/src/mongo/unittest/unittest.cpp
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2012-05-30 17:48:52 -0400
committerAndy Schwerin <schwerin@10gen.com>2012-06-04 13:08:27 -0400
commitc04922ad14ebe43d99ba056b7b3ae79860b8cd91 (patch)
tree5057ff729113f61028ed4c94ae96c26796d49c92 /src/mongo/unittest/unittest.cpp
parent7cb8e1f11959d8cb45954fcb1cfe13cdc6caa169 (diff)
downloadmongo-c04922ad14ebe43d99ba056b7b3ae79860b8cd91.tar.gz
SERVER-5702: C++ unit test framework that can be compiled separately.
Includes a unit test of the unit test framework written in the unit test framework, itself.
Diffstat (limited to 'src/mongo/unittest/unittest.cpp')
-rw-r--r--src/mongo/unittest/unittest.cpp153
1 files changed, 84 insertions, 69 deletions
diff --git a/src/mongo/unittest/unittest.cpp b/src/mongo/unittest/unittest.cpp
index 0844bd942da..34b90dccc33 100644
--- a/src/mongo/unittest/unittest.cpp
+++ b/src/mongo/unittest/unittest.cpp
@@ -1,5 +1,3 @@
-// mongo/unittest/unittest.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -16,25 +14,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "mongo/pch.h"
-#include "pch.h"
#include "mongo/unittest/unittest.h"
#include <iostream>
#include <map>
#include "mongo/util/assert_util.h"
-#include "mongo/util/concurrency/mutex.h"
+#include "mongo/util/log.h"
namespace mongo {
namespace unittest {
namespace {
- std::map<std::string, Suite *> *_suites = 0;
+ typedef std::map<std::string, Suite*> SuiteMap;
+
+ inline SuiteMap &_allSuites() {
+ static SuiteMap allSuites;
+ return allSuites;
+ }
- mutex currentTestNameMutex("currentTestNameMutex");
- std::string currentTestName;
} // namespace
class Result {
@@ -72,9 +73,17 @@ namespace mongo {
Result *Result::cur = 0;
- TestCase::~TestCase() {}
- void TestCase::setUp() {}
- void TestCase::tearDown() {}
+ Test::Test() {}
+ Test::~Test() {}
+
+ void Test::run() {
+ setUp();
+ _doTest();
+ tearDown();
+ }
+
+ void Test::setUp() {}
+ void Test::tearDown() {}
Suite::Suite( const std::string &name ) : _name( name ) {
registerSuite( name , this );
@@ -82,9 +91,11 @@ namespace mongo {
Suite::~Suite() {}
+ void Suite::add(const std::string& name, const TestFunction& testFn) {
+ _tests.push_back(new TestHolder(name, testFn));
+ }
+
Result * Suite::run( const std::string& filter ) {
- // set tlogLevel to -1 to suppress tlog() output in a test program
- tlogLevel = -1;
log(1) << "\t about to setupTests" << std::endl;
setupTests();
@@ -93,11 +104,8 @@ namespace mongo {
Result * r = new Result( _name );
Result::cur = r;
- /* see note in SavedContext */
- //writelock lk("");
-
- for ( std::vector<TestCase*>::iterator i=_tests.begin(); i!=_tests.end(); i++ ) {
- TestCase * tc = *i;
+ for ( std::vector<TestHolder*>::iterator i=_tests.begin(); i!=_tests.end(); i++ ) {
+ TestHolder * tc = *i;
if ( filter.size() && tc->getName().find( filter ) == std::string::npos ) {
log(1) << "\t skipping test: " << tc->getName() << " because doesn't match filter" << std::endl;
continue;
@@ -107,12 +115,9 @@ namespace mongo {
bool passes = false;
- {
- scoped_lock lk(currentTestNameMutex);
- currentTestName = tc->getName();
- }
+ onCurrentTestNameChange( tc->getName() );
- log(1) << "\t going to run test: " << tc->getName() << std::endl;
+ std::cout << "\t going to run test: " << tc->getName() << std::endl;
std::stringstream err;
err << tc->getName() << "\t";
@@ -121,23 +126,22 @@ namespace mongo {
tc->run();
passes = true;
}
- catch ( MyAssertionException * ae ) {
- err << ae->ss.str();
- delete( ae );
+ catch ( const TestAssertionFailureException & ae ) {
+ err << ae.toString();
}
- catch ( std::exception& e ) {
- err << " exception: " << e.what();
+ catch ( const std::exception& e ) {
+ err << " std::exception: " << e.what() << " in test " << tc->getName();
}
catch ( int x ) {
- err << " caught int : " << x << std::endl;
+ err << " caught int " << x << " in test " << tc->getName();
}
catch ( ... ) {
- err << "unknown exception in test: " << tc->getName() << std::endl;
+ err << "unknown exception in test: " << tc->getName();
}
if ( ! passes ) {
std::string s = err.str();
- log() << "FAIL: " << s << std::endl;
+ std::cout << "FAIL: " << s << std::endl;
r->_fails++;
r->_messages.push_back( s );
}
@@ -147,44 +151,48 @@ namespace mongo {
r->_rc = 17;
- {
- scoped_lock lk(currentTestNameMutex);
- currentTestName = "";
- }
+ onCurrentTestNameChange( "" );
- log(1) << "\t DONE running tests" << std::endl;
+ std::cout << "\t DONE running tests" << std::endl;
return r;
}
int Suite::run( const std::vector<std::string> &suites , const std::string& filter ) {
+
+ if (_allSuites().empty()) {
+ std::cout << "error: no suites registered.";
+ return 1;
+ }
+
for ( unsigned int i = 0; i < suites.size(); i++ ) {
- if ( _suites->find( suites[i] ) == _suites->end() ) {
+ if ( _allSuites().count( suites[i] ) == 0 ) {
std::cout << "invalid test suite [" << suites[i] << "], use --list to see valid names" << std::endl;
- return -1;
+ return 1;
}
}
std::vector<std::string> torun(suites);
if ( torun.empty() ) {
- for ( std::map<std::string,Suite*>::iterator i=_suites->begin() ; i!=_suites->end(); i++ )
+ for ( SuiteMap::const_iterator i = _allSuites().begin();
+ i !=_allSuites().end(); ++i ) {
+
torun.push_back( i->first );
+ }
}
std::vector<Result*> results;
for ( std::vector<std::string>::iterator i=torun.begin(); i!=torun.end(); i++ ) {
std::string name = *i;
- Suite * s = (*_suites)[name];
+ Suite* s = _allSuites()[name];
fassert( 16145, s );
- log() << "going to run suite: " << name << std::endl;
+ std::cout << "going to run suite: " << name << std::endl;
results.push_back( s->run( filter ) );
}
- Logstream::get().flush();
-
std::cout << "**************************************************" << std::endl;
int rc = 0;
@@ -215,53 +223,60 @@ namespace mongo {
}
void Suite::registerSuite( const std::string &name , Suite * s ) {
- if ( ! _suites )
- _suites = new std::map<std::string,Suite*>();
- Suite*& m = (*_suites)[name];
+ Suite*& m = _allSuites()[name];
fassert( 10162, ! m );
m = s;
}
- void assert_pass() {
- Result::cur->_asserts++;
+ Suite* Suite::getSuite(const std::string& name) {
+ Suite* result = _allSuites()[name];
+ if (!result)
+ result = new Suite(name); // Suites are self-registering.
+ return result;
}
- void assert_fail( const char * exp , const char * file , unsigned line ) {
- Result::cur->_asserts++;
+ void Suite::setupTests() {}
- MyAssertionException * e = new MyAssertionException();
- e->ss << "ASSERT FAILED! " << file << ":" << line << std::endl;
- std::cout << e->ss.str() << std::endl;
- throw e;
+ TestAssertionFailureDetails::TestAssertionFailureDetails(
+ const std::string &theFile,
+ unsigned theLine,
+ const std::string &theMessage )
+ : file( theFile ), line( theLine ), message( theMessage ) {
}
- MyAssertionException * MyAsserts::getBase() {
- MyAssertionException * e = new MyAssertionException();
- e->ss << _file << ":" << _line << " " << _aexp << " != " << _bexp << " ";
- return e;
+ TestAssertionFailureException::TestAssertionFailureException(
+ const std::string &theFile,
+ unsigned theLine,
+ const std::string &theFailingExpression )
+ : _details( new TestAssertionFailureDetails( theFile, theLine, theFailingExpression ) ) {
}
- void MyAsserts::printLocation() {
- log() << _file << ":" << _line << " " << _aexp << " != " << _bexp << " ";
+ std::string TestAssertionFailureException::toString() const {
+ std::ostringstream os;
+ os << getMessage() << " @" << getFile() << ":" << getLine();
+ return os.str();
}
- void MyAsserts::_gotAssert() {
- Result::cur->_asserts++;
+ TestAssertion::TestAssertion( const std::string &file, unsigned line )
+ : _file( file ), _line( line ) {
+
+ ++Result::cur->_asserts;
}
- std::string getExecutingTestName() {
- scoped_lock lk(currentTestNameMutex);
- return currentTestName;
+ TestAssertion::~TestAssertion() {}
+
+ void TestAssertion::fail( const std::string &message ) const {
+ throw TestAssertionFailureException( _file, _line, message );
}
+ ComparisonAssertion::ComparisonAssertion( const std::string &aexp, const std::string &bexp,
+ const std::string &file, unsigned line )
+ : TestAssertion( file, line ), _aexp( aexp ), _bexp( bexp ) {}
+
std::vector<std::string> getAllSuiteNames() {
std::vector<std::string> result;
- if (_suites) {
- for ( std::map<std::string, Suite *>::const_iterator i = _suites->begin();
- i != _suites->end(); ++i ) {
-
+ for (SuiteMap::const_iterator i = _allSuites().begin(); i != _allSuites().end(); ++i) {
result.push_back(i->first);
- }
}
return result;
}