Scoverage: обеспечить 100% -ное покрытие ветвлений в «формально бесконечных» циклах while (true). - PullRequest
0 голосов
/ 28 сентября 2018

Следующий простой фрагмент кода содержит while -петл, который выглядит так, как будто он может быть бесконечным:

  def findDivisor(n: Int): Int = {
    require(n >= 2)
    var i = 2
    while (true) {
      if (n % i == 0) {
        return i
      } else {
        // do-nothing branch
      }
      i += 1
    }
    // $COVERAGE-OFF$
    throw new Error("unreachable")
    // $COVERAGE-ON$
  }

Базовая математика гарантирует, что этот метод всегда завершается (даже если он не может найти правильный делитель, он должен останавливаться на n).

Несмотря на $COVERAGE-OFF$ сразу после while -цикла, Scoverage (и, возможно, некоторые другие инструменты покрытия) будут жаловаться и вычислять только 75% покрытия филиала (поскольку while считается точкой ветвления, а ветвь false никогда не берется до return).

Перемещение // $COVERAGE-OFF$ вокруг, например, перед закрытием } whileТело тоже не помогает.

Как заставить его игнорировать невозможную ветвь?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Я бы сказал, что вместо работы с компилятором вы предоставляете свой код в терминах, понятных компилятору.Компилятор понимает бесконечную рекурсию.

@tailrec def forever(op: => Unit): Nothing = {
  op
  forever(op)
}

def findDivisor(n: Int): Int = {
  require(n >= 2)
  var i = 2
  forever {
    if (n % i == 0) {
      return i
    } else {
      // do-nothing branch
    }
    i += 1
  }
}

forever не имеет ветвей, поэтому ваш инструмент покрытия должен быть счастливым, и в качестве бонуса вам больше не нужно фиктивное исключение.

0 голосов
/ 28 сентября 2018

Просто оберните голову цикла while(true) { в отдельную пару комментариев $COVERAGE-OFF$ - $COVERAGE-ON$:

  def findDivisor(n: Int): Int = {
    require(n >= 2)
    var i = 2
    // $COVERAGE-OFF$
    while (true) {
      // $COVERAGE-ON$
      if (n % i == 0) {
        return i
      } else {
        // do-nothing branch
      }
      i += 1
      // $COVERAGE-OFF$
    }
    throw new Error("unreachable")
    // $COVERAGE-ON$
  }

Теперь Scoverage гарантирует, что каждое утверждение в теле while -цикл покрыт, но он игнорирует false -отрасль и сообщает 100% покрытие теста, например, после следующего простого теста:

  "Whatever" should "do something" in {
    MyObjectName.findDivisor(57) should be(3)
  }
...