digitalmars.D.bugs - [Issue 17613] New: Inconsistent behaviour in code coverage
- via Digitalmars-d-bugs (117/117) Jul 06 2017 https://issues.dlang.org/show_bug.cgi?id=17613
https://issues.dlang.org/show_bug.cgi?id=17613 Issue ID: 17613 Summary: Inconsistent behaviour in code coverage Product: D Version: D2 Hardware: x86_64 OS: Linux Status: NEW Severity: normal Priority: P1 Component: dmd Assignee: nobody puremagic.com Reporter: hsteoh quickfur.ath.cx Reduced code: ------------ import std.stdio; struct MyFile { this(string filename) { } auto byLine() { return 0; } } struct Wrapper { this(Args...)(Args args) {} } auto func(F = std.stdio.File)(bool[] args) { import std.algorithm.iteration : map; foreach (x; args.map!(arg => arg ? Wrapper( F("A").byLine) : Wrapper( 0))) { } } void main() { import std.algorithm : each; func!MyFile([ true, false ]); func([ false ]); } ------------ Compile with dmd -unittest -cov, and run the program. Here is the obtained .lst file: ------------ |import std.stdio; |struct MyFile |{ 1| this(string filename) { } 1| auto byLine() { return 0; } |} |struct Wrapper |{ 3| this(Args...)(Args args) {} |} |auto func(F = std.stdio.File)(bool[] args) |{ | import std.algorithm.iteration : map; 17| foreach (x; args.map!(arg => arg ? Wrapper( 0000000| F("A").byLine) : 2| Wrapper( | 0))) | { } |} |void main() |{ | import std.algorithm : each; 1| func!MyFile([ true, false ]); 1| func([ false ]); |} util.d is 87% covered ------------ Note the line with 0000000. This is clearly wrong, because the first call to func!MyFile ought to have traversed both branches of the ?: operator, so F("A").byLine must have been invoked at least once. Now comment out the second call to func (func([ false ])), recompile, and run again. Here is the obtained .lst file: ------------ |import std.stdio; |struct MyFile |{ 1| this(string filename) { } 1| auto byLine() { return 0; } |} |struct Wrapper |{ 2| this(Args...)(Args args) {} |} |auto func(F = std.stdio.File)(bool[] args) |{ | import std.algorithm.iteration : map; 11| foreach (x; args.map!(arg => arg ? Wrapper( | F("A").byLine) : 1| Wrapper( | 0))) | { } |} |void main() |{ | import std.algorithm : each; 1| func!MyFile([ true, false ]); | //func([ false ]); |} util.d is 100% covered ------------ Note that the call to F("A").byLine is now *no longer part of the coverage count*. So here we have a paradoxical situation where decreasing code coverage (by not instantiating func with the default parameter for F) increases the reported code coverage to 100%. Note that defaulting F to std.stdio.File seems to be an essential part of this bug; I could not get rid of the reference to std.stdio.File without making the bug also vanish. (I tried declaring my own version of File in a different module and importing that, but that made the bug disappear.) Also, the odd formatting of the Wrapper lines are necessary to expose this bug; in the original, unreduced code, the lines were wrapped this way because the original code had longer lines that needed to be wrapped. However, wrapping lines should not affect the code coverage percentage(!). --
Jul 06 2017