CppUnitLite will now catch exceptions and tell you the error and the line number of the failing test. This is to avoid having to hunt for crashing tests out of a large battery of tests. Look at the results of the (still failing) wrap/testWrap for an example.
							parent
							
								
									3438f89526
								
							
						
					
					
						commit
						7b85dc3ff4
					
				|  | @ -17,6 +17,16 @@ Failure::Failure (const SimpleString&	theTestName, | |||
| { | ||||
| } | ||||
| 
 | ||||
| Failure::Failure (const SimpleString&	theTestName, | ||||
| 				  const SimpleString&	theFileName, | ||||
| 		          const SimpleString&	theCondition) | ||||
| : message (theCondition), | ||||
|   testName (theTestName), | ||||
|   fileName (theFileName), | ||||
|   lineNumber (-1) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Failure::Failure (const SimpleString&	theTestName,  | ||||
| 			 	  const SimpleString&	theFileName,  | ||||
|  |  | |||
|  | @ -31,6 +31,11 @@ public: | |||
| 			 const SimpleString&		expected, | ||||
| 			 const SimpleString&		actual); | ||||
| 
 | ||||
| 	Failure (const SimpleString&		theTestName, | ||||
| 			 const SimpleString&		theFileName, | ||||
| 			 const SimpleString&		theCondition); | ||||
| 
 | ||||
| 
 | ||||
| 	SimpleString		message; | ||||
| 	SimpleString		testName; | ||||
| 	SimpleString		fileName; | ||||
|  |  | |||
|  | @ -9,47 +9,56 @@ | |||
| static const int DEFAULT_SIZE = 20; | ||||
| 
 | ||||
| SimpleString::SimpleString () | ||||
| : buffer(new char [1]) | ||||
| : buffer_(new char [1]) | ||||
| { | ||||
| 	buffer [0] = '\0'; | ||||
| 	buffer_ [0] = '\0'; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| SimpleString::SimpleString (const char *otherBuffer) | ||||
| : buffer (new char [strlen (otherBuffer) + 1]) | ||||
| : buffer_ (new char [strlen (otherBuffer) + 1]) | ||||
| { | ||||
| 	strcpy (buffer, otherBuffer); | ||||
| 	strcpy (buffer_, otherBuffer); | ||||
| } | ||||
| 
 | ||||
| SimpleString::SimpleString (const SimpleString& other) | ||||
| { | ||||
| 	buffer = new char [other.size() + 1]; | ||||
| 	strcpy(buffer, other.buffer); | ||||
| 	buffer_ = new char [other.size() + 1]; | ||||
| 	strcpy(buffer_, other.buffer_); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| SimpleString SimpleString::operator= (const SimpleString& other) | ||||
| { | ||||
| 	delete buffer; | ||||
| 	buffer = new char [other.size() + 1]; | ||||
| 	strcpy(buffer, other.buffer);	 | ||||
| 	delete buffer_; | ||||
| 	buffer_ = new char [other.size() + 1]; | ||||
| 	strcpy(buffer_, other.buffer_); | ||||
| 	return *this; | ||||
| } | ||||
| 
 | ||||
| SimpleString SimpleString::operator+ (const SimpleString& other) | ||||
| { | ||||
| 	SimpleString ret; | ||||
| 	delete ret.buffer_; | ||||
| 	ret.buffer_ = new char [size() + other.size() - 1]; | ||||
| 	strcpy(ret.buffer_, buffer_); | ||||
| 	strcat(ret.buffer_, other.buffer_); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| char *SimpleString::asCharString () const | ||||
| { | ||||
| 	return buffer; | ||||
| 	return buffer_; | ||||
| } | ||||
| 
 | ||||
| int SimpleString::size() const | ||||
| { | ||||
| 	return strlen (buffer); | ||||
| 	return strlen (buffer_); | ||||
| } | ||||
| 
 | ||||
| SimpleString::~SimpleString () | ||||
| { | ||||
| 	delete [] buffer; | ||||
| 	delete [] buffer_; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,12 +25,13 @@ public: | |||
| 						~SimpleString (); | ||||
| 
 | ||||
| 	SimpleString		operator= (const SimpleString& other); | ||||
| 	SimpleString		operator+ (const SimpleString& other); | ||||
| 
 | ||||
| 	char				*asCharString () const; | ||||
| 	int					size() const; | ||||
| 
 | ||||
| private: | ||||
| 	char				*buffer; | ||||
| 	char				*buffer_; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,11 @@ Test::Test (const SimpleString& testName) | |||
| 	TestRegistry::addTest (this); | ||||
| } | ||||
| 
 | ||||
| Test::Test (const SimpleString& testName, const SimpleString& filename, long lineNumber) | ||||
| 	: name_(testName), filename_(filename), lineNumber_(lineNumber) | ||||
| { | ||||
| 	TestRegistry::addTest (this); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Test *Test::getNext() const | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ class Test | |||
| { | ||||
| public: | ||||
| 	Test (const SimpleString& testName); | ||||
| 	Test (const SimpleString& testName, const SimpleString& filename, long lineNumber); | ||||
|   virtual ~Test() {}; | ||||
| 
 | ||||
| 	virtual void	run (TestResult& result) = 0; | ||||
|  | @ -29,6 +30,9 @@ public: | |||
| 
 | ||||
| 	void			setNext(Test *test); | ||||
| 	Test			*getNext () const; | ||||
| 	SimpleString    getName() const {return name_;} | ||||
| 	SimpleString 	getFilename() const {return filename_;} | ||||
| 	long			getLineNumber() const {return lineNumber_;} | ||||
| 
 | ||||
| protected: | ||||
| 
 | ||||
|  | @ -37,13 +41,15 @@ protected: | |||
| 
 | ||||
| 	SimpleString	name_; | ||||
| 	Test			*next_; | ||||
| 	SimpleString 	filename_; | ||||
| 	long 			lineNumber_; /// This is the line line number of the test, rather than the a single check
 | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #define TEST(testName, testGroup)\ | ||||
|   class testGroup##testName##Test : public Test \ | ||||
| 	{ public: testGroup##testName##Test () : Test (#testName "Test") {} \ | ||||
| 	{ public: testGroup##testName##Test () : Test (#testName "Test", __FILE__, __LINE__) {} \ | ||||
|             void run (TestResult& result_);} \ | ||||
|     testGroup##testName##Instance; \ | ||||
| 	void testGroup##testName##Test::run (TestResult& result_)  | ||||
|  |  | |||
|  | @ -1,8 +1,12 @@ | |||
| 
 | ||||
| 
 | ||||
| #include <exception> | ||||
| 
 | ||||
| #include "Test.h" | ||||
| #include "Failure.h" | ||||
| #include "TestResult.h" | ||||
| #include "TestRegistry.h" | ||||
| #include "SimpleString.h" | ||||
| 
 | ||||
| 
 | ||||
| void TestRegistry::addTest (Test *test)  | ||||
|  | @ -13,7 +17,7 @@ void TestRegistry::addTest (Test *test) | |||
| 
 | ||||
| int TestRegistry::runAllTests (TestResult& result)  | ||||
| { | ||||
| 	instance ().run (result); | ||||
| 	return instance ().run (result); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -30,7 +34,7 @@ void TestRegistry::add (Test *test) | |||
| 		tests = test; | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	test->setNext (tests); | ||||
| 	tests = test; | ||||
| } | ||||
|  | @ -40,10 +44,22 @@ int TestRegistry::run (TestResult& result) | |||
| { | ||||
| 	result.testsStarted (); | ||||
| 
 | ||||
| 	for (Test *test = tests; test != 0; test = test->getNext ()) | ||||
| 		test->run (result); | ||||
| 	for (Test *test = tests; test != 0; test = test->getNext ()) { | ||||
| 		// TODO: add a try/catch wrapper here
 | ||||
| 		try { | ||||
| 			test->run (result); | ||||
| 		} catch (std::exception& e) { | ||||
| 			result.addFailure( | ||||
| 					Failure(test->getName(), test->getFilename(), test->getLineNumber(), | ||||
| 							SimpleString("Exception: ") + SimpleString(e.what()))); | ||||
| 		} catch (...) { | ||||
| 			result.addFailure( | ||||
| 					Failure(test->getName(), test->getFilename(), test->getLineNumber(), | ||||
| 							SimpleString("ExceptionThrown!"))); | ||||
| 		} | ||||
| 	} | ||||
| 	result.testsEnded (); | ||||
|   return result.getFailureCount(); | ||||
| 	return result.getFailureCount(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,15 +18,22 @@ void TestResult::testsStarted () | |||
| 
 | ||||
| void TestResult::addFailure (const Failure& failure)  | ||||
| { | ||||
| 	fprintf (stdout, "%s%s%s%s%ld%s%s\n", | ||||
| 		"Failure: \"", | ||||
| 		failure.message.asCharString (), | ||||
| 		"\" " , | ||||
| 		"line ", | ||||
| 		failure.lineNumber, | ||||
| 		" in ", | ||||
| 		failure.fileName.asCharString ()); | ||||
| 		 | ||||
| 	if (failure.lineNumber < 0) // allow for no line number
 | ||||
| 		fprintf (stdout, "%s%s%s%s%ld%s%s\n", | ||||
| 				"Failure: \"", | ||||
| 				failure.message.asCharString (), | ||||
| 				"\" in ", | ||||
| 				failure.fileName.asCharString ()); | ||||
| 	else | ||||
| 		fprintf (stdout, "%s%s%s%s%ld%s%s\n", | ||||
| 				"Failure: \"", | ||||
| 				failure.message.asCharString (), | ||||
| 				"\" " , | ||||
| 				"line ", | ||||
| 				failure.lineNumber, | ||||
| 				" in ", | ||||
| 				failure.fileName.asCharString ()); | ||||
| 
 | ||||
| 	failureCount++; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,7 +34,6 @@ TEST( matrix, constructor_data ) | |||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| 
 | ||||
| TEST( matrix, constructor_vector ) | ||||
| { | ||||
| 	double data[] = { -5, 3, 0, -5 }; | ||||
|  |  | |||
|  | @ -28,72 +28,63 @@ TEST( wrap, ArgumentList ) { | |||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| TEST( wrap, parse ) { | ||||
| 	try { | ||||
| 		Module module(".", "geometry",verbose); | ||||
| 		CHECK(module.classes.size()==3); | ||||
| 	Module module(".", "geometry",verbose); | ||||
| 	CHECK(module.classes.size()==3); | ||||
| 
 | ||||
| 		// check second class, Point3
 | ||||
| 		Class cls = *(++module.classes.begin()); | ||||
| 		CHECK(cls.name=="Point3"); | ||||
| 		CHECK(cls.constructors.size()==1); | ||||
| 		CHECK(cls.methods.size()==1); | ||||
| 	// check second class, Point3
 | ||||
| 	Class cls = *(++module.classes.begin()); | ||||
| 	CHECK(cls.name=="Point3"); | ||||
| 	CHECK(cls.constructors.size()==1); | ||||
| 	CHECK(cls.methods.size()==1); | ||||
| 
 | ||||
| 		// first constructor takes 3 doubles
 | ||||
| 		Constructor c1 = cls.constructors.front(); | ||||
| 		CHECK(c1.args.size()==3); | ||||
| 	// first constructor takes 3 doubles
 | ||||
| 	Constructor c1 = cls.constructors.front(); | ||||
| 	CHECK(c1.args.size()==3); | ||||
| 
 | ||||
| 		// check first double argument
 | ||||
| 		Argument a1 = c1.args.front(); | ||||
| 		CHECK(!a1.is_const); | ||||
| 		CHECK(a1.type=="double"); | ||||
| 		CHECK(!a1.is_ref); | ||||
| 		CHECK(a1.name=="x"); | ||||
| 	// check first double argument
 | ||||
| 	Argument a1 = c1.args.front(); | ||||
| 	CHECK(!a1.is_const); | ||||
| 	CHECK(a1.type=="double"); | ||||
| 	CHECK(!a1.is_ref); | ||||
| 	CHECK(a1.name=="x"); | ||||
| 
 | ||||
| 		// check method
 | ||||
| 		Method m1 = cls.methods.front(); | ||||
| 		CHECK(m1.returns=="double"); | ||||
| 		CHECK(m1.name=="norm"); | ||||
| 		CHECK(m1.args.size()==0); | ||||
| 		CHECK(m1.is_const); | ||||
| 
 | ||||
| 	} catch (exception& e) { | ||||
| 		FAIL(e.what()); | ||||
| 	} | ||||
| 	// check method
 | ||||
| 	Method m1 = cls.methods.front(); | ||||
| 	CHECK(m1.returns=="double"); | ||||
| 	CHECK(m1.name=="norm"); | ||||
| 	CHECK(m1.args.size()==0); | ||||
| 	CHECK(m1.is_const); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| TEST( wrap, matlab_code ) { | ||||
| 	// Parse into class object
 | ||||
| 	try { | ||||
| 		Module module(".","geometry",verbose); | ||||
| 	Module module(".","geometry",verbose); | ||||
| 
 | ||||
| 		// emit MATLAB code
 | ||||
| 		// make_geometry will not compile, use make testwrap to generate real make
 | ||||
| 		module.matlab_code("actual", "", "-O5"); | ||||
| 	// emit MATLAB code
 | ||||
| 	// make_geometry will not compile, use make testwrap to generate real make
 | ||||
| 	module.matlab_code("actual", "", "-O5"); | ||||
| 
 | ||||
| 		CHECK(files_equal("expected/@Point2/Point2.m"  , "actual/@Point2/Point2.m"  )); | ||||
| 		CHECK(files_equal("expected/@Point2/x.cpp"     , "actual/@Point2/x.cpp"     )); | ||||
| 	CHECK(files_equal("expected/@Point2/Point2.m"  , "actual/@Point2/Point2.m"  )); | ||||
| 	CHECK(files_equal("expected/@Point2/x.cpp"     , "actual/@Point2/x.cpp"     )); | ||||
| 
 | ||||
| 		CHECK(files_equal("expected/@Point3/Point3.m"  , "actual/@Point3/Point3.m"  )); | ||||
| 		CHECK(files_equal("expected/new_Point3_ddd.m"  , "actual/new_Point3_ddd.m"  )); | ||||
| 		CHECK(files_equal("expected/new_Point3_ddd.cpp", "actual/new_Point3_ddd.cpp")); | ||||
| 		CHECK(files_equal("expected/@Point3/norm.m"    , "actual/@Point3/norm.m"    )); | ||||
| 		CHECK(files_equal("expected/@Point3/norm.cpp"  , "actual/@Point3/norm.cpp"  )); | ||||
| 	CHECK(files_equal("expected/@Point3/Point3.m"  , "actual/@Point3/Point3.m"  )); | ||||
| 	CHECK(files_equal("expected/new_Point3_ddd.m"  , "actual/new_Point3_ddd.m"  )); | ||||
| 	CHECK(files_equal("expected/new_Point3_ddd.cpp", "actual/new_Point3_ddd.cpp")); | ||||
| 	CHECK(files_equal("expected/@Point3/norm.m"    , "actual/@Point3/norm.m"    )); | ||||
| 	CHECK(files_equal("expected/@Point3/norm.cpp"  , "actual/@Point3/norm.cpp"  )); | ||||
| 
 | ||||
| 		CHECK(files_equal("expected/new_Test_.cpp"           , "actual/new_Test_.cpp"           )); | ||||
| 		CHECK(files_equal("expected/@Test/Test.m"            , "actual/@Test/Test.m"            )); | ||||
| 		CHECK(files_equal("expected/@Test/return_string.cpp" , "actual/@Test/return_string.cpp" )); | ||||
| 		CHECK(files_equal("expected/@Test/return_pair.cpp"   , "actual/@Test/return_pair.cpp"   )); | ||||
| 		CHECK(files_equal("expected/@Test/return_field.cpp"  , "actual/@Test/return_field.cpp"  )); | ||||
| 		CHECK(files_equal("expected/@Test/return_TestPtr.cpp", "actual/@Test/return_TestPtr.cpp")); | ||||
| 		CHECK(files_equal("expected/@Test/return_ptrs.cpp"   , "actual/@Test/return_ptrs.cpp"   )); | ||||
| 		CHECK(files_equal("expected/@Test/print.m"           , "actual/@Test/print.m"           )); | ||||
| 		CHECK(files_equal("expected/@Test/print.cpp"         , "actual/@Test/print.cpp"         )); | ||||
| 	CHECK(files_equal("expected/new_Test_.cpp"           , "actual/new_Test_.cpp"           )); | ||||
| 	CHECK(files_equal("expected/@Test/Test.m"            , "actual/@Test/Test.m"            )); | ||||
| 	CHECK(files_equal("expected/@Test/return_string.cpp" , "actual/@Test/return_string.cpp" )); | ||||
| 	CHECK(files_equal("expected/@Test/return_pair.cpp"   , "actual/@Test/return_pair.cpp"   )); | ||||
| 	CHECK(files_equal("expected/@Test/return_field.cpp"  , "actual/@Test/return_field.cpp"  )); | ||||
| 	CHECK(files_equal("expected/@Test/return_TestPtr.cpp", "actual/@Test/return_TestPtr.cpp")); | ||||
| 	CHECK(files_equal("expected/@Test/return_ptrs.cpp"   , "actual/@Test/return_ptrs.cpp"   )); | ||||
| 	CHECK(files_equal("expected/@Test/print.m"           , "actual/@Test/print.m"           )); | ||||
| 	CHECK(files_equal("expected/@Test/print.cpp"         , "actual/@Test/print.cpp"         )); | ||||
| 
 | ||||
| 		CHECK(files_equal("expected/make_geometry.m"   , "actual/make_geometry.m"   )); | ||||
| 	} catch (exception& e) { | ||||
| 		FAIL(e.what()); // fails if file is in wrong place
 | ||||
| 	} | ||||
| 	CHECK(files_equal("expected/make_geometry.m"   , "actual/make_geometry.m"   )); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue