On Friday, January 26, 2018 12:30:03 Oleksii Skidan via Digitalmars-d-learn 
wrote:
> On Friday, 26 January 2018 at 11:32:42 UTC, Mike Parker wrote:
> > On Friday, 26 January 2018 at 11:18:21 UTC, Oleksii Skidan
> >
> > wrote:
> >> I could imagine a mixin-based solution in D:
> >> ```d
> >> // Usage:
> >> ASSERT!"a == b";
> >> ```
> >> But it seems a bit alien to me. First of all, it kind of
> >> stringly-typed one. Secondly, neither IDEs nor advanced text
> >> editors are able to figure out that the string contains actual
> >> D code, and so neither syntax highlighting nor code assistance
> >> work with this approach.
> >
> > Token strings are intended for this and editors *should*
> > highlight them (don't know if any currently do):
> >
> > https://dlang.org/spec/lex.html#token_strings
>
> Seems like I have to add some context into this conversation: I'm
> writing a poor man's testing framework, since it's the best and
> easiest way to learn D ;-)
>
> I'm trying to achieve something similar to
> `Catch2``REQUIRE`macro. To be honest, I did not know about toking
> strings until today, and I don't know D much. Here's what I came
> up with so far:
>
> ```d
> string require(string expr)(string file = __FILE__, int line =
> __LINE__)
> {
>      import std.array, std.conv;
>      return q{
>          if (!($expr)) {
>              import std.stdio;
>              writeln("Test failed @", `$file`, ":", $line, "\n",
>                      "  Expected: `", `$expr`, "` to be
> `true`.\n");
>          }
>      }.replace("$expr", expr)
>       .replace("$file", file)
>       .replace("$line", to!string(line));
> }
>
> ```
>
> That code snippet uses token strings to compose an if statement
> that basically checks whether the given condition holds. That
> looks okay-ish to me, the usage of that function is not pretty
> though:
>
> ```d
> unittest
> {
>      mixin(require!q{false}); // This test will fail.
> }
> ```
>
> It would be awesome if I could write something like the this
> instead:
>
> ```d
> unittest
> {
>      require!q{false};
> }
> ```
>
> At first glance it seems like I could have moved the `mixin`
> statement into the `require` function itself, but that would not
> really work. Consider the following snippet:
>
> ```d
> unittest
> {
>      float value = 3f;
>      require!q{value == 3f}; // This line won't compile.
> }
> ```
>
> That code won't even compile, since `value` exists in `unittest`
> scope, which is not visible to the `require` function.

Why are you using strings for any of this? Printing out the expression is
kind of pointless. If you have the file and line number (which an
AssertError will give you), then you know where the failure is, and you can
see the expression. All of this extra machinery is just going to increase
your compile times for no benefit. So, what you're doing here is objectively
worse than just using assertions.

There might be some value if you had something like

assertEqual(lhs, rhs);

and then on failure, you printed the values that were being compared, since
that's not necessarily information that's in the code, but the expressions
themselves _are_ already in the code, so printing them out doesn't help any.

But even if you have helper functions that take the values separately so
that they can be printed, in my experience, the extra template
instantiations required to use helper functions like that everywhere in unit
tests increases the compilation times (and memory required) enough that it's
not worth it, especially when you consider that once the tests are passing,
all of that extra machinery does you no good whatsoever. Ultimately, it just
costs less to temporarily make an adjustment to the test and rerun it if you
need more information.

If you don't think that simply using assertions for unit tests is good
enough, then I'd suggest that you look at
https://code.dlang.org/packages/unit-threaded

- Jonathan M Davis

Reply via email to