import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge

import random

@cocotb.test()
async def test_counter_reset(dut):
    clock = Clock(dut.clk, 10, units="us")  # Create a 10us period clock on port clk
    cocotb.fork(clock.start())              # Start the clock

    await RisingEdge(dut.clk)
    await RisingEdge(dut.clk)

    dut.rst <= 1
    await RisingEdge(dut.clk)
    await FallingEdge(dut.clk)

    cnt = dut.data_out.value.integer        # assert counter ouput is 0
    assert cnt == 0
    
    await RisingEdge(dut.clk)
    await RisingEdge(dut.clk)

@cocotb.test()
async def test_counter_load(dut):
    clock = Clock(dut.clk, 10, units="us")  # Create a 10us period clock on port clk
    cocotb.fork(clock.start())              # Start the clock

    dut.rst <= 0
    dut.load <= 1
    soll = random.randint(0,15)
    dut.data <= soll

    await RisingEdge(dut.clk)
    await FallingEdge(dut.clk)
    assert dut.data_out.value.integer == soll, f"counter value is incorrect: {dut.data_out.value.integer} != {soll}"



@cocotb.test()
async def test_counter_inc(dut):
    """Test for count up"""

    dut.rst <= 0
    dut.load <= 0
    dut.updown <= 1
    dut.data <= random.randint(0,15)

    clock = Clock(dut.clk, 10, units="us")  # Create a 10us period clock on port clk
    cocotb.fork(clock.start())              # Start the clock

    dut.rst <= 1
    await RisingEdge(dut.clk)
    await FallingEdge(dut.clk)
    dut.rst <= 0

    soll = 0
    for _ in range(10):
        assert dut.data_out.value.integer == soll, f"counter value is incorrect: {dut.data_out.value.integer} != {soll}"

        await RisingEdge(dut.clk)
        soll += 1
        await FallingEdge(dut.clk)


@cocotb.test()
async def test_counter_dec(dut):
    """Test for count down"""

    dut.rst <= 0
    dut.load <= 0
    dut.updown <= 0
    dut.data <= 14
    soll = 14

    clock = Clock(dut.clk, 10, units="us")  # Create a 10us period clock on port clk
    cocotb.fork(clock.start())              # Start the clock

    dut.rst <= 1
    await RisingEdge(dut.clk)
    await FallingEdge(dut.clk)
    dut.rst <= 0

    dut.load <= 1
    await RisingEdge(dut.clk)
    await FallingEdge(dut.clk)
    dut.load <= 0

    for _ in range(10):
        assert dut.data_out.value.integer == soll, f"counter value is incorrect: {dut.data_out.value.integer} != {soll}"

        await RisingEdge(dut.clk)
        soll -= 1
        await FallingEdge(dut.clk)



