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