Почему kcov вычисляет неправильную статистику покрытия кода для программ Rust?

Я попытался использовать kcov, чтобы получить покрытие кода для библиотеки Rust. Я следил за этот учебник для создания и использования kcov. Покрытие, похоже, работает, однако я столкнулся с странным высоким охватом. Некоторые файлы в проекте получают 100% -ый охват, даже если они на самом деле не покрыты вообще!

Это минимальный проект, воспроизводящий проблему:

Cargo.toml

[package]
name = "mypackage"
version = "0.1.0"
authors = ["mbrt"]

SRC/lib.rs

pub mod subm;

pub fn coverage1(i : bool) -> bool {
    if i {
        true
    }
    else {
        false
    }
}

#[cfg(test)]
mod test {
    use super::coverage1;

    #[test]
    fn test_coverage1() {
        assert!(coverage1(true));
    }
}

SRC/subm.rs

pub fn coverage2(i : bool) -> bool {
    if i {
        true
    }
    else {
        false
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_coverage2() {
    }
}

Существуют две идентичные функции: одна в корневом ящике, другая - в подмодуле. Единственное отличие состоит в том, что первый тест стимулирует одну функцию, а другой вообще ничего не делает. В этом случае я ожидаю, что покрытие будет не более 50%.

Однако kcov сообщает об этом:

сводку покрытия

Покрытие для lib.rs верное:

coverage1

Но покрытие для subm.rs неверно! Обратите внимание, что функция является общедоступной, поэтому ее нельзя оптимизировать из библиотеки:

coverage2

Здесь мы можем проверить, что kcov работает, потому что он способен вычислять покрытие кода для одного файла, но он не может видеть, что второй файл вообще не покрывается.

В чем проблема? Может быть, тестовые двоичные файлы сбрасывают неиспользуемые функции, а kcov их не видит?

Ответ 1

Вы правы: полностью неиспользуемые функции на данный момент лишены, поэтому инструменты покрытия, такие как kcov, хороши только для охвата веток в рамках используемых функций (по крайней мере, сводная функциональность таких инструментов). Существует обсуждение о том, что это не происходит по умолчанию для сборки тестов/отладок.

Ответ 2

Существует обходное решение: переменная среды RUSTFLAGS='-C link-dead-code'. Используйте его при построении, а компилятор Rust свяжет также мертвый код:

RUSTFLAGS='-C link-dead-code' cargo test