Bug 12269 – Unittest within template struct scope is not executed

Status
RESOLVED
Resolution
INVALID
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-02-26T15:23:00Z
Last change time
2014-02-28T05:22:43Z
Assigned to
nobody
Creator
growlercab

Comments

Comment #0 by growlercab — 2014-02-26T15:23:01Z
using: $ rdmd --main -unittest -debug utbug.d (also tried with just dmd but same result) --- import std.stdio; struct S(T) { T val; this(T v) {val=v;} unittest { // << UT-1 writeln("Here 1!"); auto s = S!int(10); assert(s.val == 1); // <<-- this should fail s=writeln("abcd"); // <<-- this should not compile } } // Uncomment to make the struct unittest run /* unittest { // << UT-2 writeln("Here 2"); auto s = S!int(10); assert(s.val == 10); }*/ --- If UT-2 is commented out the UT-1 unit test does not get compiled and executed. Only occurs with template struct, non-template S works as expected. I am running Arch Linux x86_64, dmd 2065. I have not tried to reproduce with other configurations. Thanks, ed
Comment #1 by growlercab — 2014-02-26T18:10:55Z
After some more testing I have some more information which may help. Firstly, the problem is also present in DMD 2.064. (I have no DMD older than this) Secondly, I found that the unittest within struct scope is run only if S is instantiated in a module scope unit test. For example the following incorrectly compiles and executes without an error: $ rdmd --main -unittest -debug utbug.d --- // utbug.d struct S(T) { unittest { BUGME("should not compile"); // <<-- should break the build } } unittest { } ---- But instantiating S!int() in the module scope unit test works as expected: $ rdmd --main -unittest -debug utbug.d utbug.d(5): Error: undefined identifier BUGME utbug.d(9): Error: template instance utbug.S!int error instantiating --- // utbug.d struct S(T) { unittest { BUGME("should not compile"); // <<-- Should break the build } } unittest { auto s = S!int(); } ---- Thanks, ed
Comment #2 by andrej.mitrovich — 2014-02-27T04:49:47Z
It's by design. How would the unittest code know what to replace T with if you don't instantiate the struct?
Comment #3 by growlercab — 2014-02-27T18:12:29Z
Thanks for the clarification. As I understand it this is the situation: Within a template unittests will be silently ignored by the compiler unless another unittest, outside the template scope, instantiates that template. Is it really a good idea? To treat unittests like regular functions w.r.t templates regarding how/when they're compiled. IMO all unittests should be lifted to module scope by the compiler, excepting static-if and version() blocks. This way there would be no unittests that are missed because a template was not instantiated. This all came about because someone elsewhere in the code removed an one line that instantiated S. We were blissfully unaware that most of out S unittests were not actually being compiled, let alone executed. A simple mistake but it happens. Thanks, ed
Comment #4 by andrej.mitrovich — 2014-02-28T00:45:54Z
(In reply to comment #3) > IMO all unittests should be lifted to module scope by the compiler, excepting > static-if and version() blocks. This way there would be no unittests that are > missed because a template was not instantiated. I don't think you're following me here, if you have: struct S(T) { T val; } It doesn't matter where you put the unittest, it cannot possibly know what to instantiate 'S' with. Here's an example of a unittest within a struct block that could be both compilable and non-compilable based on what S is instantiated with: ----- struct S(T) { T val; unittest { /// this will fail if 'T' is not int static assert(is(T == int)); } } alias S_Int = S!int; alias S_Float = S!float; // triggers compile-time failure -----
Comment #5 by growlercab — 2014-02-28T04:21:45Z
struct S(T) { T val; unittest { /// this will fail if 'T' is not int static assert(is(T == int)); } } alias S_Int = S!int; alias S_Float = S!float; // triggers compile-time failure --- Yes, I understand this and I'd expect the compile failure. I don't think it is a good idea to conditionally compile/execute unittests according to whether templates are instantiated, which is why I was saying they should not be treated as regular functions that are subject to template/struct/class scope. Of course that may raise other issues I haven't thought of...I'm not a compiler/language developer by any means :) Anyway, thanks for taking the time to look into this issue. It is only a minor problem due to my preferred unittest structure/workflow. I can work around it easily enough. Cheers, ed
Comment #6 by dlang-bugzilla — 2014-02-28T04:28:09Z
This is a clearly invalid issue. The compiler can't execute the unit test because it can't POSSIBLY know what to instantiate the template with. It's like asking someone to verify that a mathematical equation is sound, but leaving half of the variables as blanks. The compiler will generate a unit test for every unique instantiation of the template. This way, the unit test will effectively test every combination of parameters - out of those used in your program. There is no problem and no need to restructure any code, as long as you build your entire program with the -unittest switch, as opposed to separate modules that only contain template declarations without instantiating them.
Comment #7 by growlercab — 2014-02-28T05:21:40Z
The compiler can't execute the unit test because it can't POSSIBLY know what to instantiate the template with. It's like asking someone to verify that a mathematical equation is sound, but leaving half of the variables as blanks. --- No, I'm arguing the unittest should not be part of the equation as they are now relying on template parameters (when in template scope). A unittest should be forced to define all variables to test the equation with, irrespective of where it is defined. But it is minor and I may not be seeing the bigger picture here so I'll drop it and move on :D Thanks again, ed
Comment #8 by dlang-bugzilla — 2014-02-28T05:22:43Z
(In reply to comment #7) > A unittest should be forced to define all variables to test the equation with, > irrespective of where it is defined. But then that would break the current usage of unit tests within templates (to test each instantiation).