Thread: [Cppunit-devel] templatized assertions
Brought to you by:
blep
From: Steve M. R. <ste...@vi...> - 2001-05-15 20:41:25
|
Hello, Using 1.5.5, I can see two flavours of assertions: assert( boolean ) and assertDoublesEqual( double, double ) [ also assertLongsEqual() ] The second form is potentially very useful, since it allows the diagnostic message to say "expected X, got Y". I'd like to extend this form of assertion to arbitrary types. To this end, I've added templatized assertEquals() and notEqualsMessage() member functions to class TestAssert, and a new assertion macro "assertEqual(x,y)". The assertion will work on any type that has operator=() and operator<<(). The patch below does work. Before I go further down this road and submit a full patch with doc changes, and the whole 9 yards, I thought I'd check to see whether you folks see a problem with this approach. Perhaps this approach has been previously considered and discarded? Comments? -Steve Index: include/cppunit/TestAssert.h =================================================================== RCS file: /cvsroot/cppunit/cppunit/include/cppunit/TestAssert.h,v retrieving revision 1.2 diff -u -b -B -r1.2 TestAssert.h --- include/cppunit/TestAssert.h 2001/05/06 16:19:31 1.2 +++ include/cppunit/TestAssert.h 2001/05/15 20:20:50 @@ -2,6 +2,7 @@ #define CPPUNIT_TESTASSERT_H #include <string> +#include <sstream> #include <cppunit/Exception.h> namespace CppUnit { @@ -19,22 +20,34 @@ long lineNumber = Exception::UNKNOWNLINENUMBER, std::string fileName = Exception::UNKNOWNFILENAME); - static void assertEquals (long expected, - long actual, + template <class T> + static void assertEquals ( + const T& expected, + const T& actual, long lineNumber = Exception::UNKNOWNLINENUMBER, - std::string fileName = Exception::UNKNOWNFILENAME); + std::string fileName = Exception::UNKNOWNFILENAME) + { + if (expected != actual) + assertImplementation (false, notEqualsMessage(expected, actual), lineNumber, fileName); + } + static void assertEquals (double expected, double actual, double delta, long lineNumber = Exception::UNKNOWNLINENUMBER, std::string fileName = Exception::UNKNOWNFILENAME); - static std::string notEqualsMessage (long expected, - long actual); + template <class T> + static std::string notEqualsMessage (const T& expected, + const T& actual) + { + ostringstream ost; + ost << "expected: " << expected + << " but was: " << actual; + return ost.str(); + } - static std::string notEqualsMessage (double expected, - double actual); }; @@ -69,6 +82,15 @@ /// Macro for primitive value comparisons #define assertLongsEqual(expected,actual)\ +(CppUnit::TestAssert::assertEquals ((expected),\ + (actual),__LINE__,__FILE__)) + +/// Generalized macro for primitive value comparisons +/** Any type that implements operator= and operator<< + * can be compared. A diagnostic is printed if the + * actual and expected values disagree. + */ +#define assertEqual(expected,actual)\ (CppUnit::TestAssert::assertEquals ((expected),\ (actual),__LINE__,__FILE__)) -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <bl...@cl...> - 2001-05-16 19:12:15
|
I would use a trait to add the object to the stream. The trait generic implementation would use '<<', but could be specialized when needed. Also, since it is a template member, if should be protected with a define. VC++ 5.0 (and many other compiler I guess) does not support template member for example (though it a static member so I'm not sure). In JUnit, there is also a assertion of the form assert( bool, message )... ----- Original Message ----- From: "Steve M. Robbins" <ste...@vi...> To: <cpp...@li...> Sent: Tuesday, May 15, 2001 10:43 PM Subject: [Cppunit-devel] templatized assertions > Hello, > > Using 1.5.5, I can see two flavours of assertions: > > assert( boolean ) > and assertDoublesEqual( double, double ) [ also assertLongsEqual() ] > > The second form is potentially very useful, since it allows the > diagnostic message to say "expected X, got Y". I'd like to extend > this form of assertion to arbitrary types. > > To this end, I've added templatized assertEquals() and > notEqualsMessage() member functions to class TestAssert, and a new > assertion macro "assertEqual(x,y)". The assertion will work on any > type that has operator=() and operator<<(). > > The patch below does work. Before I go further down this road and > submit a full patch with doc changes, and the whole 9 yards, I thought > I'd check to see whether you folks see a problem with this approach. > Perhaps this approach has been previously considered and discarded? > > Comments? > -Steve > > > > Index: include/cppunit/TestAssert.h > =================================================================== > RCS file: /cvsroot/cppunit/cppunit/include/cppunit/TestAssert.h,v > retrieving revision 1.2 > diff -u -b -B -r1.2 TestAssert.h > --- include/cppunit/TestAssert.h 2001/05/06 16:19:31 1.2 > +++ include/cppunit/TestAssert.h 2001/05/15 20:20:50 > @@ -2,6 +2,7 @@ > #define CPPUNIT_TESTASSERT_H > > #include <string> > +#include <sstream> > #include <cppunit/Exception.h> > > namespace CppUnit { > @@ -19,22 +20,34 @@ > long lineNumber = Exception::UNKNOWNLINENUMBER, > std::string fileName = Exception::UNKNOWNFILENAME); > > - static void assertEquals (long expected, > - long actual, > + template <class T> > + static void assertEquals ( > + const T& expected, > + const T& actual, > long lineNumber = Exception::UNKNOWNLINENUMBER, > - std::string fileName = Exception::UNKNOWNFILENAME); > + std::string fileName = Exception::UNKNOWNFILENAME) > + { > + if (expected != actual) > + assertImplementation (false, notEqualsMessage(expected, actual), lineNumber, fileName); > > + } > + > static void assertEquals (double expected, > double actual, > double delta, > long lineNumber = Exception::UNKNOWNLINENUMBER, > std::string fileName = Exception::UNKNOWNFILENAME); > > - static std::string notEqualsMessage (long expected, > - long actual); > + template <class T> > + static std::string notEqualsMessage (const T& expected, > + const T& actual) > + { > + ostringstream ost; > + ost << "expected: " << expected > + << " but was: " << actual; > + return ost.str(); > + } > > - static std::string notEqualsMessage (double expected, > - double actual); > }; > > > @@ -69,6 +82,15 @@ > > /// Macro for primitive value comparisons > #define assertLongsEqual(expected,actual)\ > +(CppUnit::TestAssert::assertEquals ((expected),\ > + (actual),__LINE__,__FILE__)) > + > +/// Generalized macro for primitive value comparisons > +/** Any type that implements operator= and operator<< > + * can be compared. A diagnostic is printed if the > + * actual and expected values disagree. > + */ > +#define assertEqual(expected,actual)\ > (CppUnit::TestAssert::assertEquals ((expected),\ > (actual),__LINE__,__FILE__)) > > > > > -- > by Rocket to the Moon, > by Airplane to the Rocket, > by Taxi to the Airport, > by Frontdoor to the Taxi, > by throwing back the blanket and laying down the legs ... > - They Might Be Giants > > > _______________________________________________ > Cppunit-devel mailing list > Cpp...@li... > http://lists.sourceforge.net/lists/listinfo/cppunit-devel > |
From: Steve M. R. <ste...@vi...> - 2001-05-17 03:07:33
|
On Wed, May 16, 2001 at 09:28:06PM +0200, Baptiste Lepilleur wrote: > I would use a trait to add the object to the stream. The trait generic > implementation would use '<<', but could be specialized when needed. That sounds like a reasonable idea. I'm not terribly experienced in traits; what would be a good name for the function? Some of CppUnit already uses "toString", which seems reasonable enough, yes? > Also, since it is a template member, if should be protected with a define. > VC++ 5.0 (and many other compiler I guess) does not support template member > for example (though it a static member so I'm not sure). I'm not very knowledgable about the state of support for various features of the language. What is the workaround for compilers that don't support template static members? Actually: why does TestAssert need to be a class at all? There are no data members, so why not just make it a namespace with a bunch of templatized functions? -S -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <gai...@fr...> - 2001-05-17 13:03:10
|
Quoting "Steve M. Robbins" <ste...@vi...>: > On Wed, May 16, 2001 at 09:28:06PM +0200, Baptiste Lepilleur wrote: > > I would use a trait to add the object to the stream. The trait generic > > implementation would use '<<', but could be specialized when needed. > > That sounds like a reasonable idea. I'm not terribly experienced in > traits; what would be a good name for the function? Some of CppUnit > already uses "toString", which seems reasonable enough, yes? It looks good to me. > > Also, since it is a template member, if should be protected with a > define. > > VC++ 5.0 (and many other compiler I guess) does not support template > member > > for example (though it a static member so I'm not sure). > > I'm not very knowledgable about the state of support for various > features > of the language. What is the workaround for compilers that don't > support > template static members? I don't really know, but I can think of a few dirty things (make it a templatized function which take the class instance as parameter). The clean way would probably to add the "expected" template instantiation as method (such as the current assertEquals). > > Actually: why does TestAssert need to be a class at all? There are no > data members, so why not just make it a namespace with a bunch of > templatized functions? The idea was to inherit that class when you wanted to use assertion. But this is of no use since we use macro to capture source file & line number and those macro are global. Using namespace should indeed solve the template member problem. I can see the following impact: - remove inheritance of TestAssert in TestCase - update the sample to use assert macro instead of assertImplementation (I wonder why it's doing that anyway) Removing inheritance would require people to explicitly use the namespace for assertion if they disabled the assert macro. Anybody see a problem with that ? Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Steve M. R. <ste...@vi...> - 2001-05-17 14:44:40
|
On Thu, May 17, 2001 at 02:16:20PM +0200, Baptiste Lepilleur wrote: > Quoting "Steve M. Robbins" <ste...@vi...>: > > On Wed, May 16, 2001 at 09:28:06PM +0200, Baptiste Lepilleur wrote: > > > I would use a trait to add the object to the stream. The trait generic > > > implementation would use '<<', but could be specialized when needed. > > > > That sounds like a reasonable idea. I'm not terribly experienced in > > traits; what would be a good name for the function? Some of CppUnit > > already uses "toString", which seems reasonable enough, yes? > It looks good to me. Okay. I have defined a templated class named AssertionTraits, with exactly one member: toString. Using a traits class for just one thing seems like overkill to me. What other things do you suppose might go in there? Is there a better name than AssertionTraits? > > Actually: why does TestAssert need to be a class at all? There are no > > data members, so why not just make it a namespace with a bunch of > > templatized functions? > The idea was to inherit that class when you wanted to use assertion. But this > is of no use since we use macro to capture source file & line number and those > macro are global. That was my thinking: the assert macros are the interface, as far as I know (but remember that I only started using CppUnit this week!), so what they use as a back-end is irrelevant. Global functions in a TestAssert namespace should do just as well. ... unless folks are using the class functions CppUnit::TestAssert:: TestImplementation(), etc directly. Do you? What is the advantage of doing that? I discovered an annoyance with the current names. As I mentioned the other day, I'd like to have a generic "assert a == b" macro. I tentatively called it assertEqual. The definition is as follows: #define assertEqual(expected,actual)\ (CppUnit::TestAssert::assertEquals ((expected),\ (actual),__LINE__,__FILE__)) unfortunately, the name is too close to TestAssert::assertEquals, which can also take two parameters (the last two have default values). This makes it way too easy (I've already done it once) to use assertEquals(x,y) in the test case, and then wonder why the failure shows up at "unknown line". If nobody is using the back-end functions, I'd solve this by just renaming them. Then, using assertEquals() would be a compile-time error. Of course, the other way to solve it is to pick a sufficiently different name for the new macro. Suggestions welcome. > Using namespace should indeed solve the template member problem. > I can see the following impact: > - remove inheritance of TestAssert in TestCase > - update the sample to use assert macro instead of assertImplementation (I > wonder why it's doing that anyway) > > Removing inheritance would require people to explicitly use the namespace for > assertion if they disabled the assert macro. Anybody see a problem with that ? I don't understand what you mean by "disabled the assert macro". I don't see a way for doing that. Are you referring to folks directly using the TestAssert member functions? -S -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <gai...@fr...> - 2001-05-17 16:35:05
|
Quoting "Steve M. Robbins" <ste...@vi...>: > Okay. I have defined a templated class named AssertionTraits, with > exactly one member: toString. Using a traits class for just one thing > seems like overkill to me. What other things do you suppose might go > in there? Is there a better name than AssertionTraits? The == operator seems like something that could be in the traits to. I'm not very good at naming stuff in english, but I would prefer a name that show that its not about assertion (the assertion is not done there), but converting the object to a string, and testing object for equality. > That was my thinking: the assert macros are the interface, as far as I > know (but remember that I only started using CppUnit this week!), so > what they use as a back-end is irrelevant. Global functions in a > TestAssert namespace should do just as well. My though too. > ... unless folks are using the class functions CppUnit::TestAssert:: > TestImplementation(), etc directly. Do you? What is the advantage of > doing that? See Dolores Scott mail. I only have very few idea why someone would not rely on the assert: 1) Somewhere there are some include of C assert, which override our assert macro... I'm still trying to find a work around that one. Suggestions are welcome. 2) Don't want to use macro despite their usefulness 3) Copied the example (which for unknown reason use assertImplementation). That one can be twisted around by implementing it in the TestCase class, and marking it as "deprecated" for later removal. I use macro because they provide location information. I'm still dreaming of having a stack trace ;-) > I discovered an annoyance with the current names. As I mentioned the > other > day, I'd like to have a generic "assert a == b" macro. I tentatively > called it assertEqual. The definition is as follows: > > #define assertEqual(expected,actual)\ > (CppUnit::TestAssert::assertEquals ((expected),\ > (actual),__LINE__,__FILE__)) > > unfortunately, the name is too close to TestAssert::assertEquals, which > can also take two parameters (the last two have default values). This > makes it way too easy (I've already done it once) to use > assertEquals(x,y) > in the test case, and then wonder why the failure shows up at "unknown > line". I often also have the problem with the assertLongEqual which I write assertLongEquals. Fortunately it ends with compiler error... > > If nobody is using the back-end functions, I'd solve this by just > renaming > them. Then, using assertEquals() would be a compile-time error. > > Of course, the other way to solve it is to pick a sufficiently > different > name for the new macro. Suggestions welcome. I would rather remove the existing assertEquals method which have "the" intuitive name. I don't like twisting around when its not needed. > I don't understand what you mean by "disabled the assert macro". I > don't see a > way for doing that. Are you referring to folks directly using the > TestAssert > member functions? If you look at the source you have: /** A set of macros which allow us to get the line number * and file name at the point of an error. * Just goes to show that preprocessors do have some * redeeming qualities. */ #define CPPUNIT_SOURCEANNOTATION #ifdef CPPUNIT_SOURCEANNOTATION ... Which means if you removed the define, you must use the implementation (TestAssert). --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Steve M. R. <ste...@vi...> - 2001-05-17 16:50:18
|
On Thu, May 17, 2001 at 06:35:02PM +0200, Baptiste Lepilleur wrote: > Quoting "Steve M. Robbins" <ste...@vi...>: > > ... unless folks are using the class functions CppUnit::TestAssert:: > > TestImplementation(), etc directly. Do you? What is the advantage of > > doing that? > See Dolores Scott mail. I only have very few idea why someone would not rely > on the assert: > 1) Somewhere there are some include of C assert, which override our assert > macro... I'm still trying to find a work around that one. Suggestions are > welcome. True. The only fix that comes to mind is for CppUnit to use a different macro name. > > I don't understand what you mean by "disabled the assert macro". I > > don't see a > > way for doing that. Are you referring to folks directly using the > > TestAssert > > member functions? > > If you look at the source you have: > /** A set of macros which allow us to get the line number > * and file name at the point of an error. > * Just goes to show that preprocessors do have some > * redeeming qualities. > */ > #define CPPUNIT_SOURCEANNOTATION > > #ifdef CPPUNIT_SOURCEANNOTATION > ... > > Which means if you removed the define, you must use the implementation > (TestAssert). Read a bit further; there is an #else clause! This symbol is used to choose between two different implementations of the assert macro. In both cases, you have a macro named "assert". -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <bl...@cl...> - 2001-05-17 19:29:18
|
> > If you look at the source you have: > > /** A set of macros which allow us to get the line number > > * and file name at the point of an error. > > * Just goes to show that preprocessors do have some > > * redeeming qualities. > > */ > > #define CPPUNIT_SOURCEANNOTATION > > > > #ifdef CPPUNIT_SOURCEANNOTATION > > ... > > > > Which means if you removed the define, you must use the implementation > > (TestAssert). > > Read a bit further; there is an #else clause! This symbol is used to > choose between two different implementations of the assert macro. In > both cases, you have a macro named "assert". Sorry. I wrote this from memory and it seems it's pretty messed up (that what you get when you're playing with 3 differents versions of cppunit ;-(. ) Is CPPUNIT_SOURCEANNOTATION really required ? The only reason I can see for it would be that some weird compiler does not support the __FILE__ & __LINE__ macros. Have anobody hear of something like that ? Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Author of The Text Reformatter, a tool for fanfiction readers and writers. Language: English, French (Well, I'm French). |
From: Steve M. R. <ste...@vi...> - 2001-05-17 20:25:05
|
On Thu, May 17, 2001 at 09:45:03PM +0200, Baptiste Lepilleur wrote: > > > If you look at the source you have: > > > /** A set of macros which allow us to get the line number > > > * and file name at the point of an error. > > > * Just goes to show that preprocessors do have some > > > * redeeming qualities. > > > */ > > > #define CPPUNIT_SOURCEANNOTATION > > > > > > #ifdef CPPUNIT_SOURCEANNOTATION > > > ... > > > > > > Which means if you removed the define, you must use the implementation > > > (TestAssert). > > > > Read a bit further; there is an #else clause! This symbol is used to > > choose between two different implementations of the assert macro. In > > both cases, you have a macro named "assert". > > Sorry. I wrote this from memory and it seems it's pretty messed up (that > what you get when you're playing with 3 differents versions of cppunit > ;-(. ) I understand. I think you're still suffering from source code overload, however. > Is CPPUNIT_SOURCEANNOTATION really required ? The only reason I can see for > it would be that some weird compiler does not support the __FILE__ & > __LINE__ macros. Have anobody hear of something like that ? No, but then __FILE__ and __LINE__ is not the difference between the two assert() macros. #ifdef CPPUNIT_SOURCEANNOTATION #undef assert #define assert(condition)\ (CppUnit::TestAssert::assertImplementation ((condition),(#condition),\ __LINE__, __FILE__)) #else #undef assert #define assert(condition)\ (CppUnit::TestAssert::assertImplementation ((condition),"",\ __LINE__, __FILE__)) #endif The difference is the use of (#condition) in the first. That seems to make "condition" into a string. It's the first time I've seen this, so it wouldn't surprise me that some preprocessors don't understand it. On the other hand, it wouldn't surprise me to learn this has been in the C standard for 10 years. I try to use the preprocessor as little as possible. :-/ -S -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <bl...@cl...> - 2001-05-19 14:05:34
|
> On Wed, May 16, 2001 at 09:28:06PM +0200, Baptiste Lepilleur wrote: > > I would use a trait to add the object to the stream. The trait generic > > implementation would use '<<', but could be specialized when needed. > > That sounds like a reasonable idea. I'm not terribly experienced in > traits; what would be a good name for the function? Some of CppUnit > already uses "toString", which seems reasonable enough, yes? How about using specialized template function: template<class Type> std::string toString( Type &object ) { std::ostringstream stream; stream << object; return stream.str(); } template<class Type> bool equalsTo( Type &object1, Type &object2 ) { return object1 == object2; } // Example of specializations: struct MyObject { std::string print() { return "<MyObject>"; } }; template<> std::string toString<MyObject>( MyObject &object ) { return object.print(); } template<> bool equalsTo<MyObject>( MyObject &object1, MyObject &object2 ) { return &object1 == &object2; } I like that one because it solves the naming problem and you can change only the behavior you really need to change. Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Author of The Text Reformatter, a tool for fanfiction readers and writers. Language: English, French (Well, I'm French). |
From: Steve M. R. <ste...@vi...> - 2001-05-19 16:38:09
|
Hi Baptiste, First, thanks _so_ much for suggesting that an equality function be part of the assertion traits class. That's precisely what I needed yesterday! The brilliant point is that both equality and the string representation for a type can be different for assertions than it is for other code. The traits class I'm using looks like the following, which can easily be specialized. namespace CppUnit { template <class T> struct assertion_traits { static bool equal( const T& x, const T& y ) { return x == y; } static std::string toString( const T& x ) { ostringstream ost; ost << x; return ost.str(); } }; } On Sat, May 19, 2001 at 02:38:07PM +0200, Baptiste Lepilleur wrote: > > > > On Wed, May 16, 2001 at 09:28:06PM +0200, Baptiste Lepilleur wrote: > > > I would use a trait to add the object to the stream. The trait generic > > > implementation would use '<<', but could be specialized when needed. > > > > That sounds like a reasonable idea. I'm not terribly experienced in > > traits; what would be a good name for the function? Some of CppUnit > > already uses "toString", which seems reasonable enough, yes? > > How about using specialized template function: [...] > I like that one because it solves the naming problem and you can change only > the behavior you really need to change. That sounds like you want to do away with wrapping the functions in a common traits class. I see your point about being able to override each function individually. I'm not convinced that this outweighs the value of wrapping up the functions in a common name space, as a traits class does. I guess you could use a "traits namespace", instead. I'm not well-versed enough to know why classes are used over namespaces for traits. Maybe its historical? Or maybe it has something to do with being able to partially specialize a class template? I discovered the hard way that GCC does not allow default template parameters in templated functions, while it does allow them for templated classes. This leads me to suspect that templated classes are better supported than templated functions, and for this reason the former are used for traits. Comments? -Steve -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <bl...@cl...> - 2001-05-20 09:39:07
|
> The traits class I'm using looks like the following, which can easily > be specialized. > > namespace CppUnit { > > template <class T> > struct assertion_traits > > static bool equal( const T& x, const T& y ) > { > return x == y; > } > > static std::string toString( const T& x ) > { > ostringstream ost; shouldn't is be std::ostringstream ost; ? > ost << x; > return ost.str(); > } > }; > } Could you send the patch with the new assert/trait. I'd like to give it a try. > I guess you could use a "traits namespace", instead. I'm not > well-versed enough to know why classes are used over namespaces for > traits. Maybe its historical? Or maybe it has something to do with > being able to partially specialize a class template? I discovered the I think it has to do with the fact you can specify a traits as a template parameter type. I don't think you can to that with a namespace. This is a very powerful idiom. See this month online expert column by Andrei Alexandrescu on CUJ for pointer. > hard way that GCC does not allow default template parameters in > templated functions, while it does allow them for templated classes. > This leads me to suspect that templated classes are better supported > than templated functions, and for this reason the former are used > for traits. That's likely true. STL uses trait specialization, but I'm not sure it uses function specialization. Let's stick to traits for now, I don't think you need to override only one function that often. Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Author of The Text Reformatter, a tool for fanfiction readers and writers. Language: English, French (Well, I'm French). |
From: Steve M. R. <ste...@vi...> - 2001-05-20 16:23:19
|
On Sun, May 20, 2001 at 11:44:44AM +0200, Baptiste Lepilleur wrote: > > static std::string toString( const T& x ) > > { > > ostringstream ost; > shouldn't is be std::ostringstream ost; ? Yes, thanks. > Could you send the patch with the new assert/trait. I'd like to give it a > try. Here's what I'm currently using. Index: src/cppunit/Makefile.am =================================================================== RCS file: /cvsroot/cppunit/cppunit/src/cppunit/Makefile.am,v retrieving revision 1.4 diff -u -b -B -r1.4 Makefile.am --- src/cppunit/Makefile.am 2001/05/19 17:41:03 1.4 +++ src/cppunit/Makefile.am 2001/05/20 16:10:33 @@ -8,7 +8,6 @@ lib_LTLIBRARIES = libcppunit.la libcppunit_la_SOURCES = \ - TestAssert.cpp \ TestCase.cpp \ TestSuite.cpp \ TestResult.cpp \ Index: include/cppunit/TestAssert.h =================================================================== RCS file: /cvsroot/cppunit/cppunit/include/cppunit/TestAssert.h,v retrieving revision 1.2 diff -u -b -B -r1.2 TestAssert.h --- include/cppunit/TestAssert.h 2001/05/06 16:19:31 1.2 +++ include/cppunit/TestAssert.h 2001/05/20 16:10:33 @@ -2,10 +2,29 @@ #define CPPUNIT_TESTASSERT_H #include <string> +#include <sstream> #include <cppunit/Exception.h> + namespace CppUnit { + template <class T> + struct assertion_traits + { + static bool equal( const T& x, const T& y ) + { + return x == y; + } + + static std::string toString( const T& x ) + { + std::ostringstream ost; + ost << x; + return ost.str(); + } + }; + + /*! \brief This class represents */ class TestAssert @@ -17,24 +36,48 @@ bool condition, std::string conditionExpression = "", long lineNumber = Exception::UNKNOWNLINENUMBER, - std::string fileName = Exception::UNKNOWNFILENAME); + std::string fileName = Exception::UNKNOWNFILENAME) + { + if (!condition) + throw Exception (conditionExpression, + lineNumber, + fileName); + } + - static void assertEquals (long expected, - long actual, + template <class T> + static std::string notEqualsMessage (const T& expected, + const T& actual) + { + return "expected: " + assertion_traits<T>::toString(expected) + + " but was: " + assertion_traits<T>::toString(actual); + } + + + template <class T> + static void assertEquals ( + const T& expected, + const T& actual, long lineNumber = Exception::UNKNOWNLINENUMBER, - std::string fileName = Exception::UNKNOWNFILENAME); + std::string fileName = Exception::UNKNOWNFILENAME) + { + assertImplementation( assertion_traits<T>::equal(expected,actual), + notEqualsMessage(expected, actual), + lineNumber, + fileName); + } static void assertEquals (double expected, double actual, double delta, long lineNumber = Exception::UNKNOWNLINENUMBER, - std::string fileName = Exception::UNKNOWNFILENAME); - - static std::string notEqualsMessage (long expected, - long actual); - - static std::string notEqualsMessage (double expected, - double actual); + std::string fileName = Exception::UNKNOWNFILENAME) + { + assertImplementation( fabs(expected - actual) <= delta, + notEqualsMessage(expected, actual), + lineNumber, + fileName); + } }; @@ -69,6 +112,15 @@ /// Macro for primitive value comparisons #define assertLongsEqual(expected,actual)\ +(CppUnit::TestAssert::assertEquals ((expected),\ + (actual),__LINE__,__FILE__)) + +/// Generalized macro for primitive value comparisons +/** Any type that implements operator== and operator<< + * can be compared. A diagnostic is printed if the + * actual and expected values disagree. + */ +#define assertEqual(expected,actual)\ (CppUnit::TestAssert::assertEquals ((expected),\ (actual),__LINE__,__FILE__)) -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |