3

Hello fellow overflowers,

I'm working on a Swift class whose initializer contains a for loop that runs a certain amount of times according to a parameter of the init. Unfortunately, I cannot show you the exact code, but it's similar to this:

init(numberOfTimes: Int) {
    ...
    for index in 0..<numberOfTimes {
        // do some stuff here
        // shows 0 coverage
    }
    ...
}

I have several unit tests for this initializer, running the for loop between 0 and 5 times. The tests pass, yet code coverage always marks the inside of the loop as not covered, even though it clearly runs — I can breakpoint inside the loop and every function called in the loop shows as covered.

Furthermore, if I extract the contents of the for loop, the code does appear covered and the overall code coverage of the class increased by nearly 20%:

init(numberOfTimes: Int) {
    ...
    for index in 0..<numberOfTimes {
        doOne(index)
        // this part still shows 0 coverage
    }
    ...
}

private func doOne(_ index: Int) {
    // do same things here
    // shows correct coverage
}

Why does this happen? Am I not meeting the correct criteria for code coverage inside the for loop?

RenanGreca
  • 63
  • 4
  • 1
    I think it's a bug with initializers. I had an `if` statement inside of a `convenience init` in an extension of `UIColor`, the body of which was clearly running during tests but still showed 0 coverage. – Paolo May 07 '18 at 18:16

1 Answers1

2

I believe this might be the bug you are talking about:

https://bugs.swift.org/browse/SR-7446

Since upgrading to Xcode 9.3/Swift 4.1, I noticed that code coverage percentage dropped in several of my projects.

The bug seems to occur when I use conditional code within an initializer...

Which was fixed in:

https://github.com/apple/swift/pull/15966

This scheme of using a designated constructor for profiling purposes is a bit brittle. One concrete issue with this is that swift ends up attempting to create distinct SILProfilers for different constructors of a nominal type, and stored property initializers we want coverage for may not be emitted in the designated constructor.

A simpler idea is to store a map from nominal types to SILProfilers, and to then create a single merged profiler instance for all constructors of a nominal type.

R.B.
  • 422
  • 4
  • 10