Scoverage: обеспечить 100% -ное покрытие ветвлений в "формально бесконечных" циклах while(true).

Следующий простой фрагмент кода содержит 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-loop, Scoverage (и, возможно, некоторые другие инструменты покрытия) будут жаловаться и вычислять только 75% покрытия филиала (потому что while считается точкой ветвления, а false ветка никогда не берется раньше return).

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

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

2 ответа

Решение

Просто заверните 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)
  }

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

@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 не имеет веток, поэтому ваш инструмент покрытия должен быть счастливым, и в качестве бонуса вам больше не нужно фиктивное исключение.

Другие вопросы по тегам