Let's bikeshed std.experimental.testing assertions/checks/whatchamacallits

Atila Neves via Digitalmars-d digitalmars-d at puremagic.com
Wed Jul 1 01:40:23 PDT 2015


On Tuesday, 30 June 2015 at 08:06:37 UTC, Atila Neves wrote:
> In case you don't know what I'm talking about: 
> https://github.com/D-Programming-Language/phobos/pull/3207
>
> Since this is an API issue it's import to get it right the 
> first time. Personally I'm not sure what I prefer (well, I am, 
> but what I actually want isn't syntactically valid D). I think 
> the options so far are:
>
> 1) What's there already, namely `shouldEquals`, `shouldBeIn`, 
> etc.
> 2a) Compile-time strings for operators: `should!"=="`, 
> `should!"in"`
> 2b) Dicebot's `test!"=="`. `assert` is so much better, I wish 
> we could use that.
> 3) Composable ones: should.equals, should.not.equals, or 
> another word that isn't "should"
> 4) Anything else?
>
> I'm not convinced composability brings anything to the table 
> except for editor dot-completion. I don't like the verbosity of 
> what's there now, but my prefererred syntax doesn't work except 
> for the ubiquitous  check for equality (`should ==`). Well, the 
> dream would be that `assert(foo == bar)` did what part of this 
> PR does, but that's another story and something that can't be 
> done by a library unless we had AST macros, which we won't. Or 
> Lisp's reader macros, but we won't get those either.
>
> Thoughts? Votes?
>
> Atila

After much thinking and some _incredibly_ hacky attempts to come 
up with a library solution that can use operators (it was really 
hacky, I was using `assert()` and making the expression always 
return true), I came to the conclusion that what I have there 
already is probably as good as it's going to get bar language 
changes.

The reason is this: D has very smartly side-stepped C++'s 
problems with operator overloading and boilerplate by making 
things like `a >=b` be translated to `a.opCmp(b) >=0`. This is 
one of them Good Things. The same with `!=`, it's 
`!(a.opEquals(b)`. Again, good.

But for test asserts, that means that by the time any possible 
library code gets to handle it there's been a loss of 
information. There's so way to know whether opEquals was called 
with or without negation, or if opCmp was called because the user 
typed `>`, `>=`, `<` or `<=`.

I can make this work:

3.timesTwo.should == 6;
3.timesTwo.should.not == 5;


But anything with opCmp is a no-go. The only other operator that 
would make sense (to me) to overload is opBinary!("in"), but the 
naming there is a problem. `should.in`? `should.beIn`? Oh wait, 
that's not the operator anymore. Which brings me to...

Naming. Any one word that isn't `assert` is... not as good. It 
always breaks down for one use case or another, and I think 
what's in the PR is the best I've heard so far on this forum or 
in the comments. A compile-time string is... ugly and error-prone 
especially since the most common assertion is for equality and 
`!"=="` looks too much like `!=`. So, despite the fact that I 
wrote `shouldBeGreaterThan`, I hate its verbosity and all I 
really want to write is `assert(a > b)` and get a decent error 
message.

I don't buy that `should.` is more extensible. For two reasons, 
first because in all the test frameworks I've seen there aren't 
that many more types of assertions, and secondly because adding a 
member function to the struct returned by `should` and adding a 
new `shouldCamelCase` function is the same amount of work. As for 
auto-completion, I also see no real difference between the two.

Other than assert being semi-magical, I don't see how it can be 
any better.

Atila


More information about the Digitalmars-d mailing list