|
Boost : |
From: Gennadiy Rozental (gennadiy.rozental_at_[hidden])
Date: 2005-12-20 19:47:21
"Daniel James" <daniel_at_[hidden]> wrote in message
news:doa5fo$fd6$1_at_sea.gmane.org...
> 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.
No. This is not what a definition says.
> 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.
This is requirement for strong guarantee
> I'll try to give you an idea about what I'm doing. The example I gave
[...]
> 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;
> }
This is a correct way of structuring your tests. Don't mix basic and strong
test withing the same test case. TDD actually recommends to have separate
test case for every single assertion. And in this design you do not need to
know where exception was thrown from. It's possible that your class needs
to check different invariants depending on where the failure occur. Do NOT
do this within same test case. Use two - with different mocks throwing
exceptions in different locations and different invariants checks.
> 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.
This statement is self-conflicting or what the word.
> 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 gather you do invariants checks in destructor of your scope guard like
tester class. I don't think this is good idea to do anything smart in
destructors (with rare exceptions). I don't really see why is it better
then:
tester t(x)
try {
// test case body
}
catch(...) {
t.check_invariants();
throw;
}
Gennadiy
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk