From dd470140297240ea71b23ae689bfd14e571b025a Mon Sep 17 00:00:00 2001 From: saji Date: Thu, 19 Sep 2024 14:32:02 -0500 Subject: [PATCH] fix geom, add unittest --- src/groovylight/geom.py | 22 +++++++++++++++-- src/groovylight/test_hub75.py | 38 ----------------------------- src/groovylight/test_swapbuffer.py | 34 -------------------------- src/groovylight/tests/test_gamma.py | 0 src/groovylight/tests/test_geom.py | 32 ++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 74 deletions(-) delete mode 100644 src/groovylight/test_hub75.py delete mode 100644 src/groovylight/test_swapbuffer.py create mode 100644 src/groovylight/tests/test_gamma.py create mode 100644 src/groovylight/tests/test_geom.py diff --git a/src/groovylight/geom.py b/src/groovylight/geom.py index d658c7c..8646d4c 100644 --- a/src/groovylight/geom.py +++ b/src/groovylight/geom.py @@ -7,7 +7,7 @@ from typing import Self from math import ceil, log2 -@dataclass(frozen=True, order=True) +@dataclass(frozen=True) class Coord: """Coordinate class. Uses computer-graphics standard coordinate system, where X=0, Y=0 is top left. +X goes right. +Y goes down. @@ -20,6 +20,24 @@ class Coord: if self.x < 0 or self.y < 0: raise RuntimeError("x and y must both be >= 0") + def __lt__(self, other): + return self.x < other.x and self.y < other.y + + def __gt__(self, other): + return self.x > other.x and self.y > other.y + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __neq__(self, other): + return not (self.x == other.x and self.y == other.y) + + def __le__(self, other): + return self.x <= other.x and self.y <= other.y + + def __ge__(self, other): + return self.x >= other.x and self.y >= other.y + @dataclass(frozen=True) class BBox: @@ -34,7 +52,7 @@ class BBox: raise RuntimeError("topleft must be strictly less than bottomright") def contains(self, c: Coord) -> bool: - return c > self.topleft and c < self.bottomright + return c >= self.topleft and c <= self.bottomright @property def width(self) -> int: diff --git a/src/groovylight/test_hub75.py b/src/groovylight/test_hub75.py deleted file mode 100644 index 79c3a18..0000000 --- a/src/groovylight/test_hub75.py +++ /dev/null @@ -1,38 +0,0 @@ -from amaranth import Array, Module, Cat, Signal, Assert, unsigned -from amaranth.build import Platform -from amaranth.lib import wiring, data -from amaranth.lib.wiring import In, Out -from amaranth.lib.memory import Memory, WritePort -from amaranth.sim import Simulator - -from .bitslicer import Hub75StringDriver, Rgb666Layout - - -def test_stringdriver(): - # the string driver test must - # 1. finish - # 2. strobe through all of the data in the array - # 3. slice the correct bit from the data. - m = Module() - m.submodules.dut = dut = Hub75StringDriver() - m.submodules.mem = mem = Memory( - shape=data.ArrayLayout(Rgb666Layout, 2), depth=128, init=[] - ) - port = mem.read_port() - - wiring.connect(m, port, dut.bram_port) - - async def testbench(ctx): - # select a bit, strobe start, read values, test against known. - ctx.set(dut.bcm_select, 5) - ctx.set(dut.start, 1) - await ctx.tick() - ctx.set(dut.start, 0) - assert ctx.get(dut.bram_port.en) == 1 - pass - - sim = Simulator(m) - sim.add_clock(1e-6) - - with sim.write_vcd("output.vcd"): - sim.run_until(1e-6 * 1000) diff --git a/src/groovylight/test_swapbuffer.py b/src/groovylight/test_swapbuffer.py deleted file mode 100644 index 2b5cce2..0000000 --- a/src/groovylight/test_swapbuffer.py +++ /dev/null @@ -1,34 +0,0 @@ -from amaranth import Array, Module, Cat, Signal, Assert, unsigned -from amaranth.build import Platform -from amaranth.lib import wiring, data -from amaranth.lib.wiring import In, Out -from amaranth.lib.memory import Memory, WritePort -from amaranth.sim import Simulator - -from .bitslicer import Hub75StringDriver, Rgb666Layout, SwapBuffer - - -def test_swapbuffer(): - dut = SwapBuffer(Rgb666Layout, 512) - sim = Simulator(dut) - sim.add_clock(1e-6) - - async def testbench(ctx): - init_color = {"red": 0, "green": 0, "blue": 0} - test_color = {"red": 8, "green": 8, "blue": 8} - ctx.set(dut.selector, 0) - ctx.set(dut.write_port.addr, 1) - ctx.set(dut.read_port.addr, 1) - ctx.set(dut.write_port.data, test_color) - await ctx.tick() - # assert that the read port addr 1 = 0 - assert ctx.get(dut.read_port.data) == init_color - # swap buffer - ctx.set(dut.selector, 1) - await ctx.tick().repeat(2) # takes two clocks after switching selector to output data. - assert ctx.get(dut.read_port.data) == test_color - - # TODO: add more assertions/verification - sim.add_testbench(testbench) - with sim.write_vcd("output.vcd"): - sim.run_until(1e-6 * 1000) diff --git a/src/groovylight/tests/test_gamma.py b/src/groovylight/tests/test_gamma.py new file mode 100644 index 0000000..e69de29 diff --git a/src/groovylight/tests/test_geom.py b/src/groovylight/tests/test_geom.py new file mode 100644 index 0000000..47b8a07 --- /dev/null +++ b/src/groovylight/tests/test_geom.py @@ -0,0 +1,32 @@ +from ..geom import Coord, BBox + +import pytest + +def test_coord_comparison(): + c1 = Coord(0,0) + c2 = Coord(0,1) + c3 = Coord(1,1) + c3_other = Coord(1,1) + + assert c1 < c3 + assert not c1 < c2, "both x,y must be greater/lt/eq" + assert c2 <= c3 + + assert c3 == c3_other, "Coords with same numbers should equal each other" + assert c3 != c2 + +def test_coord_construction(): + with pytest.raises(RuntimeError): + Coord(0,-1) + + +def test_bbox(): + b = BBox(Coord(1,1), Coord(3,2)) + + assert b.width == 2 + assert b.height == 1 + + assert b.contains(Coord(1,2)) + assert not b.contains(Coord(0,0)) + + # TODO: test .intersect(other)