On 03/09/2012 08:29 PM, H. S. Teoh wrote:
On Fri, Mar 09, 2012 at 01:37:38PM -0500, Jonathan M Davis wrote:
On Friday, March 09, 2012 09:59:42 H. S. Teoh wrote:
[...]
This opens up the question of, what's the *recommended* way of
writing unittests that check for these sorts of stuff?
For example, I believe in being thorough in unit tests, so I like to
use them to verify that the complicated in-contract I just wrote
actually prevents the erroneous calls that I *think* it prevents.
But if catching AssertError's may leave the program in an undefined
state, then that pretty much invalidates any further testing past
that point (the program may appear to work when compiled with
-funittest but actually fail in release mode).
If you're testing that contracts throw when they're supposed to,
you're going to have to be very careful. Depending on what code is
involved, catching the AssertError could have no problems whatsoever.
For example
assertThrown!AssertError(func(5));
void func(int i)
in
{
assert(i == 2);
}
body
{}
wouldn't be a problem at all. There are no destructors, scope
statements, or finally blocks involved. But something like
assertThrown!AssertError(foo(5));
int foo(int i)
out(result)
{
assert(result = == 2);
}
body
{
Bar bar;
return i;
}
could have issues if Bar has a constructor than needs to run. You just
need to understand that destructors, scope statements, and finally
blocks are not guaranteed to be run if an Error is thrown and avoid
catching Errors in cases where they'd be skipped (or know enough about
the state that the program would be in if they _were_ skipped to know
that it's not going to cause problems).
Personally, I think that checking contracts is overkill, but you can
do it if you're careful.
[...]
Hmph. Well, then that defeats the purpose of checking contracts, because
checking contracts is only justifiable if it's complex enough, which
means that it's liable to involve things like dtors and scope
statements. It's silly to want to check a trivial contract like
assert(x>0);, because if something *that* simple can go wrong, then so
can the unittest, so you're not proving anything at all.
But this isn't that big a deal. One could argue that if a contract is
convoluted enough to warrant a unit test, then perhaps most (or all) of
its complexity should be factored out into a separate, unit tested
function, which is then just invoked from the contract.
(I find this a bit ironic, since TDPL states that the reason contracts
allow statements is so that complicated conditions can be tested for,
rather than being limited to just a single expression, as is the case in
most other languages that support DbC. Now it seems that simple
contracts are the way to go.)
T
Jonathan is just speculating. And I think he is wrong.