unittest blocks not being run inside of class and struct templates

Steven Schveighoffer via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Jul 25 06:31:28 PDT 2017


On 7/24/17 11:13 PM, NoBigDeal256 wrote:
> On Tuesday, 25 July 2017 at 02:18:41 UTC, Adam D. Ruppe wrote:
>> On Tuesday, 25 July 2017 at 02:11:20 UTC, NoBigDeal256 wrote:
>>> it passes when it should fail because the unittest block is never 
>>> executed. Why is this?
>>
>> Did you actually instantiate the class somewhere? A template has no 
>> concrete code unless created with an argument somewhere...
> 
> What if it's instantiated in another module? Right now I'm having issues 
> where if I run 'dmd a.d b.d -unittest' and the class template in b.d is 
> instantiated in a.d and it compiles and the tests inside my class 
> template run as they should, but when using 'dub test' the tests in my 
> class template don't run at all as if it isn't instantiated in a.d even 
> though it is. This is the original issue that I had that prompted me to 
> create this thread.

There is a whole can of worms to be dealt with if you put unit tests 
inside template classes or structs.

For instance:

struct Foo(T)
{
    T foo() { return T.init; }
    unittest
    {
        Foo!int f;
        assert(is(typeof(f.foo()) == int));
    }
}

the unit test is instantiated EVERY TIME Foo is instantiated, so if you 
have Foo!int and Foo!string both instantiated, BOTH will run this unit 
test. Obviously, there is no need to run both. And yes, user code will 
also add unit tests unwittingly to their code.

In some cases, this can be useful. If you write like this:

struct Foo(T)
{
    T foo() { return T.init; }
    unittest
    {
        Foo f; // note the lack of !
        assert(is(typeof(f.foo()) == T));
    }
}

This means that for every instantiation, the unit test is checking that 
Foo.foo returns T.

But this comes at a cost. Generally unit tests deal with concrete data, 
not abstract concepts. This means, you really only want to unit test for 
some instantiations, not all.

In phobos, I did this for RedBlackTree. It works well, in that test 
coverage is nearly complete over all integral types of elements. 
However, there are drawbacks:

1. RedBlackTree with -unittest *will* add unit tests to user modules 
(unavoidable).
2. There are some tricky mechanisms to make it work properly (see the code)
3. It comes back to bite me every once in a while, bugs are filed about 
this.

The unfortunate thing is that if you want to have non-templated unit 
tests, you have to put them outside the struct itself. This sucks for 
documented unit tests, and for tests being close to the thing being 
tested. I'd love to have a way to specify that a unit test is really 
outside the struct, but still have it written inside. I'm not sure if it 
would be accepted though.

-Steve


More information about the Digitalmars-d-learn mailing list