cppunit-devel Mailing List for CppUnit - C++ port of JUnit (Page 46)
Brought to you by:
blep
You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
(21) |
May
(96) |
Jun
(109) |
Jul
(42) |
Aug
(6) |
Sep
(106) |
Oct
(60) |
Nov
(20) |
Dec
(6) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(7) |
Feb
(11) |
Mar
(49) |
Apr
(124) |
May
(30) |
Jun
(37) |
Jul
(53) |
Aug
(33) |
Sep
(21) |
Oct
(22) |
Nov
(19) |
Dec
(15) |
2003 |
Jan
(34) |
Feb
(25) |
Mar
(11) |
Apr
(12) |
May
(16) |
Jun
(24) |
Jul
(23) |
Aug
(23) |
Sep
(42) |
Oct
(7) |
Nov
(32) |
Dec
(33) |
2004 |
Jan
(41) |
Feb
(41) |
Mar
(24) |
Apr
(25) |
May
(18) |
Jun
(13) |
Jul
(11) |
Aug
(15) |
Sep
(22) |
Oct
(10) |
Nov
(15) |
Dec
(9) |
2005 |
Jan
(4) |
Feb
(15) |
Mar
(11) |
Apr
(16) |
May
(29) |
Jun
(17) |
Jul
(27) |
Aug
(12) |
Sep
(9) |
Oct
(10) |
Nov
(5) |
Dec
(6) |
2006 |
Jan
(2) |
Feb
(6) |
Mar
(7) |
Apr
(2) |
May
(1) |
Jun
(5) |
Jul
(8) |
Aug
(6) |
Sep
(10) |
Oct
(11) |
Nov
(15) |
Dec
(2) |
2007 |
Jan
(12) |
Feb
(22) |
Mar
(10) |
Apr
(7) |
May
(1) |
Jun
(8) |
Jul
(4) |
Aug
(1) |
Sep
(2) |
Oct
(1) |
Nov
|
Dec
|
2008 |
Jan
|
Feb
(7) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2009 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(7) |
Dec
|
2010 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
(1) |
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Bastiaan B. <bas...@li...> - 2001-10-22 20:51:39
|
Duane Murphy wrote: >--8<--- >(3) Use of references. While pointers are evil, references are your >friend. Const references are your best friend. They take up minimum >space, they have maximum reliability (they cant be NULL), you cant modify > Hmm, AFAIK references take as much space as pointers. I suspect most compilers translate references and pointers to the same code. They certainly CAN be *NULL (and you'll segfault if you try to use them). Personally I find having both pointers and references a not so elegant feature of C++. But I must confess to have built up a distaste for many C++ 'features' over the years and to prefer the simplicity of Java. Regards, Bastiaan Bakker |
From: Michael F. <mf...@mi...> - 2001-10-22 19:54:31
|
Java=20 =20 http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.h= tml# 9317 <http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.= html #9317> There are three kinds of reference types: class types (=A78) <http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html= #385 7> , interface types (=A79) <http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.h= tml# 238678> , and array types (=A710) <http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#= 2780 3> . =20 I would say Java is full of references. Michael Finney=20 Sun Certified Programmer for the Java 2 Platform=20 Sun Certified Developer for the Java 2 Platform=20 Cofounder of PPJDG - http://www.ppjdg.org <http://www.ppjdg.org/> =20 Cofounder of cosAgile - Colorado Springs XP Users Group - http://groups.yahoo.com/group/cosAgile <http://groups.yahoo.com/group/cosAgile> =20 <clip> Java has no references.=20 |
From: King D. <Ki...@tc...> - 2001-10-22 19:35:52
|
> Message: 3 > From: Duane Murphy <dua...@ma...> > To: CppUnit Developers <cpp...@li...> > Subject: Re: [Cppunit-devel] A new architecture ? > Date: Sun, 21 Oct 2001 23:30:32 -0700 > > I'll try and chime in with some thoughts of my own about what you have > written and my experiences with CppUnit. > > I agree with all of the points you make in your discussion > concerning the > architecture of CppUnit. I spent a number of years writing > Java and was a > bit disappointed to discover that CppUnit appeared to be, for > lack of a > better term, a port of JUnit. I dont know whether that's good > or bad. I > like C++ a lot and I feel that there are many things that can be done > better in C++. My opinion. Well CppUnit is in fact a port of JUnit. JUnit is a wonderful testing framework, but what works in Java does not necessarily work in C++ and vice versa. > I would like to hope that we can address a few items that make me > uncomfortable using CppUnit. I would be happy to work towards solving > some of these problems. > > (1) Too many pointers. I have found many places in the code > where objects > are constructed for no good reason. It almost struck me that > the author > somehow believed that the only way to get an object was to > use new(). In Java, of course, that is true. Since CppUnit is a port of Junit you will see lots of news. > (2) Const correctness. Most of the changes and additions I > have made to > my working copy of CppUnit fix const correctness. Just as I dont like > new() I dont like non-const objects. If an object is > non-const that means > I might change it without meaning to. If I want to change it > then I will > use a non-const object. There are several methods that are > clearly const > that are not labeled as such. Again a port of Java which does not have const. > (3) Use of references. While pointers are evil, references are your > friend. Const references are your best friend. They take up minimum > space, they have maximum reliability (they cant be NULL), you > cant modify > them without meaning to, and they are polymorphic. Excellent! Java has no references. > (4) Counted pointers. Sometimes you have to use pointers. If I have to > use pointers, I almost always use a counted pointer. I have a > class that > I use for my own work but that was because I wrote it before Boost. I > highly recommend using the boost class libraries > <http://www.boost.org> > especially the counted pointer library. Many of the other libraries > should also be examined for possible use. Why write it, when > you can just > use it. In general, I do not favor counted pointers, but in this case things are usually arranged in a tree, so loops are not an issue. > (5) C++ is not Java. There are many java'isms in the code. I probably > cant name them all two that I most recall are using new() > (see above) and > returning containers. If a class is modeling a container then > it should > model the container, not simply return its contents. Once again the Java'isms are expected. Of course that doesn't mean they should remain. > --- At Mon, 22 Oct 2001 00:02:55 -0400, Steve M. Robbins wrote: > > >Hello, > > > >So I spent some time yesterday thinking about the architecture of > >CppUnit, basically the same issues that I raised previously in two > >messages: > > > > http://www.geocrawler.com/archives/3/6780/2001/7/0/6126116/ > > http://www.geocrawler.com/archives/3/6780/2001/7/0/6126118/ > > > >In those messages, I tried to outline my understanding of the various > >classes in the current CppUnit. In the end, I concluded > that a lot of > >my difficulty in understanding CppUnit came from a couple of rather > >odd bits of system architecture. As one example, there is the class > >TestCase that is used in two different ways: it can be used to > >implement a single test case, or it can be used as a "fixture" to > >implement several test cases. In addition, there is the fact that a > >test case can be programmed to check for an "expected" exception if > >the case is constructed with TestCaller, but not if it is a direct > >subclass of TestCase. And there is the truly baroque > TestResult class > >that is very inflexible and heavy. I agree. > >I spent some time considering what a clean design would look > like, and > >then some more time actually coding it. There are two large > groups of > >classes needed for unit testing: classes to set up the tests, and > >classes to run them and capture the output. I thought about putting > >these two classes into separate namespaces, which I will tentatively > >call CppUnit::Test and CppUnit::Result. > > > > > > Test Construction Classes (CppUnit::Test) > > ----------------------------------------- > > > >I'll leave aside the assertions and the exception classes for > >the moment. Whic really need a rework as well. I really prefer JUnit where all the assert methods are defined as superclasses of the base Test class. The problem as always is how to get the file and line number info to those methods, so you end up creating nasty macros and to get lots of flexibility with them requires creating many macros with different names since you can't overload macros. > >The current design includes single test cases and suites of test > >cases, both of which implement a common interface. As Baptiste > >pointed out these are, respectively, the leaf, composite, and > >component classes of a "Composite Pattern". I propose to have three > >classes that serve the same purposes, all in CppUnit::Test > >namespace: > > > >Base - a pure virtual class that defines the interface > (i.e. the Component) > >Case - the leaf class that implements a *single* test case; > subclass of Base > >Suite - the composite component (also a subclass of Base), > consisting > > of a set of tests where a test could be any subclass of Base > > > >To these basic three -- each of which are fairly simple and > clean -- \ > >I also added the following. > > > >CaseWithException: a single test that requires that a specified > >exception is thrown. The class is templated on the exception > >type. > > > >FunctionAdaptor: takes a pointer to a "void foo(void)" function > >and turns it into a CppUnit::Test::Case object. I see no need to cater to someone not using OO. > >MethodAdaptor: takes a pointer to a "void foo(void)" class method > >and turns it into a CppUnit::Test::Case object. Which is the TestCaller class now. > >These three are all subclasses of CppUnit::Test::Case, so very little > >extra code is required. > > > > > >Using the MethodAdaptor and CaseWithException, I can easily implement > >the CPPUNIT_TEST_SUITE(), CPPUNIT_TEST(), CPPUNIT_TEST_EXCEPTION(), > >and CPPUNIT_TEST_SUITE_END() macros. The beauty of this scheme is > >that *any* class can contain a test suite. In the current scheme, I > >think that you can only use these macros in a subclass of > >CppUnit::TestCase. And with the FunctionAdaptor you can make test > >suites out of arbitrary global functions. One of the weaknesses of the macros right now is the difficulty in applying a TestDecorator to a test. I'd like to see that addressed. What makes things ugly is the use of macros everywhere. Unfortunately that seems hard to avoid because of the need to get file and line number passed around to tell where the error occurred. It would sure be nice to be able to generate a stack trace like in Java. > >So the test-definition side seems sufficiently flexible, at least > >to me :-). Have I missed something out? > > Test Result Classes (CppUnit::Result) > > ------------------------------------- > > > >To keep the code clean and flexible, I opted here to use the > composite > >pattern again. I used CppUnit::Result::Base for the interface class, > > > >class Base > >{ > >public: > > virtual ~Base() {}; > > > > //! Callback to indicate a test is about to start. > > virtual void startTest( CppUnit::Test::Base* test ) = 0; > > > > //! Callback to indicate that a failure has occurred. > > virtual void addFailure( CppUnit::Failure* failure ) = 0; > > > > //! Callback to indicate a test has just ended. > > virtual void endTest( CppUnit::Test::Base* test ) = 0; > >}; Some reason you want to drop the addError method? > >and CppUnit::Result::Group for the composite class. The latter is > >basically identical to the test suite class in that it contains > >a vector of pointers to result classes, and the callbacks are > >passed along to each result object in the group. > > > >There are a number of possible leaf classes. The simplest ones > >will just print the test progress to the screen. For example, > >here is one in the same vein as the CompilerOutputter classes > >recently added. This one is for emacs-compatible output. > > > > > >class EmacsOutput : public CppUnit::Result::Base > >{ > >public: > > void startTest( CppUnit::Test::Base* test ) {} > > > > void addFailure( CppUnit::Failure* failure ) > > { > > if ( failure->getSourceLine().isValid() ) { > > std::cerr << failure->getSourceLine().fileName() > > << ":" > > << failure->getSourceLine().lineNumber() > > << ":"; > > } else { > > std::cerr << "Error at unknown location:"; > > } > > > > std::cerr << failure->getMessage() > > << std::endl; > > }; > > > > void endTest( CppUnit::Test::Base* test ) > > {} > >}; > > > >It cannot get any simpler than this! Output for other IDEs will be > >similarly trivial. If you have a GUI running, then you can implement > >a leaf leaf class that updates the progress meter. Agreed on simpler architecture, except I don't see the need for the Group composite class. Basically the TestRunner is the composite class that has 0 or more TestListeners registered to listen for events. > >If you want to save the failures and generate a report at the > >end, then you just implement another leaf class that stores > >a copy of the failures received. > > > > > > What's Next > > ----------- > > > >I believe that the current functionality is available using > the simple > >classes outlined above. Those, plus the current assertion functions, > >exception class, and test registry classes. I haven't looked too > >carefully at the latter, however; perhaps there is room to simplify > >those also. > > > >There are two questions to consider. First, is it worth > reworking the > >foundations of CppUnit? Certainly, the gain in clarity is persuasive > >to me; how about the rest of you? Second, if we decide to go ahead > >with this, how much compability must be maintained? I agree that it should be done. Compatibility is not as big a concern as doing it right. -- Dale King |
From: Niel C. <nr...@tr...> - 2001-10-22 09:01:55
|
Hi, The cause of the failure isn't too hard to figure. To keep the description simple, imagine that the vtable for an object is implemented by the _vtbl data member. _vtbl points to the class specific vtable, which I'll call Class::class_vtbl. 1. the line "other = e;" causes the other._vtbl to be overwritten with exception::class_vtbl. 2. Hence when "other.what()" is called from within "checkIsSame", the routine exception::what() is run, not CppUnit::Exception::what() as expected. The problem seems to lie in the call to the compiler generated assignment operator for exception (exception::operator =). Ignoring self assignment, this routine first calls exception::~exception (destructor) followed by the compiler generated constructor (I can't tell if this is a default constructor or a copy constructor, only the latter really makes sense). The constructor writes this->_vtbl (which of course, it should). In principle, this algorithm for generating the assignment operator seems reasonable, although not really what I'd expect. Note that the implementation of CppUnit::Exception::operator = is not needed for this program, as C++ will do the "right thing" when assigning data members (it calls each member's assignment operator). Interestingly, commenting out CppUnit::Exception::operator = results in the same problem. The compiler generated assignment operator for CppUnit::Exception first calls exception::operator = (exactly the same as your original implementation), and then performs the assignments for each data member. Applying the same logic to CppUnit::Exception's copy constructor and commenting that out also still gives the same result. For some reason, the compiler generated exception::operator = is generated in a fundamentally different way to the CppUnit::Exception derived class. Obviously there's something very odd going on here. best regards, Niel Clausen. /\ Manor Court Yard, High Wycombe / \ /\ TRANSTECH Bucks, HP13 5RE, UK -/ \ / \^--------- Voice +44 1494 464432 \/ D S P Fax +44 1494 464472 nr...@tr... http://www.transtech-dsp.com |
From: Duane M. <dua...@ma...> - 2001-10-22 06:30:30
|
I'll try and chime in with some thoughts of my own about what you have written and my experiences with CppUnit. I agree with all of the points you make in your discussion concerning the architecture of CppUnit. I spent a number of years writing Java and was a bit disappointed to discover that CppUnit appeared to be, for lack of a better term, a port of JUnit. I dont know whether that's good or bad. I like C++ a lot and I feel that there are many things that can be done better in C++. My opinion. One question about your architecture that doesnt seem obvious to me is where is the test fixture? So far I have found the current architecture to be very heavy with test fixture. I have worked around it in ways that I believe conserve time and memory. However, the basic concept of setup() and tearDown() appear sound to me. How would one setup a test fixture with the new architecture. As might be hinted from my statements above, I think a rewrite should be considered. Backwards compatibility should be examined, but if this is taken as a major revision, we might be able to side step that requirement by simply making a version of 1.x available. Truthfully the architecture is not that complicated that converting tests shouldnt that much of a burden although we should get some user feedback on this. I would like to hope that we can address a few items that make me uncomfortable using CppUnit. I would be happy to work towards solving some of these problems. (1) Too many pointers. I have found many places in the code where objects are constructed for no good reason. It almost struck me that the author somehow believed that the only way to get an object was to use new(). I hate new(). new is my enemy. In my years of experience 90+% of programming errors are caused by new. I avoid new at all costs. Using new should be the final decision not the first. (2) Const correctness. Most of the changes and additions I have made to my working copy of CppUnit fix const correctness. Just as I dont like new() I dont like non-const objects. If an object is non-const that means I might change it without meaning to. If I want to change it then I will use a non-const object. There are several methods that are clearly const that are not labeled as such. (3) Use of references. While pointers are evil, references are your friend. Const references are your best friend. They take up minimum space, they have maximum reliability (they cant be NULL), you cant modify them without meaning to, and they are polymorphic. Excellent! (4) Counted pointers. Sometimes you have to use pointers. If I have to use pointers, I almost always use a counted pointer. I have a class that I use for my own work but that was because I wrote it before Boost. I highly recommend using the boost class libraries <http://www.boost.org> especially the counted pointer library. Many of the other libraries should also be examined for possible use. Why write it, when you can just use it. (5) C++ is not Java. There are many java'isms in the code. I probably cant name them all two that I most recall are using new() (see above) and returning containers. If a class is modeling a container then it should model the container, not simply return its contents. I dont mean for these items to be heavy handed. This is my experience writing and architecting C++ and then looking at CppUnit. These are just my opinions and I certainly am not running the show. I just wanted to express them. I will work toward the goals that are set for the group. I look forward to building a new and better CppUnit! ..Duane --- At Mon, 22 Oct 2001 00:02:55 -0400, Steve M. Robbins wrote: >Hello, > >So I spent some time yesterday thinking about the architecture of >CppUnit, basically the same issues that I raised previously in two >messages: > > http://www.geocrawler.com/archives/3/6780/2001/7/0/6126116/ > http://www.geocrawler.com/archives/3/6780/2001/7/0/6126118/ > >In those messages, I tried to outline my understanding of the various >classes in the current CppUnit. In the end, I concluded that a lot of >my difficulty in understanding CppUnit came from a couple of rather >odd bits of system architecture. As one example, there is the class >TestCase that is used in two different ways: it can be used to >implement a single test case, or it can be used as a "fixture" to >implement several test cases. In addition, there is the fact that a >test case can be programmed to check for an "expected" exception if >the case is constructed with TestCaller, but not if it is a direct >subclass of TestCase. And there is the truly baroque TestResult class >that is very inflexible and heavy. > >I spent some time considering what a clean design would look like, and >then some more time actually coding it. There are two large groups of >classes needed for unit testing: classes to set up the tests, and >classes to run them and capture the output. I thought about putting >these two classes into separate namespaces, which I will tentatively >call CppUnit::Test and CppUnit::Result. > > > Test Construction Classes (CppUnit::Test) > ----------------------------------------- > >I'll leave aside the assertions and the exception classes for >the moment. > >The current design includes single test cases and suites of test >cases, both of which implement a common interface. As Baptiste >pointed out these are, respectively, the leaf, composite, and >component classes of a "Composite Pattern". I propose to have three >classes that serve the same purposes, all in CppUnit::Test >namespace: > >Base - a pure virtual class that defines the interface (i.e. the Component) >Case - the leaf class that implements a *single* test case; subclass of Base >Suite - the composite component (also a subclass of Base), consisting > of a set of tests where a test could be any subclass of Base > >To these basic three -- each of which are fairly simple and clean -- \ >I also added the following. > >CaseWithException: a single test that requires that a specified >exception is thrown. The class is templated on the exception >type. > >FunctionAdaptor: takes a pointer to a "void foo(void)" function >and turns it into a CppUnit::Test::Case object. > >MethodAdaptor: takes a pointer to a "void foo(void)" class method >and turns it into a CppUnit::Test::Case object. > > >These three are all subclasses of CppUnit::Test::Case, so very little >extra code is required. > > >Using the MethodAdaptor and CaseWithException, I can easily implement >the CPPUNIT_TEST_SUITE(), CPPUNIT_TEST(), CPPUNIT_TEST_EXCEPTION(), >and CPPUNIT_TEST_SUITE_END() macros. The beauty of this scheme is >that *any* class can contain a test suite. In the current scheme, I >think that you can only use these macros in a subclass of >CppUnit::TestCase. And with the FunctionAdaptor you can make test >suites out of arbitrary global functions. > >So the test-definition side seems sufficiently flexible, at least >to me :-). Have I missed something out? > > > > Test Result Classes (CppUnit::Result) > ------------------------------------- > >To keep the code clean and flexible, I opted here to use the composite >pattern again. I used CppUnit::Result::Base for the interface class, > >class Base >{ >public: > virtual ~Base() {}; > > //! Callback to indicate a test is about to start. > virtual void startTest( CppUnit::Test::Base* test ) = 0; > > //! Callback to indicate that a failure has occurred. > virtual void addFailure( CppUnit::Failure* failure ) = 0; > > //! Callback to indicate a test has just ended. > virtual void endTest( CppUnit::Test::Base* test ) = 0; >}; > >and CppUnit::Result::Group for the composite class. The latter is >basically identical to the test suite class in that it contains >a vector of pointers to result classes, and the callbacks are >passed along to each result object in the group. > >There are a number of possible leaf classes. The simplest ones >will just print the test progress to the screen. For example, >here is one in the same vein as the CompilerOutputter classes >recently added. This one is for emacs-compatible output. > > >class EmacsOutput : public CppUnit::Result::Base >{ >public: > void startTest( CppUnit::Test::Base* test ) {} > > void addFailure( CppUnit::Failure* failure ) > { > if ( failure->getSourceLine().isValid() ) { > std::cerr << failure->getSourceLine().fileName() > << ":" > << failure->getSourceLine().lineNumber() > << ":"; > } else { > std::cerr << "Error at unknown location:"; > } > > std::cerr << failure->getMessage() > << std::endl; > }; > > void endTest( CppUnit::Test::Base* test ) > {} >}; > >It cannot get any simpler than this! Output for other IDEs will be >similarly trivial. If you have a GUI running, then you can implement >a leaf leaf class that updates the progress meter. > > >If you want to save the failures and generate a report at the >end, then you just implement another leaf class that stores >a copy of the failures received. > > > What's Next > ----------- > >I believe that the current functionality is available using the simple >classes outlined above. Those, plus the current assertion functions, >exception class, and test registry classes. I haven't looked too >carefully at the latter, however; perhaps there is room to simplify >those also. > >There are two questions to consider. First, is it worth reworking the >foundations of CppUnit? Certainly, the gain in clarity is persuasive >to me; how about the rest of you? Second, if we decide to go ahead >with this, how much compability must be maintained? > > >I have implemented the classes mentioned above along with the >CPPUNIT_TEST_SUITE() macros, and was able to use the macro-based test >suites previously written with no modifications. Since none of the >assertion macros had changed, my custom assertion_traits worked okay. >I did have to change my custom TestResult class, but since it was >customized precisely to put the output in emacs format, I can happily >change to the EmacsOutput class. ;-) > >My initial ambition was to reimplement completely the current Test, >TestCase, TestCaller, TestResult classes using the new classes. I >think that is a lot work and I'm not sure whether the gain is worth >it. It is straightforward to replace the TEST_SUITE macros with >equivalent ones using the new classes. So any tests that use the >macros alone will continue to function. What other techniques are in >use? Derivation of TestCase? Direct use of TestCaller and TestCase >subclass methods? How many are worth supporting? > > >At the moment, none of the code is in CVS. There are two reasons for >this. First, I'd like to see how people feel about pursuing this. >Second, I made a mistake in choosing the namespace CppUnit::Test. >Using that namespace will prevent it from coexisting with the old >CppUnit::Test class. Since I'd like, as much as possible, to >reimplement the old classes in terms of the new I'm going to change >the new classes to a different namespace. Perhaps CppUnit::Setup ? >Suggestions welcomed. |
From: Steve M. R. <ste...@vi...> - 2001-10-22 04:02:58
|
Hello, So I spent some time yesterday thinking about the architecture of CppUnit, basically the same issues that I raised previously in two messages: http://www.geocrawler.com/archives/3/6780/2001/7/0/6126116/ http://www.geocrawler.com/archives/3/6780/2001/7/0/6126118/ In those messages, I tried to outline my understanding of the various classes in the current CppUnit. In the end, I concluded that a lot of my difficulty in understanding CppUnit came from a couple of rather odd bits of system architecture. As one example, there is the class TestCase that is used in two different ways: it can be used to implement a single test case, or it can be used as a "fixture" to implement several test cases. In addition, there is the fact that a test case can be programmed to check for an "expected" exception if the case is constructed with TestCaller, but not if it is a direct subclass of TestCase. And there is the truly baroque TestResult class that is very inflexible and heavy. I spent some time considering what a clean design would look like, and then some more time actually coding it. There are two large groups of classes needed for unit testing: classes to set up the tests, and classes to run them and capture the output. I thought about putting these two classes into separate namespaces, which I will tentatively call CppUnit::Test and CppUnit::Result. Test Construction Classes (CppUnit::Test) ----------------------------------------- I'll leave aside the assertions and the exception classes for the moment. The current design includes single test cases and suites of test cases, both of which implement a common interface. As Baptiste pointed out these are, respectively, the leaf, composite, and component classes of a "Composite Pattern". I propose to have three classes that serve the same purposes, all in CppUnit::Test namespace: Base - a pure virtual class that defines the interface (i.e. the Component) Case - the leaf class that implements a *single* test case; subclass of Base Suite - the composite component (also a subclass of Base), consisting of a set of tests where a test could be any subclass of Base To these basic three -- each of which are fairly simple and clean -- \ I also added the following. CaseWithException: a single test that requires that a specified exception is thrown. The class is templated on the exception type. FunctionAdaptor: takes a pointer to a "void foo(void)" function and turns it into a CppUnit::Test::Case object. MethodAdaptor: takes a pointer to a "void foo(void)" class method and turns it into a CppUnit::Test::Case object. These three are all subclasses of CppUnit::Test::Case, so very little extra code is required. Using the MethodAdaptor and CaseWithException, I can easily implement the CPPUNIT_TEST_SUITE(), CPPUNIT_TEST(), CPPUNIT_TEST_EXCEPTION(), and CPPUNIT_TEST_SUITE_END() macros. The beauty of this scheme is that *any* class can contain a test suite. In the current scheme, I think that you can only use these macros in a subclass of CppUnit::TestCase. And with the FunctionAdaptor you can make test suites out of arbitrary global functions. So the test-definition side seems sufficiently flexible, at least to me :-). Have I missed something out? Test Result Classes (CppUnit::Result) ------------------------------------- To keep the code clean and flexible, I opted here to use the composite pattern again. I used CppUnit::Result::Base for the interface class, class Base { public: virtual ~Base() {}; //! Callback to indicate a test is about to start. virtual void startTest( CppUnit::Test::Base* test ) = 0; //! Callback to indicate that a failure has occurred. virtual void addFailure( CppUnit::Failure* failure ) = 0; //! Callback to indicate a test has just ended. virtual void endTest( CppUnit::Test::Base* test ) = 0; }; and CppUnit::Result::Group for the composite class. The latter is basically identical to the test suite class in that it contains a vector of pointers to result classes, and the callbacks are passed along to each result object in the group. There are a number of possible leaf classes. The simplest ones will just print the test progress to the screen. For example, here is one in the same vein as the CompilerOutputter classes recently added. This one is for emacs-compatible output. class EmacsOutput : public CppUnit::Result::Base { public: void startTest( CppUnit::Test::Base* test ) {} void addFailure( CppUnit::Failure* failure ) { if ( failure->getSourceLine().isValid() ) { std::cerr << failure->getSourceLine().fileName() << ":" << failure->getSourceLine().lineNumber() << ":"; } else { std::cerr << "Error at unknown location:"; } std::cerr << failure->getMessage() << std::endl; }; void endTest( CppUnit::Test::Base* test ) {} }; It cannot get any simpler than this! Output for other IDEs will be similarly trivial. If you have a GUI running, then you can implement a leaf leaf class that updates the progress meter. If you want to save the failures and generate a report at the end, then you just implement another leaf class that stores a copy of the failures received. What's Next ----------- I believe that the current functionality is available using the simple classes outlined above. Those, plus the current assertion functions, exception class, and test registry classes. I haven't looked too carefully at the latter, however; perhaps there is room to simplify those also. There are two questions to consider. First, is it worth reworking the foundations of CppUnit? Certainly, the gain in clarity is persuasive to me; how about the rest of you? Second, if we decide to go ahead with this, how much compability must be maintained? I have implemented the classes mentioned above along with the CPPUNIT_TEST_SUITE() macros, and was able to use the macro-based test suites previously written with no modifications. Since none of the assertion macros had changed, my custom assertion_traits worked okay. I did have to change my custom TestResult class, but since it was customized precisely to put the output in emacs format, I can happily change to the EmacsOutput class. ;-) My initial ambition was to reimplement completely the current Test, TestCase, TestCaller, TestResult classes using the new classes. I think that is a lot work and I'm not sure whether the gain is worth it. It is straightforward to replace the TEST_SUITE macros with equivalent ones using the new classes. So any tests that use the macros alone will continue to function. What other techniques are in use? Derivation of TestCase? Direct use of TestCaller and TestCase subclass methods? How many are worth supporting? At the moment, none of the code is in CVS. There are two reasons for this. First, I'd like to see how people feel about pursuing this. Second, I made a mistake in choosing the namespace CppUnit::Test. Using that namespace will prevent it from coexisting with the old CppUnit::Test class. Since I'd like, as much as possible, to reimplement the old classes in terms of the new I'm going to change the new classes to a different namespace. Perhaps CppUnit::Setup ? Suggestions welcomed. -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: Steve M. R. <ste...@vi...> - 2001-10-21 21:26:57
|
Just a note that a new (very minor update) to the stable branch was just put on sourceforge. In addition, I made a snapshot of the current CVS tree, and labelled it version 1.7.1. You can find it using http://cppunit.sourceforge.net/alpha/ As the URL indicates, this is an "alpha" release. Probably it is better (what do you think Baptiste?) to report bugs on this list, rather than the formal bug reporting scheme. -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: Steve M. R. <ste...@vi...> - 2001-10-20 17:34:35
|
Can someone with RogueWave confirm or refute this (that RogueWave chokes if <iostream> is used rather than <iostream.h>) ? -S ----- Forwarded message from no...@so... ----- To: no...@so... From: no...@so... Subject: [cppunit - Help] RE: I'm using cppUnit with Tools 7.1.1 Date: Thu, 11 Oct 2001 04:48:56 -0700 Read and respond to this message at: http://sourceforge.net/forum/message.php?msg_id=247259 By: dhallu I think the problem is that the CppUnit test framework relies on files like IOStream (without .h extension) whilst RogueWave relies on IOStream.h which seems to be part of the old standard. ______________________________________________________________________ You are receiving this email because you elected to monitor this forum. To stop monitoring this forum, login to SourceForge and visit: http://sourceforge.net/forum/monitor.php?forum_id=37108 ----- End forwarded message ----- -- 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-10-20 09:31:41
|
----- Original Message ----- From: "Steve M. Robbins" <ste...@vi...> To: "Cpp Unit Develpment Mailing List" <cpp...@li...> Sent: Friday, October 19, 2001 10:59 PM Subject: Re: [Cppunit-devel] Release 1.8.0 ? > On Fri, Oct 19, 2001 at 03:17:08PM +0200, Baptiste Lepilleur wrote: > > Quoting "Steve M. Robbins" <ste...@vi...>: [...] > OK. What I propose is to make a snapshot of the CVS tree, tag it > 1.7.0, and make it available as an "alpha" version. My suspicion is, > that aside from you, few people are using the CVS version (I'm not > using it, for instance). > > If I do that Sunday evening, will you have time to stabilize current > CVS? I fixed the what() throw() thing. There should also be 117 test running. Means that there is still some missing in the makefile. Sight... This time I did add the makefile to the VC project to update when I added file. Last time we found those missing file by building the dist. So, go ahead. --- 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-10-19 20:59:34
|
On Fri, Oct 19, 2001 at 03:17:08PM +0200, Baptiste Lepilleur wrote: > Quoting "Steve M. Robbins" <ste...@vi...>: > > > Hi all, > > > > I discovered that cppunit 1.6.1 won't install properly on a system > > that lacks "doxygen". So I started a 1.6 branch in CVS and committed > > the fix. I'll make a 1.6.2 release on the weekend if I get time. Is > > there anything else that ought to be addressed? I just found another bug today. SGI CC chokes without this patch: --- examples/cppunittest/TestSetUpTest.h 2001/06/11 19:56:23 1.1 +++ examples/cppunittest/TestSetUpTest.h 2001/10/19 20:45:01 @@ -26,7 +26,7 @@ { public: SetUp( CppUnit::Test *test ) : - TestSetUp( test ), + CppUnit::TestSetUp( test ), m_setUpCalled( false ), m_tearDownCalled( false ) { This will also go into 1.6.2. Anything else? > > On Mon, Oct 08, 2001 at 02:21:38PM +0200, Baptiste Lepilleur wrote: > We need to readd throw() to Exception::what(). I add mistakenly removed it > during my quest to find the Exception::operator =() problemon VC++, and forgot > to change it back. OK. What I propose is to make a snapshot of the CVS tree, tag it 1.7.0, and make it available as an "alpha" version. My suspicion is, that aside from you, few people are using the CVS version (I'm not using it, for instance). If I do that Sunday evening, will you have time to stabilize current CVS? > > > What do you think Steve ? > > > > I don't understand what you've done! :-) > > Which feature are you refering to ? All of them! It's my fault: I haven't been paying attention to cppunit until a couple of days ago. So I haven't gone through the several entries in the NEWS file to understand what has happened. > Your test runner proposition sound goods. My self, I found two kinds of user > for TestResult: > - Listeners, which provides dynamic feed back during the run (progress) > - Outputters, which print report based on the list of failures and run tests > (since they might print them in an order that don't match the run, grouping all > the sucessful tests together for example, they do their 'thing' after all the > tests have been run). Yes, that agrees with my experience. I might be tempted to call the latter category "reporters" or a test "summary" rather than "outputters". > > I'd really like to have this cleaned up for 1.8. And hopefully I'd be > > able to understand CppUnit well enough to write some documentation ... > > I can't see that done really quickly. So I would prefer to go for 1.8 > (release often), then tackle that issue. The CompilerOutputter and assertion > helper are so useful! I can't see how anybody can live without them ;-) Yes, you could be right. Still, I'd like to give it a week to see if we can get something done. If no progress happens before the end of next weekend, then we'll postpone it. How does that sound? -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: King D. <Ki...@tc...> - 2001-10-19 18:53:52
|
I submitted bug #472263 about an issue like the following: CPPUNIT_ASSERT_EQUAL( 255, longVariable ); This will not compile. The problem is that 255 is an int constant and therefore has a different type than the long variable. The implementation under the macro is a template method that expects the expected and actual to have the same type. Since they have different types it will not use the template method. One can make it work by making the constant a long constant by appending an L, but it would be nice to not require users to have to remember this. I was told that I should discuss this issue on the mailing list as it has come up before. Therefore here is my proposal for a fix. My proposal is to split the template method to have 2 class template parameters. In my proposal I will use Te and Ta for the expected type and the actual type. Replace them with better names. This entails doing the same to the assertion_traits template. In that case I would split out the toString stuff from the equals test as follows: template <class Te, class Ta> struct assertion_traits { static bool equal( const Te& x, const Ta& y ) { return x == y; } }; template <class T> struct assertion_tostring { static std::string toString( const T& x ) { OStringStream ost; ost << x; return ost.str(); } }; Then you change the template method as follows: template <class Te, class Ta> void assertEquals( const Te& expected, const Ta& actual, long lineNumber = Exception::UNKNOWNLINENUMBER, std::string fileName = Exception::UNKNOWNFILENAME ) { if ( !assertion_traits<Te,Ta>::equal(expected,actual) ) { assertNotEqualImplementation( assertion_tostring<Te>::toString(expected), assertion_tostring<Ta>::toString(actual), lineNumber, fileName ); } } You also have to change the toString stuff in the double version. That seems to solve the issue. This could probably be cleaned up further, but hopefully this gets the idea across. |
From: Baptiste L. <gai...@fr...> - 2001-10-19 13:17:12
|
Quoting "Steve M. Robbins" <ste...@vi...>: > Hi all, > > I discovered that cppunit 1.6.1 won't install properly on a system > that lacks "doxygen". So I started a 1.6 branch in CVS and committed > the fix. I'll make a 1.6.2 release on the weekend if I get time. Is > there anything else that ought to be addressed? > > To get the 1.6 branch, I'd suggest finding a clean spot and doing > a new checkout. You need to give the "-r BRANCH_1_6" option to > cvs: > > cvs -d xx...@cv...:/cvsroot/cppunit \ > checkout -r BRANCH_1_6 -d cppunit-1.6branch cppunit > > Remember that commits in that directory will go on the BRANCH_1_6 > branch, *not* on the main trunk. > > > > > On Mon, Oct 08, 2001 at 02:21:38PM +0200, Baptiste Lepilleur wrote: > > > Well, there a load of new stuffs... If everything is ok on the > > Unix side, we should try for the release, no ? > > Eh, well I can build it and "make check" reports no failures (104 > tests), so things look good on the unix side. That's only one > platform (Linux), mind you. Since we've recently run into problems > with Solaris compilers, it would be nice if a Solaris person would > test things out. > > Any takers? > > We could make a 1.7.0 tarball as a snapshot of the current development > tree -- would that help? We need to readd throw() to Exception::what(). I add mistakenly removed it during my quest to find the Exception::operator =() problemon VC++, and forgot to change it back. > > What do you think Steve ? > > I don't understand what you've done! :-) Which feature are you refering to ? > I'm getting a bit worried that the "test runner" stuff is getting out > of hand. Once upon a time I posted a sketch of how to rework the > classes to (in my view) drastically simplify the "runner" code and > make it trivial to implement output by writing a simple "listener" > class. See > > http://www.geocrawler.com/archives/3/6780/2001/7/0/6126118/ > > What do you think of the proposals contained therein? How have > your recent changes modified this? There is simplification, but some complexity have been "added" to stay backward compatible. I would go for only the following functionnality: - give me the list of the failures, - give me the list of testcase that has been run, - give me the number of tests run, - give me the number of failures. => before, TestResult stored two kinds of failures: failure and error. Because of this, there was a lot of code duplication in "user" code of TestResult. Now, failure kind is stored in TestFailure. > And there is also the issue of TestCaller versus fixtures, c.f. > the thread starting from > > http://www.geocrawler.com/archives/3/6780/2001/7/0/6126116/ Your test runner proposition sound goods. My self, I found two kinds of user for TestResult: - Listeners, which provides dynamic feed back during the run (progress) - Outputters, which print report based on the list of failures and run tests (since they might print them in an order that don't match the run, grouping all the sucessful tests together for example, they do their 'thing' after all the tests have been run). > I'd really like to have this cleaned up for 1.8. And hopefully I'd be > able to understand CppUnit well enough to write some documentation ... I can't see that done really quickly. So I would prefer to go for 1.8 (release often), then tackle that issue. The CompilerOutputter and assertion helper are so useful! I can't see how anybody can live without them ;-) Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-10-19 12:36:14
|
Quoting Gigi <gi...@mo...>: > Hi, > I downloaded CppUnit couple of days ago, and what bothered > me was that the TestRunner dialog was not resizable. > Another related problem is that the column widths of the > list view show almost nothing. And last thing is that the > window position is not persisted. I decided to solve this > problem and it turned out to be a nice little project. I > got a fully resizable dialog with all controls moving and > resizing accordingly, everything is persisted to the > registry including the column widths of list view. Great! > I'm no open source guy, and I know no CVS. I just want to > send my code to someone who will review it and integrate it > with the regular CppUnit dist. > > BTW, I must say that the code is highly organized and I > didn't encountered any dependencies or learning curve. I > just went here and there, read some code and modified what > I needed without disrupting anything else. Very good job of > separating logic from UI. It's not an easy thing to do in > MFC environment. *blush* Thanks! Send me (gai...@fr...) a zipped version of the source. I'll merge that using a 3-ways merge. It's a feature that I alway wanted to add, but never took the time to. I was thinking of a work around that I used in the Qt TestRunner: displaying the detail of a failure below the list of failures. In the list, only failure test name, and may be type would be shown. Baptiste. > > Keep up the good job, > Gigi > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Greg Z. <gr...@pa...> - 2001-10-19 08:14:26
|
Hi, In response to the faq question Why does the test ExceptionTest.testAssignment failed in CppUnit test suite? I don't know if anyone has responded to this bug yet but here is what I discovered. As best as I can tell when cppunit Excepiton::operator= calls SuperClass::operator= (which really is std::exception::operator=), the cppunit Exception object's vtable address is overwritten with that of std::exception's vtable address. So when you call the what() method (a call through the vtable since it is virtual), instead of calling cppunit Exception's what(), it calls std::exception's what. This returns the value stored in std::exception's _m_what member, which is "Unknown exception" (the default value). So either there is a bug in std::exception operator= or the compiler is not properly setting up the vtable when calling std::exception operator=. The copy constructor works fine. You can fix the bug by either - Don't have cppunit's class Exception inherit from std::exception and remove all use of std::exception. NOTE: I tried this and it worked fine. I.e. ExceptionTest.testAssignment passed. Not really sure why you are inheriting from std::exception since nothing in it is really used. or - Still have cppunit's class Exception inherit from std::exception and use it's _m_what member instead of cppunit Exception's m_message. You need to make these changes * add std::exception initialization to the following cppunit Exception constructor Exception::Exception( std::string message, long lineNumber, std::string fileName ) : std::exception ( message.c_str() ), <=== add this to initialize std::exception's _m_what member // m_message( message ), <== remove this not needed any more. using std::exception to hold the message m_lineNumber( lineNumber ), m_fileName( fileName ) { } * remove m_message and all it's uses * remove the what() method from exception.h and it's implementation from exception.cpp. You can still call what() as it will invoke std::exception::what() which will return the value in _m_what as a const char *. NOTE: I tried this and it worked fine. I.e. ExceptionTest.testAssignment passed. However, the problem with this is that the vtable address for cppunit Exception is wrong if operator= is ever called. Could lead to problems down the road. or - Leave everything as is and get MS to fix their bug. ~greg |
From: Steve M. R. <ste...@vi...> - 2001-10-19 01:59:19
|
Hi all, I discovered that cppunit 1.6.1 won't install properly on a system that lacks "doxygen". So I started a 1.6 branch in CVS and committed the fix. I'll make a 1.6.2 release on the weekend if I get time. Is there anything else that ought to be addressed? To get the 1.6 branch, I'd suggest finding a clean spot and doing a new checkout. You need to give the "-r BRANCH_1_6" option to cvs: cvs -d xx...@cv...:/cvsroot/cppunit \ checkout -r BRANCH_1_6 -d cppunit-1.6branch cppunit Remember that commits in that directory will go on the BRANCH_1_6 branch, *not* on the main trunk. On Mon, Oct 08, 2001 at 02:21:38PM +0200, Baptiste Lepilleur wrote: > Well, there a load of new stuffs... If everything is ok on the > Unix side, we should try for the release, no ? Eh, well I can build it and "make check" reports no failures (104 tests), so things look good on the unix side. That's only one platform (Linux), mind you. Since we've recently run into problems with Solaris compilers, it would be nice if a Solaris person would test things out. Any takers? We could make a 1.7.0 tarball as a snapshot of the current development tree -- would that help? > What do you think Steve ? I don't understand what you've done! :-) I'm getting a bit worried that the "test runner" stuff is getting out of hand. Once upon a time I posted a sketch of how to rework the classes to (in my view) drastically simplify the "runner" code and make it trivial to implement output by writing a simple "listener" class. See http://www.geocrawler.com/archives/3/6780/2001/7/0/6126118/ What do you think of the proposals contained therein? How have your recent changes modified this? And there is also the issue of TestCaller versus fixtures, c.f. the thread starting from http://www.geocrawler.com/archives/3/6780/2001/7/0/6126116/ I'd really like to have this cleaned up for 1.8. And hopefully I'd be able to understand CppUnit well enough to write some documentation ... On Fri, Oct 12, 2001 at 05:14:48PM +0200, Baptiste Lepilleur wrote: > > I contacted Ron, we are now referenced on: > > http://www.xprogramming.com/software.htm > > Which list "all" know Unit testing framework. Thanks for that! -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-10-16 10:06:47
|
This week-end I finally took the time to make a library out of the Qt TestRunner. I added it to CppUnit: src/qttestrunner include/cppunitui/qt examples/qt You must build cppunit core library before running TMAKE in the src/qttestrunner directory. Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-10-12 15:14:53
|
I contacted Ron, we are now referenced on: http://www.xprogramming.com/software.htm Which list "all" know Unit testing framework. Let me know if you feel that the describtion should be changed. Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-10-08 12:36:44
|
Quoting Baptiste Lepilleur <bl...@cl...>: It does raise an interesting point about testing in C++. Exception::operator = () test failed, but NotEqualException::operator =() test worked!!! NotEqualException compared the values in the same method where the object were declared, while Exception called an helper method to do the job, passing reference to the Exception objects. That means that in the case of NotEqualException, the compiler knew the actual type of the object and resolved the virtual method call statically. That same test would have failed if the comparison was done in an helper function, since std::exception::operator =() implementation is bugged, leading to a buggy implementation of Exception::operator =(). So we had a passing test that should have failed, but did not because the compiler optimized away the resolution of the virtual call. Disturbing, isn't it ? That does raise interesting question about testing components that subclass third party class. Baptiste. > Went one step further in that quest... > > When the std::exception::operator =() call the destructor and the > constructor to do the 'copy', the constructor reset the virtual table > back > to std::exception > virtual table. Therefore, the previous affectation to > CppUnit::Exception > virtual table is lost, and all call to any virtual function of > std::exception (what() is among them) will lead to a call to the > std::exception implementatin instead of the most derived class > implementation. > > I beleive this is a MSVC++ STL bug (I'll tell you, that stuff is pure > black > magic ;-) ). Has anyone heard of it ? > > Well, anyway I'll go for the simplest thing that could possibly work > and > comment out the call to std::exception::operator =() in > CppUnit::Exception::operator =() (no data from the base class are use > anyway). But at least, now we know what is going wrong ! > > And we finaly got to see the green bar =) > > Thanks Phil, > Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-10-08 12:21:42
|
Well, there a load of new stuffs... If everything is ok on the Unix side, we should try for the release, no ? What do you think Steve ? Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <bl...@cl...> - 2001-10-06 12:01:13
|
Well I've just added it. Some work need to be done to support g++. I'm thinking of creating a small hierarchy ( CompilerTestResutOutputter, GccTestResutOutputter and MsvcTestResutOutputter which override printFailureLocation() ), and introducing a factory method in the base class: defaultOutputter(). That method would return the 'right' instance (How do we do that ? config.h settings ?) Here is a example of output in the compiler window (after adding a post-build step: "$(TargetPath) -selftest", to cppunittest ) --------------------Configuration: CppUnitTestMain - Win32 Debug-------------------- Linking... Self test ............................................................................ ............................F............. g:\prg\vc\lib\cppunit\examples\cppunittest\xmltestresultoutputtertest.cpp(32 2) : Assertion Test name: XmlTestResultOutputterTest.testWriteXmlResultWithThreeFailureTwoErrorsAndTwo Sucess - Expected : <TestRun><FailedTests><FailedTest id="1"><Name> test1</Name><FailureType>Assertion</FailureType>failure1</Fa iledTest><FailedTest id="2"><Name>test2</Name><FailureType>E rror</FailureType>error1</FailedTest><FailedTest id="3"><Nam e>test3</Name><FailureType>Assertion</FailureType>failure2</ FailedTest><FailedTest id="4"><Name>test4</Name><FailureType >Assertion</FailureType>failure3</FailedTest><FailedTest id= "6"><Name>test6</Name><FailureType>Error</FailureType>error2 </FailedTest></FailedTests><SzucessfulTests><Test id="5"><Na me>test5</Name></Test><Test id="7"><Name>test7</Name></Test> </SucessfulTests><Statistics><Tests>7</Tests><FailuresTotal> 5</FailuresTotal><Errors>2</Errors><Failures>3</Failures></S tatistics></TestRun> - Actual : <TestRun><FailedTests><FailedTest id="1"><Name> test1</Name><FailureType>Assertion</FailureType>failure1</Fa iledTest><FailedTest id="2"><Name>test2</Name><FailureType>E rror</FailureType>error1</FailedTest><FailedTest id="3"><Nam e>test3</Name><FailureType>Assertion</FailureType>failure2</ FailedTest><FailedTest id="4"><Name>test4</Name><FailureType >Assertion</FailureType>failure3</FailedTest><FailedTest id= "6"><Name>test6</Name><FailureType>Error</FailureType>error2 </FailedTest></FailedTests><SucessfulTests><Test id="5"><Nam e>test5</Name></Test><Test id="7"><Name>test7</Name></Test>< /SucessfulTests><Statistics><Tests>7</Tests><FailuresTotal>5 </FailuresTotal><Errors>2</Errors><Failures>3</Failures></St atistics></TestRun> - differ at index: 496 expected: zucessfulTests><Test id="5" ><Name>test5</Name></Test><Test id="7"><Name>test7</Name></T est></SucessfulTests><Statistics><Tests>7</Tests><FailuresTo tal>5</FailuresTotal><Errors>2</Errors><Failures>3</Failures ></Statistics></TestRun> but was : ucessfulTests><Test id="5 "><Name>test5</Name></Test><Test id="7"><Name>test7</Name></ Test></SucessfulTests><Statistics><Tests>7</Tests><FailuresT otal>5</FailuresTotal><Errors>2</Errors><Failures>3</Failure s></Statistics></TestRun> Failures !!! Run: 117 Failure total: 1 Failures: 1 Errors: 0 Error executing g:\winnt\system32\cmd.exe. CppUnitTestMain.exe - 1 error(s), 0 warning(s) --- Great, ne ? 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: Baptiste L. <bl...@cl...> - 2001-10-06 10:15:21
|
Went one step further in that quest... When the std::exception::operator =() call the destructor and the constructor to do the 'copy', the constructor reset the virtual table back to std::exception virtual table. Therefore, the previous affectation to CppUnit::Exception virtual table is lost, and all call to any virtual function of std::exception (what() is among them) will lead to a call to the std::exception implementatin instead of the most derived class implementation. I beleive this is a MSVC++ STL bug (I'll tell you, that stuff is pure black magic ;-) ). Has anyone heard of it ? Well, anyway I'll go for the simplest thing that could possibly work and comment out the call to std::exception::operator =() in CppUnit::Exception::operator =() (no data from the base class are use anyway). But at least, now we know what is going wrong ! And we finaly got to see the green bar =) Thanks Phil, Baptiste. ----- Original Message ----- From: "Phil Taylor" <phi...@ts...> To: <cpp...@li...> Sent: Thursday, October 04, 2001 2:57 PM Subject: [Cppunit-devel] Partial answer: 2.3) Why does the test ExceptionTest.testAssignment failed in CppUnit test > The implementation of the assignment operator for std::exception in > MSVCRT seems to be cause of the problem. Comment out the > SuperClass::operator= (other) call in Exception::operator=(Exception&) > and the test now passes. > > Examination of MSVCRT disassembly yields some odd-looking (shortcut?) > behavior. It looks as though exception::operator=(exception&) resets > itself by calling its own destructor (memory is not freed) then calls > exception(exception&) to complete the assignment. > > I can't progress the problem any further at this time but the > information above may be of some assistance. > > Regards, > Phil > > > _______________________________________________ > Cppunit-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppunit-devel > |
From: Baptiste L. <bl...@cl...> - 2001-10-06 08:22:50
|
Thanks for pointing that out Phil. I went a little further, and while the operator =() does weird stuff it does the job. When checkIsSame() is called, members of the original and assigned exception are equal (m_message members that are used by CppUnit::Exception::what() have the same value). I tracked down the problem, and it occurs in checkIsSame(): void ExceptionTest::checkIsSame( CppUnit::Exception &e, CppUnit::Exception &other ) { std::string eWhat( e.what() ); std::string otherWhat( other.what() ); --- 004054DA mov esi,esp 004054DC lea eax,[ebp-38h] 004054DF push eax 004054E0 mov ecx,dword ptr [ebp+0Ch] 004054E3 mov edx,dword ptr [ecx] 004054E5 mov edi,esp 004054E7 mov ecx,dword ptr [ebp+0Ch] 004054EA call dword ptr [edx+4] // here std::exception::what() is called instead of CppUnit::Exception::what() which returns the m_message member. // The weird stuff is that e.what() does call CppUnit::Exception::what() correctly... --- CPPUNIT_ASSERT_EQUAL( eWhat, otherWhat ); CPPUNIT_ASSERT( e.sourceLine() == other.sourceLine() ); } No matter how I twist think around, for other, it is always std::exception::what() that is called ! // Inverting the order of initialisation doesn't change a thing... const char *otherWhat = other.what(); const char *eWhat = e.what(); CPPUNIT_ASSERT_EQUAL( std::string(eWhat), std::string(otherWhat) ); Any idea ? Baptiste. ----- Original Message ----- From: "Phil Taylor" <phi...@ts...> To: <cpp...@li...> Sent: Thursday, October 04, 2001 2:57 PM Subject: [Cppunit-devel] Partial answer: 2.3) Why does the test ExceptionTest.testAssignment failed in CppUnit test > The implementation of the assignment operator for std::exception in > MSVCRT seems to be cause of the problem. Comment out the > SuperClass::operator= (other) call in Exception::operator=(Exception&) > and the test now passes. > > Examination of MSVCRT disassembly yields some odd-looking (shortcut?) > behavior. It looks as though exception::operator=(exception&) resets > itself by calling its own destructor (memory is not freed) then calls > exception(exception&) to complete the assignment. > > I can't progress the problem any further at this time but the > information above may be of some assistance. > > Regards, > Phil > > > _______________________________________________ > Cppunit-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppunit-devel > |
From: Baptiste L. <bl...@cl...> - 2001-10-05 22:33:21
|
Done. The SourceLine make the code much cleaner and compact (isValid() instead of magic comparison to UNKNOWNNUMBER ;-). I updated CPPUNITTEST_ASSERT_XML_EQUAL to use that mecanism and it works well. Also added a few other stuffs that make life easier. Well, I can't think right anymore, so it's time for me to call it a day. Good night, Baptiste. ----- Original Message ----- From: "Baptiste Lepilleur" <gai...@fr...> To: "Steve M. Robbins" <ste...@vi...> Cc: "Cpp Unit Develpment Mailing List" <cpp...@li...> Sent: Friday, October 05, 2001 6:45 PM Subject: Re: [Cppunit-devel] Assertion, ASSERT_EQUAL & co... > Quoting "Steve M. Robbins" <ste...@vi...>: > > > Hey Baptiste, > > > > > > On Fri, Oct 05, 2001 at 02:30:36PM +0200, Baptiste Lepilleur wrote: > > > > > So, the path I wish to take is: > > > 1) propose a reasonable default ASSERT_EQUAL (to discuss later) > > > 2) provide all the tools for user to easily implement a new assert > > macro > > > > This sounds promising! > > > > > > > Here is the list of what a ASSERT macro typically do: > > > a) capture filename and line where the macro was expanded for easy > > > > > localisation of failure > > > b) throw an Exception if failure occurs. The Exception convey a > > message > > > describing the failure, and the location of the failure captured in > > (a). > > > > > > That means CppUnit should help the user with both step. At the > > current > > > time, it means relying on TestAssert::assertImplemention and a lot of > > passing > > > filename and line around as parameter. > > > > > > First I apply IntroduceParameterObject and create a SourceLine > > class that > > > contains the filename and the line, and a nice default constructor > > when those > > > are not available. Refactor all CppUnit to use SourceLine (Exception, > > > > > TestAssert) > > > > I like this idea. > > So do I! The thing hit me when I was writting the assertion for XML equality. > I wondered about capturing the location, and finally decided against it because > that would lead to a lot of code duplication. And I just though that just about > everyone had the same problem, and probably wrote a lot of code that qualify > as "duplication"... > > > > Introduce helper methods in TestAssert to factor out code that > > throw > > > exception for failure. > > > > OK, but anything that is called an "assertion" should involve testing > > a boolean value. A function that unconditionally throws an exception > > is not an assertion of anything, it is merely throwing an exception; > > such a function should not live in TestAssert. It could live in the > > Exception class, perhaps. > > Like you pointed out, TestAssert is probably not a good name. Those helper > method help to factor out the could produced by when writing asssertion. That > is: > - building the failure message > - constructing the exception object to carry the message and failure location > - throwing the exception object > - (optionaly) test an expression to conditionnaly throw the exception object > > Why make the condition check optional ? Because otherwise, you must build the > string even if not used. Computing those string can be costly, especially if > you do more than expected/was, by adding another statement pin pointing where > the difference is. Computing that difference can take some time. > > That helper would be some kind of facade. You don't need to bother yourself > with knowing how the exception classes works to use them (and you don't need to > include them). Manipulating CppUnit Exception is only for advanced usage > (subclassing exception to carry additional info (screen capture, timing...)). > > > > (That last one is not well refined yet, but it would be something > > like: > > > > > > void fail( std::string message, > > > SourceLine location = SourceLine() ); > > > > This sounds like "throw exception unconditionally" ? > Yes. Would usually be used after computing a message when you already are in > the "fail" branch. > > > > > > > > void failIf( bool shouldFail, > > > std::string message, > > > SourceLine location = SourceLine() ); > > > > This sounds like the replacement for the current > > "assertImplementation"? > > Yes. > > > If so, why not call it simply "assert"? > > The "C" assert macro from hell is still around... > > > > void failNotEqual( std::string expected, > > > std::string actual, > > > SourceLine location = SourceLine(), > > > std::string additionalMessage ="" ); > > > > > > void failNotEqual( bool shouldFail, > > > std::string expected, > > > std::string actual, > > > SourceLine location = SourceLine(), > > > std::string additionalMessage ="" ); > > > > I don't get these two. It seems like replacements for the current > > "assertEquals", except that you've simply moved the equality testing > > out of the assertion_traits and made it a parameter (of the second > > function). > > Somewhat. Those build a NotEqualException (which store both the > expected/actual value), and throw it if needed. The user don't have to bother > himself knowing that a NotEqualException is thrown, only that an exception will > be thrown. > > > If that is the aim, then what is being provided to the library > > user? It is construction of the exception message. So, how about > > thinking up common message constructors that one can use with the > > standard TestAssert::assert(): > > Noooo!!! Like I pointed out, it constructs and throw the RIGHT exception > type. For example, TextTestResult detect that it is an NotEqualException, and > outputs the actual and expected value on two distinct lines, and aligned for > easy comparison. Advanced TestRunner could even make a diff between the two > values and point out where the difference is! (Could have really used that > feature for XML equality. That's how I ended up adding the extra statement on > failure that pointed out the difference). > > [...] > > I really like the idea of providing small building blocks for writing > > custom assertions. I think the building blocks should be very small > > and very generic. Having five nearly-the-same-but-slightly-different > > methods leads to great confusion, at least in my mind. I think we > > should consider hard what building blocks the library should provide. > > > > I also wonder whether "TestAssert" is the best namespace for it. > > Probably not. How about AssertionHelper or FailureReporter or Asserter or ? > The main responsability of those functions being to construct and throw the > exception. The condition check is only provided because to factor the "if" out > of the user code. > > > -Steve > > > > P.S. Also, think about backwards compatibility. I know we are still > > "pre-alpha" so I don't mind breaking it, but if it doesn't cost too > > much, I'm in favour of being compatible. If nothing else, make notes > > about what is getting broken. > > Well, most of the interface to assertion is through macros. Their interface > won't change. Current methods could forward toward the new one (at least for > one or two releases). > > For now, I'll put the new code in Asserter. We'll rename when we got the > right name. > > I wrote down the current list of compatiblity break in NEWS. Let me know if > it need to be more detailed. I don't expect compatibility break for this, just > some "deprecated" methods. > > Also, another important point I noticed when refactoring the TestResult and > TextTestResult. I've splitted the output into a lot of small methods (some can > still be split), is that it incredibly enhance the reuse. Make all those l ittle > print methods virtual and it becomes very easy to customize your output. > > Baptiste. > > --- > Baptiste Lepilleur <gai...@fr...> > http://gaiacrtn.free.fr/index.html > Language: English, French > > _______________________________________________ > Cppunit-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppunit-devel > |
From: Baptiste L. <gai...@fr...> - 2001-10-05 17:02:40
|
Quoting Duane Murphy <dua...@ma...>: > --- At Fri, 5 Oct 2001 17:26:56 +0200, Baptiste Lepilleur wrote: > > >> > >> There is a problem with missing itoa() (not only) on Linux, gcc > >> version > >> 2.95.2. I have attached a fix. > > > > Thanks, I'll include that this evening. The baka I am completly > forgot to > >check if itoa was ANSI (aren't an ANSI equivalent anyway ?) (the question was 'aren't there'...) > > itoa() is most certainly not ANSI and there is no ANSI equivalent. Yup, was specific VC++ (at least that what the doc said when looked afterward). > > >- return ::itoa( value, buffer, 10 ); > >+ ::sprintf( buffer, "%d", value ); > > While this replacement is ANSI, its not really in keeping with the > rest > of the code style. The rest of the code is largely C++ standard > library. > Therefore the replacement should be something like the toString() > function in assertionTraits<>. Yes. I asked for an equivalent because OStringStream is the "heavy" canon. > Maybe that function should be brought out entirely and converted to a > toString template function instead: > > template <T> > std::string toString( const T& x ) > { > OStringStream ost; > ost << x; > return ost.str(); > } That would solve the local code duplication. Though I'm not sure if it is the right solution. I'm still playing the idea, but I'm considering introducing a CppUnit::String class. It would have helper for those comon conversion and supports both Unicode and ANSI in its interface (but would store everything as Unicode). This would make CppUnit full Unicode (at least for failure message). But the idea is still unclear about the interface of that string class... Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-10-05 16:45:34
|
Quoting "Steve M. Robbins" <ste...@vi...>: > Hey Baptiste, > > > On Fri, Oct 05, 2001 at 02:30:36PM +0200, Baptiste Lepilleur wrote: > > > So, the path I wish to take is: > > 1) propose a reasonable default ASSERT_EQUAL (to discuss later) > > 2) provide all the tools for user to easily implement a new assert > macro > > This sounds promising! > > > > Here is the list of what a ASSERT macro typically do: > > a) capture filename and line where the macro was expanded for easy > > > localisation of failure > > b) throw an Exception if failure occurs. The Exception convey a > message > > describing the failure, and the location of the failure captured in > (a). > > > > That means CppUnit should help the user with both step. At the > current > > time, it means relying on TestAssert::assertImplemention and a lot of > passing > > filename and line around as parameter. > > > > First I apply IntroduceParameterObject and create a SourceLine > class that > > contains the filename and the line, and a nice default constructor > when those > > are not available. Refactor all CppUnit to use SourceLine (Exception, > > > TestAssert) > > I like this idea. So do I! The thing hit me when I was writting the assertion for XML equality. I wondered about capturing the location, and finally decided against it because that would lead to a lot of code duplication. And I just though that just about everyone had the same problem, and probably wrote a lot of code that qualify as "duplication"... > > Introduce helper methods in TestAssert to factor out code that > throw > > exception for failure. > > OK, but anything that is called an "assertion" should involve testing > a boolean value. A function that unconditionally throws an exception > is not an assertion of anything, it is merely throwing an exception; > such a function should not live in TestAssert. It could live in the > Exception class, perhaps. Like you pointed out, TestAssert is probably not a good name. Those helper method help to factor out the could produced by when writing asssertion. That is: - building the failure message - constructing the exception object to carry the message and failure location - throwing the exception object - (optionaly) test an expression to conditionnaly throw the exception object Why make the condition check optional ? Because otherwise, you must build the string even if not used. Computing those string can be costly, especially if you do more than expected/was, by adding another statement pin pointing where the difference is. Computing that difference can take some time. That helper would be some kind of facade. You don't need to bother yourself with knowing how the exception classes works to use them (and you don't need to include them). Manipulating CppUnit Exception is only for advanced usage (subclassing exception to carry additional info (screen capture, timing...)). > > (That last one is not well refined yet, but it would be something > like: > > > > void fail( std::string message, > > SourceLine location = SourceLine() ); > > This sounds like "throw exception unconditionally" ? Yes. Would usually be used after computing a message when you already are in the "fail" branch. > > > > void failIf( bool shouldFail, > > std::string message, > > SourceLine location = SourceLine() ); > > This sounds like the replacement for the current > "assertImplementation"? Yes. > If so, why not call it simply "assert"? The "C" assert macro from hell is still around... > > void failNotEqual( std::string expected, > > std::string actual, > > SourceLine location = SourceLine(), > > std::string additionalMessage ="" ); > > > > void failNotEqual( bool shouldFail, > > std::string expected, > > std::string actual, > > SourceLine location = SourceLine(), > > std::string additionalMessage ="" ); > > I don't get these two. It seems like replacements for the current > "assertEquals", except that you've simply moved the equality testing > out of the assertion_traits and made it a parameter (of the second > function). Somewhat. Those build a NotEqualException (which store both the expected/actual value), and throw it if needed. The user don't have to bother himself knowing that a NotEqualException is thrown, only that an exception will be thrown. > If that is the aim, then what is being provided to the library > user? It is construction of the exception message. So, how about > thinking up common message constructors that one can use with the > standard TestAssert::assert(): Noooo!!! Like I pointed out, it constructs and throw the RIGHT exception type. For example, TextTestResult detect that it is an NotEqualException, and outputs the actual and expected value on two distinct lines, and aligned for easy comparison. Advanced TestRunner could even make a diff between the two values and point out where the difference is! (Could have really used that feature for XML equality. That's how I ended up adding the extra statement on failure that pointed out the difference). [...] > I really like the idea of providing small building blocks for writing > custom assertions. I think the building blocks should be very small > and very generic. Having five nearly-the-same-but-slightly-different > methods leads to great confusion, at least in my mind. I think we > should consider hard what building blocks the library should provide. > > I also wonder whether "TestAssert" is the best namespace for it. Probably not. How about AssertionHelper or FailureReporter or Asserter or ? The main responsability of those functions being to construct and throw the exception. The condition check is only provided because to factor the "if" out of the user code. > -Steve > > P.S. Also, think about backwards compatibility. I know we are still > "pre-alpha" so I don't mind breaking it, but if it doesn't cost too > much, I'm in favour of being compatible. If nothing else, make notes > about what is getting broken. Well, most of the interface to assertion is through macros. Their interface won't change. Current methods could forward toward the new one (at least for one or two releases). For now, I'll put the new code in Asserter. We'll rename when we got the right name. I wrote down the current list of compatiblity break in NEWS. Let me know if it need to be more detailed. I don't expect compatibility break for this, just some "deprecated" methods. Also, another important point I noticed when refactoring the TestResult and TextTestResult. I've splitted the output into a lot of small methods (some can still be split), is that it incredibly enhance the reuse. Make all those little print methods virtual and it becomes very easy to customize your output. Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |