* fix * fix pyrefly * remove tests * Update tests/unit/test_exporter.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/peakrdl_busdecoder/listener.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/unit/test_exporter.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix iter --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
286 lines
8.5 KiB
Python
286 lines
8.5 KiB
Python
"""Tests for body classes used in code generation."""
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
from peakrdl_busdecoder.body import (
|
|
Body,
|
|
CombinationalBody,
|
|
ForLoopBody,
|
|
IfBody,
|
|
StructBody,
|
|
)
|
|
|
|
|
|
class TestBody:
|
|
"""Test the base Body class."""
|
|
|
|
def test_empty_body(self):
|
|
"""Test empty body returns empty string."""
|
|
body = Body()
|
|
assert str(body) == ""
|
|
assert not body # Should be falsy when empty
|
|
|
|
def test_add_single_line(self):
|
|
"""Test adding a single line to body."""
|
|
body = Body()
|
|
body += "line1"
|
|
assert str(body) == "line1"
|
|
assert body # Should be truthy when not empty
|
|
|
|
def test_add_multiple_lines(self):
|
|
"""Test adding multiple lines to body."""
|
|
body = Body()
|
|
body += "line1"
|
|
body += "line2"
|
|
body += "line3"
|
|
expected = "line1\nline2\nline3"
|
|
assert str(body) == expected
|
|
|
|
def test_add_returns_self(self):
|
|
"""Test that add operation returns self for chaining."""
|
|
body = Body()
|
|
body += "line1"
|
|
body += "line2"
|
|
# Chaining works because += returns self
|
|
assert len(body.lines) == 2
|
|
|
|
def test_add_nested_body(self):
|
|
"""Test adding another body as a line."""
|
|
outer = Body()
|
|
inner = Body()
|
|
inner += "inner1"
|
|
inner += "inner2"
|
|
outer += "outer1"
|
|
outer += inner
|
|
outer += "outer2"
|
|
expected = "outer1\ninner1\ninner2\nouter2"
|
|
assert str(outer) == expected
|
|
|
|
|
|
class TestForLoopBody:
|
|
"""Test the ForLoopBody class."""
|
|
|
|
def test_genvar_for_loop(self):
|
|
"""Test genvar-style for loop."""
|
|
body = ForLoopBody("genvar", "i", 4)
|
|
body += "statement1;"
|
|
body += "statement2;"
|
|
|
|
result = str(body)
|
|
assert "for (genvar i = 0; i < 4; i++)" in result
|
|
assert "statement1;" in result
|
|
assert "statement2;" in result
|
|
assert "end" in result
|
|
|
|
def test_int_for_loop(self):
|
|
"""Test int-style for loop."""
|
|
body = ForLoopBody("int", "j", 8)
|
|
body += "assignment = value;"
|
|
|
|
result = str(body)
|
|
assert "for (int j = 0; j < 8; j++)" in result
|
|
assert "assignment = value;" in result
|
|
assert "end" in result
|
|
|
|
def test_empty_for_loop(self):
|
|
"""Test empty for loop."""
|
|
body = ForLoopBody("genvar", "k", 2)
|
|
result = str(body)
|
|
# Empty for loop should still have structure
|
|
assert "for (genvar k = 0; k < 2; k++)" in result
|
|
|
|
def test_nested_for_loops(self):
|
|
"""Test nested for loops."""
|
|
outer = ForLoopBody("genvar", "i", 3)
|
|
inner = ForLoopBody("genvar", "j", 2)
|
|
inner += "nested_statement;"
|
|
outer += inner
|
|
|
|
result = str(outer)
|
|
assert "for (genvar i = 0; i < 3; i++)" in result
|
|
assert "for (genvar j = 0; j < 2; j++)" in result
|
|
assert "nested_statement;" in result
|
|
|
|
|
|
class TestIfBody:
|
|
"""Test the IfBody class."""
|
|
|
|
def test_simple_if(self):
|
|
"""Test simple if statement."""
|
|
body = IfBody()
|
|
with body.cm("condition1") as b:
|
|
b += "statement1;"
|
|
|
|
result = str(body)
|
|
assert "if (condition1)" in result
|
|
assert "statement1;" in result
|
|
assert "end" in result
|
|
|
|
def test_if_else(self):
|
|
"""Test if-else statement."""
|
|
body = IfBody()
|
|
with body.cm("condition1") as b:
|
|
b += "if_statement;"
|
|
with body.cm(None) as b: # None for else
|
|
b += "else_statement;"
|
|
|
|
result = str(body)
|
|
assert "if (condition1)" in result
|
|
assert "if_statement;" in result
|
|
assert "else" in result
|
|
assert "else_statement;" in result
|
|
|
|
def test_if_elif_else(self):
|
|
"""Test if-elif-else chain."""
|
|
body = IfBody()
|
|
with body.cm("condition1") as b:
|
|
b += "statement1;"
|
|
with body.cm("condition2") as b:
|
|
b += "statement2;"
|
|
with body.cm(None) as b: # None for else
|
|
b += "statement3;"
|
|
|
|
result = str(body)
|
|
assert "if (condition1)" in result
|
|
assert "statement1;" in result
|
|
assert "else if (condition2)" in result
|
|
assert "statement2;" in result
|
|
assert "else" in result
|
|
assert "statement3;" in result
|
|
|
|
def test_multiple_elif(self):
|
|
"""Test multiple elif statements."""
|
|
body = IfBody()
|
|
with body.cm("cond1") as b:
|
|
b += "stmt1;"
|
|
with body.cm("cond2") as b:
|
|
b += "stmt2;"
|
|
with body.cm("cond3") as b:
|
|
b += "stmt3;"
|
|
|
|
result = str(body)
|
|
assert "if (cond1)" in result
|
|
assert "else if (cond2)" in result
|
|
assert "else if (cond3)" in result
|
|
|
|
def test_empty_if_branches(self):
|
|
"""Test if statement with empty branches."""
|
|
body = IfBody()
|
|
with body.cm("condition"):
|
|
pass
|
|
|
|
result = str(body)
|
|
assert "if (condition)" in result
|
|
|
|
def test_nested_if(self):
|
|
"""Test nested if statements."""
|
|
outer = IfBody()
|
|
with outer.cm("outer_cond") as outer_body:
|
|
inner = IfBody()
|
|
with inner.cm("inner_cond") as inner_body:
|
|
inner_body += "nested_statement;"
|
|
outer_body += inner
|
|
|
|
result = str(outer)
|
|
assert "if (outer_cond)" in result
|
|
assert "if (inner_cond)" in result
|
|
assert "nested_statement;" in result
|
|
|
|
|
|
class TestCombinationalBody:
|
|
"""Test the CombinationalBody class."""
|
|
|
|
def test_simple_combinational_block(self):
|
|
"""Test simple combinational block."""
|
|
body = CombinationalBody()
|
|
body += "assign1 = value1;"
|
|
body += "assign2 = value2;"
|
|
|
|
result = str(body)
|
|
assert "always_comb" in result
|
|
assert "begin" in result
|
|
assert "assign1 = value1;" in result
|
|
assert "assign2 = value2;" in result
|
|
assert "end" in result
|
|
|
|
def test_empty_combinational_block(self):
|
|
"""Test empty combinational block."""
|
|
body = CombinationalBody()
|
|
result = str(body)
|
|
assert "always_comb" in result
|
|
assert "begin" in result
|
|
assert "end" in result
|
|
|
|
def test_combinational_with_if_statement(self):
|
|
"""Test combinational block with if statement."""
|
|
cb = CombinationalBody()
|
|
ifb = IfBody()
|
|
with ifb.cm("condition") as b:
|
|
b += "assignment = value;"
|
|
cb += ifb
|
|
|
|
result = str(cb)
|
|
assert "always_comb" in result
|
|
assert "if (condition)" in result
|
|
assert "assignment = value;" in result
|
|
|
|
|
|
class TestStructBody:
|
|
"""Test the StructBody class."""
|
|
|
|
def test_simple_struct(self):
|
|
"""Test simple struct definition."""
|
|
body = StructBody("my_struct_t", packed=True, typedef=True)
|
|
body += "logic [7:0] field1;"
|
|
body += "logic field2;"
|
|
|
|
result = str(body)
|
|
assert "typedef struct packed" in result
|
|
assert "my_struct_t" in result
|
|
assert "logic [7:0] field1;" in result
|
|
assert "logic field2;" in result
|
|
|
|
def test_unpacked_struct(self):
|
|
"""Test unpacked struct definition."""
|
|
body = StructBody("unpacked_t", packed=False, typedef=True)
|
|
body += "int field1;"
|
|
|
|
result = str(body)
|
|
assert "typedef struct" in result
|
|
assert "packed" not in result or "typedef struct {" in result
|
|
assert "unpacked_t" in result
|
|
|
|
def test_struct_without_typedef(self):
|
|
"""Test struct without typedef."""
|
|
body = StructBody("my_struct", packed=True, typedef=False)
|
|
body += "logic field;"
|
|
|
|
result = str(body)
|
|
# When typedef=False, packed is not used
|
|
assert "struct {" in result
|
|
assert "typedef" not in result
|
|
assert "my_struct" in result
|
|
|
|
def test_empty_struct(self):
|
|
"""Test empty struct."""
|
|
body = StructBody("empty_t", packed=True, typedef=True)
|
|
result = str(body)
|
|
assert "typedef struct packed" in result
|
|
assert "empty_t" in result
|
|
|
|
def test_nested_struct(self):
|
|
"""Test struct with nested struct."""
|
|
outer = StructBody("outer_t", packed=True, typedef=True)
|
|
inner = StructBody("inner_t", packed=True, typedef=True)
|
|
inner += "logic field1;"
|
|
outer += "logic field2;"
|
|
outer += str(inner) # Include inner struct as a string
|
|
|
|
result = str(outer)
|
|
assert "outer_t" in result
|
|
assert "field2;" in result
|
|
# Inner struct should appear in the string
|
|
assert "inner_t" in result
|