www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 12269] New: Unittest within template struct scope is not executed

reply d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269

           Summary: Unittest within template struct scope is not executed
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: growlercab gmail.com


--- Comment #0 from growlercab gmail.com 2014-02-26 15:23:01 PST ---
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

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 26 2014
next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269



--- Comment #1 from growlercab gmail.com 2014-02-26 18:10:55 PST ---
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

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 26 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269


Andrej Mitrovic <andrej.mitrovich gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |andrej.mitrovich gmail.com


--- Comment #2 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2014-02-27
04:49:47 PST ---
It's by design. How would the unittest code know what to replace T with if you
don't instantiate the struct?

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 27 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269



--- Comment #3 from growlercab gmail.com 2014-02-27 18:12:29 PST ---
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

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 27 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269



--- Comment #4 from Andrej Mitrovic <andrej.mitrovich gmail.com> 2014-02-28
00:45:54 PST ---
(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 ----- -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Feb 28 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269



--- Comment #5 from growlercab gmail.com 2014-02-28 04:21:45 PST ---
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

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 28 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269


Vladimir Panteleev <thecybershadow gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |thecybershadow gmail.com
         Resolution|                            |INVALID


--- Comment #6 from Vladimir Panteleev <thecybershadow gmail.com> 2014-02-28
14:28:09 EET ---
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.

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 28 2014
prev sibling next sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269



--- Comment #7 from growlercab gmail.com 2014-02-28 05:21:40 PST ---
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

-- 
Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Feb 28 2014
prev sibling parent d-bugmail puremagic.com writes:
https://d.puremagic.com/issues/show_bug.cgi?id=12269



--- Comment #8 from Vladimir Panteleev <thecybershadow gmail.com> 2014-02-28
15:22:43 EET ---
(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). -- Configure issuemail: https://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Feb 28 2014