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 -- MASM = Mana Ada Sistem, Man!