Boost logo

Boost :

From: Daniel James (daniel_at_[hidden])
Date: 2005-12-20 18:52:05


Gennadiy Rozental wrote:
> To check basic ES you don't need to catch any exceptions. Framework will
> check that you do unwinding properly by making sure you are not leaking any
> resources.

That isn't exactly true. The class still needs to meet it's invariants.
For example, if an exception is thrown while rehashing a hash table, it
will probably be left with only some of its elements - so the test needs
to check that the size has been changed to match the decreased number of
elements. Of course, that's possible within your framework.

I'll try to give you an idea about what I'm doing. The example I gave
was that a single element insert has the strong guarantee unless an
exception was thrown from the hash object. My current way of testing
this is something like:

     unordered_set<test::mock_object,
         test::hash, test::equal, test::allocator> x;

     unordered_strong_test tester(x);
     try {
         x.insert(1);
     }
     catch(hash_exception) {
         throw;
     }
     catch(...) {
         tester.test();
         throw;
     }

'strong_test' is a class which stores several details about x to be
check that they haven't changed.

An alternative way of doing this would be something like:

     unordered_strong_test tester(x);
     try {
         x.insert(1);
     }
     catch(...) {
         if(thrown_from_scope("hash"))
             tester.test();
         throw;
     }

Which I think I prefer as it's a bit more flexible. I think this is
possible within your framework, although not really supported?

Another version would be to have two separate tests, the first to test
for basic safety:

     unordered_set<test::mock_object,
         test::hash, test::equal, test::allocator> x;
     x.insert(1);

and one to test for strong safety, with a non-throwing hash:

     boost::unordered_set<test::mock_object,
         test::hash_nothrow, test::equal, test::allocator> x;
     unordered_strong_test tester(x);
     try {
         x.insert(1);
     } catch(...) {
         tester.test();
         throw;
     }

Incidently, my tests aren't actually written like this.
unordered_strong_test works more like a scope guard, something like:

     unordered_strong_test tester(x);
     try {
         x.insert(1);
         tester.dismiss();
     }
     catch(hash_exception) {
         tester.dismiss();
         throw;
     }

I also have a similar class which tests the class invariants - in order
to test basic exception safety. It doesn't have a 'dismiss' method as I
want to run the test regardless. This is why I would like to be able to
use BOOST_CHECK in the destructor, but that's more of a convenience than
anything.

I hope that makes things clearer...

Daniel


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk