std.unittests for (final?) review
Jonathan M Davis
jmdavisProg at gmx.com
Thu Jan 6 08:34:48 PST 2011
On Thursday 06 January 2011 05:30:56 Michel Fortin wrote:
> There's an other issue that's bothering me with these assertion
> functions... with 'assert', assertions behaves differently depending on
> where you write them. In regular code, on failure it calls _d_assert*,
> in a unit test on failure it calls _d_unittest*, and in contracts for
> virtual function... well that case I don't understand it fully but it
> does something very special to implement contract inheritance.
>
> What does assertPred do? It does "throw new AssertError(...)",
> irrespective of the context. I'm pretty sure that'll break contract
> inheritance if used inside a contract. To be truly a replacement for
> assert, assertPred would need to know in which context it is called and
> generate the appropriate code, although I somewhat doubt it is even
> possible to generate the right code for contracts without the compiler
> doing it.
I don't know anything about this. As far as I know, there's no difference between
assert in unittest blocks and assert in contracts. That being said, you're
probably more knowledgeable than I am about that.
I would have thought was that all it would take would be for the AssertError to
be handled appropriately by whatever catches it. In the case of contracts, I
would think that it's an issue of the right contract code being called in the
right order, and that which contract threw the test would be irrelevant (the
stack track would show where it was; all that matters from the runtime's
perspective is that there _was_ an AssertError thrown and that execution is
therefore going to be stopping).
As for unittest blocks, I thought that it caught the AssertError from the
unittest block and dealt with it. If it does that, then I don't see why it would
need a special version of assert. I know that it _used_ to be different, because
Walter temporarily made it so that within unittest blocks assert set a flag
saying that the test failed and printed the error rather than throwing an
AssertError, but Andrei and others complained about that (both that assert would
have different behavior in different places and that a unittest block would
continue after a failure), and it was agreed that assert would throw an
AssertError like it normally does.
So, I don't know if assert does something different depending on where it is
called. The only special case for assert that I'm aware of is assert(0), which
becomes the halt instruction with -release rather than going away. If there is a
difference, then we probably need to understand what it is and what issues it
could cause. Ideally, there wouldn't be any difference.
However, I _have_ been using these functions in unit tests, and they work fine
there. So, as far as unit testing goes, they work. I have _not_ been using them
in contracts. I created them specifically with unit testing in mind (and in fact,
with the current code, the entire module is in a version(unittest) block). It
sounds like there are some folks (including Andrei) who think that it should be
useable in normal contracts just like assert is. That's simple to fix by removing
the version(unittest) block, but I don't know if there are any issues with
throwing an AssertError from a function called within a contract rather than
asserting directly inside a contract. If there is, I would think that that's a
more general problem. I've been doing that all the time with invariants (just
not with any of my unit testing functions), and that's worked as far as I can
tell, but I've been using structs primarily, which wouldn't have contract
inheritance. So, I think that assert should _definitely_ work normally when
called from a function called from a contract rather than when used directly in
a contract, but I don't know that that never causes problems. We need someone
who actually knows what assert does in each case to say whether there's an
issue, I think.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list