t27.aiEnglish

Покрытие лжёт

Вы научитесь

Почему процент покрытия бывает проверкой, которая ничего не проверила, и как это распознать.

Процент покрытия — заявление о тестах, и заявления бывают пустыми. Виджет нашёл пустой вид: 11 spec отвергнуты на разборе, 0 заблокированы только прозой, и 23 сломаны нарочно как фикстуры — но где-то ещё в корпусе «тест», являющийся только прозой, проходит все проверки, ничего не исполняя. Приметы всегда одни: число без знаменателя, проход без исполнившегося ассерта, прогон, который не может упасть. Спрашивайте с каждого процента: что сдвинуло бы это число?

Попробуйте

В прогоне по прозе найдите разницу между «отвергнут на разборе» и «заблокирован только прозой»; затем напишите тест, чей проход не исполняет ни одного ассерта.

Открыть интерактивный урок →

tri prose report: prose, or code?
tri prose report: prose, or code? ↗

11 specs refused at parse, 0 blocked only by prose, 23 broken on purpose as fixtures.

specs/fpga/testbench/fifo_tb.t27

// FIFO testbench spec
// This spec exercises a small synchronous FIFO with a power-of-two depth.
// It provides write/read helpers, a combined transaction function,
// and a set of tests covering basic operation, edge cases, and invariants.

const DEPTH : u32 = 8;

struct Fifo {
    mem : [DEPTH]u32,
    head : u32,
    tail : u32,
    fill_count : u32,
}

var fifo : Fifo = Fifo {
    mem = [0, 0, 0, 0, 0, 0, 0, 0],
    head = 0,
    tail = 0,
    fill_count = 0,
};

var wr_en : bool = false;
var rd_en : bool = false;
var wr_data : u32 = 0;
var rd_data : u32 = 0;

fn reset() {
    fifo.head = 0;
    fifo.tail = 0;
    fifo.fill_count = 0;
    wr_en = false;
    rd_en = false;
    wr_data = 0;
    rd_data = 0;
}

fn tick() {
    if wr_en && !rd_en && !full() {
        fifo.mem[fifo.tail] = wr_data;
        fifo.tail = (fifo.tail + 1) % DEPTH;
        fifo.fill_count = fifo.fill_count + 1;
    } else if rd_en && !wr_en && !empty() {
        rd_data = fifo.mem[fifo.head];
        fifo.head = (fifo.head + 1) % DEPTH;
        fifo.fill_count = fifo.fill_count - 1;
    } else if wr_en && rd_en {
        if !full() && !empty() {
            rd_data = fifo.mem[fifo.head];
            fifo.mem[fifo.tail] = wr_data;
            fifo.head = (fifo.head + 1) % DEPTH;
            fifo.tail = (fifo.tail + 1) % DEPTH;
        } else if !full() && empty() {
            fifo.mem[fifo.tail] = wr_data;
            fifo.tail = (fifo.tail + 1) % DEPTH;
            fifo.fill_count = fifo.fill_count + 1;
        } else if full() && !empty() {
            rd_data = fifo.mem[fifo.head];
            fifo.head = (fifo.head + 1) % DEPTH;
            fifo.fill_count = fifo.fill_count - 1;
        }
    }
    wr_en = false;
    rd_en = false;
}

fn full() -> bool {
    return fifo.fill_count == DEPTH;
}

fn empty() -> bool {
    return fifo.fill_count == 0;
}

fn write_word(data : u32) -> bool {
    if full() {
        return false;
    }
    wr_en = true;
    wr_data = data;
    tick();
    wr_en = false;
    return true;
}

fn read_word() -> u32 {
    if empty() {
        return 0xFFFF;
    }
    rd_en = true;
    tick();
    rd_en = false;
    return rd_data;
}

fn on_comb(data: u32) -> bool {
    return write_word(data);
}

test test_basic_write {
    reset();
    var ok = write_word(0xDEAD);
    assert ok == true;
    assert fifo.fill_count == 1;
}

test test_basic_read {
    reset();
    write_word(0xBEEF);
    var data = read_word();
    assert data == 0xBEEF;
    assert fifo.fill_count == 0;
}

test test_full_after_writes {
    reset();
    var i = 0;
    while i < DEPTH {
        var ok = write_word(i);
        assert ok == true;
        i = i + 1;
    }
    assert full() == true;
    var ok = write_word(0xFFFF);
    assert ok == false;
}

test test_empty_after_read {
    reset();
    write_word(0x1234);
    write_word(0x5678);
    var d1 = read_word();
    var d2 = read_word();
    assert d1 == 0x1234;
    assert d2 == 0x5678;
    assert empty() == true;
}

test test_overflow_rejected {
    reset();
    var i = 0;
    while i < DEPTH {
        write_word(i);
        i = i + 1;
    }
    var ok = write_word(0xABCD);
    assert ok == false;
    assert fifo.fill_count == DEPTH;
}

test test_underflow_returns_sentinel {
    reset();
    var data = read_word();
    assert data == 0xFFFF;
    assert fifo.fill_count == 0;
}

test test_overflow_then_underflow {
    reset();
    var i = 0;
    while i < DEPTH {
        write_word(i);
        i = i + 1;
    }
    var extra = write_word(0xFFFF);
    assert extra == false;
    var j = 0;
    while j < DEPTH {
        var data = read_word();
        assert data == j;
        j = j + 1;
    }
    var sentinel = read_word();
    assert sentinel == 0xFFFF;
}

test test_rapid_alternating {
    reset();
    var i = 0;
    while i < 20 {
        var ok = write_word(i);
        assert ok == true;
        var data = read_word();
        assert data == i;
        i = i + 1;
    }
    assert empty() == true;
}

test test_wrap_behavior {
    reset();
    var i = 0;
    while i < 16 {
        write_word(i);
        i = i + 1;
    }
    var j = 0;
    while j < 8 {
        var data = read_word();
        assert data == (j + 8);
        j = j + 1;
    }
    assert fifo.fill_count == 8;
}

test test_simultaneous_rw {
    reset();
    write_word(0x42);
    wr_en = true;
    rd_en = true;
    wr_data = 0x43;
    tick();
    wr_en = false;
    rd_en = false;
    invariant fill_count == 1;
}

test test_on_comb_writes_when_not_full {
    reset();
    var result = on_comb(0xAAAA);
    assert result == true;
    assert fifo.fill_count == 1;
    assert fifo.mem[0] == 0xAAAA;
}

test test_on_comb_rejects_when_full {
    reset();
    var i = 0;
    while i < DEPTH {
        write_word(i);
        i = i + 1;
    }
    var result = on_comb(0xBBBB);
    assert result == false;
    assert fifo.fill_count == DEPTH;
}

Открыть spec урока в плеере ↗

Все уроки