[tests] add a bunch of tests
This commit is contained in:
parent
cf4d7f70d4
commit
49a7ba2209
3 changed files with 322 additions and 0 deletions
110
klamath/test_elements.py
Normal file
110
klamath/test_elements.py
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import io
|
||||
import numpy
|
||||
from numpy.testing import assert_array_equal
|
||||
from klamath.elements import Boundary, Path, Text, Reference, Box, Node
|
||||
|
||||
def test_boundary_roundtrip() -> None:
|
||||
xy = numpy.array([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], dtype=numpy.int32)
|
||||
b = Boundary(layer=(4, 5), xy=xy, properties={1: b'prop1'})
|
||||
|
||||
stream = io.BytesIO()
|
||||
b.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
b2 = Boundary.read(stream)
|
||||
assert b2.layer == b.layer
|
||||
assert_array_equal(b2.xy, b.xy)
|
||||
assert b2.properties == b.properties
|
||||
|
||||
def test_path_roundtrip() -> None:
|
||||
xy = numpy.array([[0, 0], [100, 0], [100, 100]], dtype=numpy.int32)
|
||||
p = Path(layer=(10, 20), xy=xy, properties={2: b'pathprop'},
|
||||
path_type=4, width=50, extension=(10, 20))
|
||||
|
||||
stream = io.BytesIO()
|
||||
p.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
p2 = Path.read(stream)
|
||||
assert p2.layer == p.layer
|
||||
assert_array_equal(p2.xy, p.xy)
|
||||
assert p2.properties == p.properties
|
||||
assert p2.path_type == p.path_type
|
||||
assert p2.width == p.width
|
||||
assert p2.extension == p.extension
|
||||
|
||||
def test_text_roundtrip() -> None:
|
||||
xy = numpy.array([[50, 50]], dtype=numpy.int32)
|
||||
t = Text(layer=(1, 1), xy=xy, string=b"HELLO WORLD", properties={},
|
||||
presentation=5, path_type=0, width=0, invert_y=True,
|
||||
mag=2.5, angle_deg=45.0)
|
||||
|
||||
stream = io.BytesIO()
|
||||
t.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
t2 = Text.read(stream)
|
||||
assert t2.layer == t.layer
|
||||
assert_array_equal(t2.xy, t.xy)
|
||||
assert t2.string == t.string
|
||||
assert t2.presentation == t.presentation
|
||||
assert t2.invert_y == t.invert_y
|
||||
assert t2.mag == t.mag
|
||||
assert t2.angle_deg == t.angle_deg
|
||||
|
||||
def test_reference_sref_roundtrip() -> None:
|
||||
xy = numpy.array([[100, 200]], dtype=numpy.int32)
|
||||
r = Reference(struct_name=b"MY_CELL", xy=xy, colrow=None,
|
||||
properties={5: b'sref'}, invert_y=False, mag=1.0, angle_deg=90.0)
|
||||
|
||||
stream = io.BytesIO()
|
||||
r.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
r2 = Reference.read(stream)
|
||||
assert r2.struct_name == r.struct_name
|
||||
assert_array_equal(r2.xy, r.xy)
|
||||
assert r2.colrow is None
|
||||
assert r2.properties == r.properties
|
||||
assert r2.angle_deg == r.angle_deg
|
||||
|
||||
def test_reference_aref_roundtrip() -> None:
|
||||
xy = numpy.array([[0, 0], [1000, 0], [0, 500]], dtype=numpy.int32)
|
||||
colrow = (5, 2)
|
||||
r = Reference(struct_name=b"ARRAY_CELL", xy=xy, colrow=colrow,
|
||||
properties={}, invert_y=False, mag=1.0, angle_deg=0.0)
|
||||
|
||||
stream = io.BytesIO()
|
||||
r.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
r2 = Reference.read(stream)
|
||||
assert r2.struct_name == r.struct_name
|
||||
assert_array_equal(r2.xy, r.xy)
|
||||
assert r2.colrow is not None
|
||||
assert list(r2.colrow) == list(colrow)
|
||||
assert r2.properties == r.properties
|
||||
|
||||
def test_box_roundtrip() -> None:
|
||||
xy = numpy.array([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], dtype=numpy.int32)
|
||||
b = Box(layer=(30, 40), xy=xy, properties={})
|
||||
|
||||
stream = io.BytesIO()
|
||||
b.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
b2 = Box.read(stream)
|
||||
assert b2.layer == b.layer
|
||||
assert_array_equal(b2.xy, b.xy)
|
||||
|
||||
def test_node_roundtrip() -> None:
|
||||
xy = numpy.array([[0, 0], [10, 10]], dtype=numpy.int32)
|
||||
n = Node(layer=(50, 60), xy=xy, properties={})
|
||||
|
||||
stream = io.BytesIO()
|
||||
n.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
n2 = Node.read(stream)
|
||||
assert n2.layer == n.layer
|
||||
assert_array_equal(n2.xy, n.xy)
|
||||
78
klamath/test_library.py
Normal file
78
klamath/test_library.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import io
|
||||
import numpy
|
||||
from datetime import datetime
|
||||
from klamath.library import FileHeader, write_struct, try_read_struct, scan_structs, scan_hierarchy, read_elements
|
||||
from klamath.elements import Boundary
|
||||
from klamath.records import ENDLIB
|
||||
|
||||
def test_file_header_roundtrip() -> None:
|
||||
h = FileHeader(name=b"MY_LIB", user_units_per_db_unit=0.001, meters_per_db_unit=1e-9,
|
||||
mod_time=datetime(2023, 1, 1, 0, 0, 0), acc_time=datetime(2023, 1, 1, 0, 0, 0))
|
||||
|
||||
stream = io.BytesIO()
|
||||
h.write(stream)
|
||||
stream.seek(0)
|
||||
|
||||
h2 = FileHeader.read(stream)
|
||||
assert h2.name == h.name
|
||||
assert h2.user_units_per_db_unit == h.user_units_per_db_unit
|
||||
assert h2.meters_per_db_unit == h.meters_per_db_unit
|
||||
assert h2.mod_time == h.mod_time
|
||||
|
||||
def test_write_read_struct() -> None:
|
||||
xy = numpy.array([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], dtype=numpy.int32)
|
||||
b = Boundary(layer=(1, 1), xy=xy, properties={})
|
||||
|
||||
stream = io.BytesIO()
|
||||
# Need a header for some operations, but write_struct works standalone
|
||||
write_struct(stream, name=b"CELL_A", elements=[b])
|
||||
ENDLIB.write(stream, None)
|
||||
stream.seek(0)
|
||||
|
||||
res = try_read_struct(stream)
|
||||
assert res is not None
|
||||
name, elements = res
|
||||
assert name == b"CELL_A"
|
||||
assert len(elements) == 1
|
||||
assert isinstance(elements[0], Boundary)
|
||||
|
||||
def test_scan_structs() -> None:
|
||||
stream = io.BytesIO()
|
||||
write_struct(stream, name=b"CELL_A", elements=[])
|
||||
write_struct(stream, name=b"CELL_B", elements=[])
|
||||
ENDLIB.write(stream, None)
|
||||
stream.seek(0)
|
||||
|
||||
positions = scan_structs(stream)
|
||||
assert b"CELL_A" in positions
|
||||
assert b"CELL_B" in positions
|
||||
|
||||
# Verify we can seek and read
|
||||
stream.seek(positions[b"CELL_B"])
|
||||
elements = read_elements(stream)
|
||||
assert len(elements) == 0
|
||||
|
||||
def test_scan_hierarchy() -> None:
|
||||
from klamath.elements import Reference
|
||||
|
||||
stream = io.BytesIO()
|
||||
# Struct A has 2 refs to Struct B
|
||||
ref_b1 = Reference(struct_name=b"B", xy=numpy.array([[0, 0]], dtype=numpy.int32), colrow=None, properties={},
|
||||
invert_y=False, mag=1.0, angle_deg=0.0)
|
||||
ref_b2 = Reference(struct_name=b"B", xy=numpy.array([[10, 10]], dtype=numpy.int32), colrow=None, properties={},
|
||||
invert_y=False, mag=1.0, angle_deg=0.0)
|
||||
write_struct(stream, name=b"A", elements=[ref_b1, ref_b2])
|
||||
|
||||
# Struct B has a 3x2 AREF of Struct C
|
||||
ref_c = Reference(struct_name=b"C", xy=numpy.array([[0, 0], [10, 0], [0, 10]], dtype=numpy.int32),
|
||||
colrow=(3, 2), properties={}, invert_y=False, mag=1.0, angle_deg=0.0)
|
||||
write_struct(stream, name=b"B", elements=[ref_c])
|
||||
|
||||
write_struct(stream, name=b"C", elements=[])
|
||||
ENDLIB.write(stream, None)
|
||||
stream.seek(0)
|
||||
|
||||
hierarchy = scan_hierarchy(stream)
|
||||
assert hierarchy[b"A"] == {b"B": 2}
|
||||
assert hierarchy[b"B"] == {b"C": 6}
|
||||
assert hierarchy[b"C"] == {}
|
||||
134
klamath/test_record.py
Normal file
134
klamath/test_record.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import io
|
||||
import pytest
|
||||
import struct
|
||||
from datetime import datetime
|
||||
from klamath.basic import KlamathError
|
||||
from klamath.record import (
|
||||
write_record_header, read_record_header, expect_record,
|
||||
BitArrayRecord, Int2Record, ASCIIRecord, DateTimeRecord, NoDataRecord
|
||||
)
|
||||
from klamath.records import ENDLIB, HEADER
|
||||
|
||||
def test_write_read_record_header() -> None:
|
||||
stream = io.BytesIO()
|
||||
tag = 0x1234
|
||||
data_size = 8
|
||||
|
||||
write_record_header(stream, data_size, tag)
|
||||
stream.seek(0)
|
||||
|
||||
read_size, read_tag = read_record_header(stream)
|
||||
assert read_size == data_size
|
||||
assert read_tag == tag
|
||||
assert stream.tell() == 4
|
||||
|
||||
def test_write_record_header_too_big() -> None:
|
||||
stream = io.BytesIO()
|
||||
with pytest.raises(KlamathError, match="Record size is too big"):
|
||||
write_record_header(stream, 0x10000, 0x1234)
|
||||
|
||||
def test_read_record_header_errors() -> None:
|
||||
# Too small
|
||||
stream = io.BytesIO(struct.pack('>HH', 2, 0x1234))
|
||||
with pytest.raises(KlamathError, match="Record size is too small"):
|
||||
read_record_header(stream)
|
||||
|
||||
# Odd size
|
||||
stream = io.BytesIO(struct.pack('>HH', 5, 0x1234))
|
||||
with pytest.raises(KlamathError, match="Record size is odd"):
|
||||
read_record_header(stream)
|
||||
|
||||
def test_expect_record() -> None:
|
||||
stream = io.BytesIO()
|
||||
write_record_header(stream, 4, 0x1111)
|
||||
stream.seek(0)
|
||||
|
||||
# Correct tag
|
||||
size = expect_record(stream, 0x1111)
|
||||
assert size == 4
|
||||
|
||||
# Incorrect tag
|
||||
stream.seek(0)
|
||||
with pytest.raises(KlamathError, match="Unexpected record"):
|
||||
expect_record(stream, 0x2222)
|
||||
|
||||
def test_bitarray_record() -> None:
|
||||
class TestBit(BitArrayRecord):
|
||||
tag = 0x9999
|
||||
|
||||
stream = io.BytesIO()
|
||||
TestBit.write(stream, 0x8000)
|
||||
stream.seek(0)
|
||||
|
||||
val = TestBit.read(stream)
|
||||
assert val == 0x8000
|
||||
|
||||
def test_int2_record() -> None:
|
||||
class TestInt2(Int2Record):
|
||||
tag = 0x8888
|
||||
|
||||
stream = io.BytesIO()
|
||||
TestInt2.write(stream, [1, -2, 3])
|
||||
stream.seek(0)
|
||||
|
||||
val = TestInt2.read(stream)
|
||||
assert list(val) == [1, -2, 3]
|
||||
|
||||
def test_ascii_record() -> None:
|
||||
class TestASCII(ASCIIRecord):
|
||||
tag = 0x7777
|
||||
|
||||
stream = io.BytesIO()
|
||||
TestASCII.write(stream, b"HELLO")
|
||||
stream.seek(0)
|
||||
|
||||
val = TestASCII.read(stream)
|
||||
assert val == b"HELLO"
|
||||
|
||||
def test_datetime_record() -> None:
|
||||
class TestDT(DateTimeRecord):
|
||||
tag = 0x6666
|
||||
|
||||
now = datetime(2023, 10, 27, 12, 30, 45)
|
||||
stream = io.BytesIO()
|
||||
TestDT.write(stream, [now, now])
|
||||
stream.seek(0)
|
||||
|
||||
vals = TestDT.read(stream)
|
||||
assert vals == [now, now]
|
||||
|
||||
def test_nodata_record() -> None:
|
||||
class TestNoData(NoDataRecord):
|
||||
tag = 0x5555
|
||||
|
||||
stream = io.BytesIO()
|
||||
TestNoData.write(stream, None)
|
||||
stream.seek(0)
|
||||
|
||||
# Verify header: 4 bytes total (size=4, tag=0x5555), data_size=0
|
||||
header = stream.read(4)
|
||||
assert header == struct.pack('>HH', 4, 0x5555)
|
||||
|
||||
stream.seek(0)
|
||||
assert TestNoData.read(stream) is None
|
||||
|
||||
def test_record_skip_past() -> None:
|
||||
stream = io.BytesIO()
|
||||
HEADER.write(stream, 600)
|
||||
ENDLIB.write(stream, None)
|
||||
|
||||
stream.seek(0)
|
||||
# Skip past HEADER
|
||||
found = HEADER.skip_past(stream)
|
||||
assert found is True
|
||||
assert stream.tell() == 6 # 4 header + 2 data
|
||||
|
||||
# Try to skip past something that doesn't exist before ENDLIB
|
||||
class NONEXISTENT(NoDataRecord):
|
||||
tag = 0xFFFF
|
||||
|
||||
stream.seek(0)
|
||||
found = NONEXISTENT.skip_past(stream)
|
||||
assert found is False
|
||||
# Should be at the end of ENDLIB record header/tag read
|
||||
assert stream.tell() == 10 # 6 (HEADER) + 4 (ENDLIB)
|
||||
Loading…
Add table
Add a link
Reference in a new issue