Is it possible to obtain textual representation of an arbitary code?
Oleksii Skidan
al.skidan at gmail.com
Fri Jan 26 14:43:49 UTC 2018
On Friday, 26 January 2018 at 13:05:26 UTC, Jonathan M Davis
wrote:
> 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:
>> >> [...]
>> >
>> > 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
I've just realized that I can actually make the test code more
pleasant if I use string concatenation. For example, this test:
```
unittest
{
import testing;
{
Particle a = Particle(0.9, 0);
Particle b = Particle(2.1, 0);
Constraint c = Constraint(a, b);
c.distance = 1f;
c.solve();
mixin(requireEq!q{1f, a.x});
mixin(requireEq!q{0f, a.y});
mixin(requireEq!q{2f, b.x});
mixin(requireEq!q{0f, b.y});
}
}
```
could be written as:
```
unittest
{
import testing;
{
Particle a = Particle(0.9, 0);
Particle b = Particle(2.1, 0);
Constraint c = Constraint(a, b);
c.distance = 1f;
c.solve();
mixin(
requireEq!q{1f, a.x} ~
requireEq!q{0f, a.y} ~
requireEq!q{2f, b.x} ~
requireEq!q{0f, b.y}
);
}
}
```
That code looks a little bit unusual, but I guess I can get used
to it. Seems like I can write a test scenario per mixin.
More information about the Digitalmars-d-learn
mailing list