Compare commits
No commits in common. "9e6f5a336578558a2aa9c0414826d4bba594fbaa" and "cf4d7f70d4804a4b4959f2f6acb742ad5dcdb3f5" have entirely different histories.
9e6f5a3365
...
cf4d7f70d4
7 changed files with 5 additions and 510 deletions
|
|
@ -197,7 +197,7 @@ header = klamath.library.FileHeader.read(stream)
|
||||||
struct_positions = klamath.library.scan_structs(stream)
|
struct_positions = klamath.library.scan_structs(stream)
|
||||||
|
|
||||||
stream.seek(struct_positions[b'my_struct'])
|
stream.seek(struct_positions[b'my_struct'])
|
||||||
elements_A = klamath.library.read_elements(stream)
|
elements_A = klamath.library.try_read_struct(stream)
|
||||||
|
|
||||||
stream.close()
|
stream.close()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ def decode_real8(nums: NDArray[numpy.uint64]) -> NDArray[numpy.float64]:
|
||||||
exp = (nums >> 56) & 0x7f
|
exp = (nums >> 56) & 0x7f
|
||||||
mant = (nums & 0x00ff_ffff_ffff_ffff).astype(numpy.float64)
|
mant = (nums & 0x00ff_ffff_ffff_ffff).astype(numpy.float64)
|
||||||
mant[neg != 0] *= -1
|
mant[neg != 0] *= -1
|
||||||
return numpy.ldexp(mant, 4 * (exp.astype(numpy.int64) - 64) - 56)
|
return numpy.ldexp(mant, 4 * (exp - 64) - 56, signature=(float, int, float))
|
||||||
|
|
||||||
|
|
||||||
def parse_real8(data: bytes) -> NDArray[numpy.float64]:
|
def parse_real8(data: bytes) -> NDArray[numpy.float64]:
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class HEADER(Int2Record):
|
||||||
|
|
||||||
class BGNLIB(DateTimeRecord):
|
class BGNLIB(DateTimeRecord):
|
||||||
tag = 0x0102
|
tag = 0x0102
|
||||||
expected_size = 2 * 6 * 2
|
expected_size = 6 * 2
|
||||||
|
|
||||||
|
|
||||||
class LIBNAME(ASCIIRecord):
|
class LIBNAME(ASCIIRecord):
|
||||||
|
|
@ -37,7 +37,7 @@ class ENDLIB(NoDataRecord):
|
||||||
|
|
||||||
class BGNSTR(DateTimeRecord):
|
class BGNSTR(DateTimeRecord):
|
||||||
tag = 0x0502
|
tag = 0x0502
|
||||||
expected_size = 2 * 6 * 2
|
expected_size = 6 * 2
|
||||||
|
|
||||||
|
|
||||||
class STRNAME(ASCIIRecord):
|
class STRNAME(ASCIIRecord):
|
||||||
|
|
@ -173,8 +173,6 @@ class GENERATIONS(Int2Record):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check_data(cls: type[Self], data: NDArray[numpy.integer] | Sequence[int] | int) -> None:
|
def check_data(cls: type[Self], data: NDArray[numpy.integer] | Sequence[int] | int) -> None:
|
||||||
if isinstance(data, (int, numpy.integer)):
|
|
||||||
return
|
|
||||||
if not isinstance(data, Sized) or len(data) != 1:
|
if not isinstance(data, Sized) or len(data) != 1:
|
||||||
raise KlamathError(f'Expected exactly one integer, got {data}')
|
raise KlamathError(f'Expected exactly one integer, got {data}')
|
||||||
|
|
||||||
|
|
@ -224,6 +222,7 @@ class PROPATTR(Int2Record):
|
||||||
|
|
||||||
class PROPVALUE(ASCIIRecord):
|
class PROPVALUE(ASCIIRecord):
|
||||||
tag = 0x2c06
|
tag = 0x2c06
|
||||||
|
expected_size = 2
|
||||||
|
|
||||||
|
|
||||||
class BOX(NoDataRecord):
|
class BOX(NoDataRecord):
|
||||||
|
|
@ -272,8 +271,6 @@ class FORMAT(Int2Record):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check_data(cls: type[Self], data: NDArray[numpy.integer] | Sequence[int] | int) -> None:
|
def check_data(cls: type[Self], data: NDArray[numpy.integer] | Sequence[int] | int) -> None:
|
||||||
if isinstance(data, (int, numpy.integer)):
|
|
||||||
return
|
|
||||||
if not isinstance(data, Sized) or len(data) != 1:
|
if not isinstance(data, Sized) or len(data) != 1:
|
||||||
raise KlamathError(f'Expected exactly one integer, got {data}')
|
raise KlamathError(f'Expected exactly one integer, got {data}')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,156 +0,0 @@
|
||||||
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)
|
|
||||||
|
|
||||||
def test_reference_check() -> None:
|
|
||||||
import pytest
|
|
||||||
from klamath.basic import KlamathError
|
|
||||||
# SREF with too many points
|
|
||||||
xy = numpy.array([[0, 0], [10, 10]], dtype=numpy.int32)
|
|
||||||
r = Reference(struct_name=b"CELL", xy=xy, colrow=None, properties={}, invert_y=False, mag=1.0, angle_deg=0.0)
|
|
||||||
with pytest.raises(KlamathError, match="Expected size-2 xy"):
|
|
||||||
r.check()
|
|
||||||
|
|
||||||
# AREF with too few points
|
|
||||||
xy = numpy.array([[0, 0]], dtype=numpy.int32)
|
|
||||||
r = Reference(struct_name=b"CELL", xy=xy, colrow=(2, 2), properties={}, invert_y=False, mag=1.0, angle_deg=0.0)
|
|
||||||
with pytest.raises(KlamathError, match="colrow is not None, so expected size-6 xy"):
|
|
||||||
r.check()
|
|
||||||
|
|
||||||
def test_read_properties_duplicate() -> None:
|
|
||||||
import pytest
|
|
||||||
from klamath.basic import KlamathError
|
|
||||||
from klamath.records import PROPATTR, PROPVALUE, ENDEL
|
|
||||||
stream = io.BytesIO()
|
|
||||||
PROPATTR.write(stream, 1)
|
|
||||||
PROPVALUE.write(stream, b"val1")
|
|
||||||
PROPATTR.write(stream, 1) # DUPLICATE
|
|
||||||
PROPVALUE.write(stream, b"val2")
|
|
||||||
ENDEL.write(stream, None)
|
|
||||||
stream.seek(0)
|
|
||||||
|
|
||||||
from klamath.elements import read_properties
|
|
||||||
with pytest.raises(KlamathError, match="Duplicate property key"):
|
|
||||||
read_properties(stream)
|
|
||||||
|
|
||||||
def test_element_read_unexpected_tag() -> None:
|
|
||||||
import pytest
|
|
||||||
from klamath.basic import KlamathError
|
|
||||||
from klamath.records import SREF, SNAME, HEADER, XY, ENDEL
|
|
||||||
stream = io.BytesIO()
|
|
||||||
SREF.write(stream, None)
|
|
||||||
SNAME.write(stream, b"CELL")
|
|
||||||
HEADER.write(stream, 123) # UNEXPECTED TAG for Reference.read
|
|
||||||
XY.write(stream, [0, 0])
|
|
||||||
ENDEL.write(stream, None)
|
|
||||||
stream.seek(0)
|
|
||||||
|
|
||||||
with pytest.raises(KlamathError, match="Unexpected tag"):
|
|
||||||
Reference.read(stream)
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
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"] == {}
|
|
||||||
|
|
||||||
def test_scan_structs_duplicate() -> None:
|
|
||||||
import pytest
|
|
||||||
from klamath.basic import KlamathError
|
|
||||||
stream = io.BytesIO()
|
|
||||||
write_struct(stream, name=b"CELL_A", elements=[])
|
|
||||||
write_struct(stream, name=b"CELL_A", elements=[])
|
|
||||||
ENDLIB.write(stream, None)
|
|
||||||
stream.seek(0)
|
|
||||||
|
|
||||||
with pytest.raises(KlamathError, match="Duplicate structure name"):
|
|
||||||
scan_structs(stream)
|
|
||||||
|
|
||||||
def test_scan_hierarchy_duplicate() -> None:
|
|
||||||
import pytest
|
|
||||||
from klamath.basic import KlamathError
|
|
||||||
stream = io.BytesIO()
|
|
||||||
write_struct(stream, name=b"CELL_A", elements=[])
|
|
||||||
write_struct(stream, name=b"CELL_A", elements=[])
|
|
||||||
ENDLIB.write(stream, None)
|
|
||||||
stream.seek(0)
|
|
||||||
|
|
||||||
with pytest.raises(KlamathError, match="Duplicate structure name"):
|
|
||||||
scan_hierarchy(stream)
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
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)
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
import io
|
|
||||||
import pytest
|
|
||||||
import numpy
|
|
||||||
from datetime import datetime
|
|
||||||
from klamath.basic import KlamathError
|
|
||||||
from klamath import records
|
|
||||||
|
|
||||||
def test_record_tags() -> None:
|
|
||||||
assert records.HEADER.tag == 0x0002
|
|
||||||
assert records.BGNLIB.tag == 0x0102
|
|
||||||
assert records.LIBNAME.tag == 0x0206
|
|
||||||
assert records.UNITS.tag == 0x0305
|
|
||||||
assert records.ENDLIB.tag == 0x0400
|
|
||||||
assert records.BGNSTR.tag == 0x0502
|
|
||||||
assert records.STRNAME.tag == 0x0606
|
|
||||||
assert records.ENDSTR.tag == 0x0700
|
|
||||||
assert records.BOUNDARY.tag == 0x0800
|
|
||||||
assert records.PATH.tag == 0x0900
|
|
||||||
assert records.SREF.tag == 0x0a00
|
|
||||||
assert records.AREF.tag == 0x0b00
|
|
||||||
assert records.TEXT.tag == 0x0c00
|
|
||||||
assert records.LAYER.tag == 0x0d02
|
|
||||||
assert records.DATATYPE.tag == 0x0e02
|
|
||||||
assert records.WIDTH.tag == 0x0f03
|
|
||||||
assert records.XY.tag == 0x1003
|
|
||||||
assert records.ENDEL.tag == 0x1100
|
|
||||||
assert records.SNAME.tag == 0x1206
|
|
||||||
assert records.COLROW.tag == 0x1302
|
|
||||||
assert records.NODE.tag == 0x1500
|
|
||||||
assert records.TEXTTYPE.tag == 0x1602
|
|
||||||
assert records.PRESENTATION.tag == 0x1701
|
|
||||||
assert records.STRING.tag == 0x1906
|
|
||||||
assert records.STRANS.tag == 0x1a01
|
|
||||||
assert records.MAG.tag == 0x1b05
|
|
||||||
assert records.ANGLE.tag == 0x1c05
|
|
||||||
assert records.REFLIBS.tag == 0x1f06
|
|
||||||
assert records.FONTS.tag == 0x2006
|
|
||||||
assert records.PATHTYPE.tag == 0x2102
|
|
||||||
assert records.GENERATIONS.tag == 0x2202
|
|
||||||
assert records.ATTRTABLE.tag == 0x2306
|
|
||||||
assert records.ELFLAGS.tag == 0x2601
|
|
||||||
assert records.NODETYPE.tag == 0x2a02
|
|
||||||
assert records.PROPATTR.tag == 0x2b02
|
|
||||||
assert records.PROPVALUE.tag == 0x2c06
|
|
||||||
assert records.BOX.tag == 0x2d00
|
|
||||||
assert records.BOXTYPE.tag == 0x2e02
|
|
||||||
assert records.PLEX.tag == 0x2f03
|
|
||||||
assert records.BGNEXTN.tag == 0x3003
|
|
||||||
assert records.ENDEXTN.tag == 0x3103
|
|
||||||
assert records.TAPENUM.tag == 0x3202
|
|
||||||
assert records.TAPECODE.tag == 0x3302
|
|
||||||
assert records.FORMAT.tag == 0x3602
|
|
||||||
assert records.MASK.tag == 0x3706
|
|
||||||
assert records.ENDMASKS.tag == 0x3800
|
|
||||||
assert records.LIBDIRSIZE.tag == 0x3902
|
|
||||||
assert records.SRFNAME.tag == 0x3a06
|
|
||||||
assert records.LIBSECUR.tag == 0x3b02
|
|
||||||
|
|
||||||
def test_header_validation() -> None:
|
|
||||||
# Correct size
|
|
||||||
records.HEADER.check_size(2)
|
|
||||||
|
|
||||||
# Incorrect size
|
|
||||||
with pytest.raises(KlamathError, match="Expected size 2, got 4"):
|
|
||||||
records.HEADER.check_size(4)
|
|
||||||
|
|
||||||
def test_bgnlib_validation() -> None:
|
|
||||||
now = datetime(2023, 10, 27, 12, 30, 45)
|
|
||||||
# Correct size (2 datetimes = 24 bytes)
|
|
||||||
records.BGNLIB.check_size(24)
|
|
||||||
|
|
||||||
# Incorrect size
|
|
||||||
with pytest.raises(KlamathError, match="Expected size 24, got 12"):
|
|
||||||
records.BGNLIB.check_size(12)
|
|
||||||
|
|
||||||
def test_reflibs_fonts_validation() -> None:
|
|
||||||
# REFLIBS must be multiple of 44
|
|
||||||
records.REFLIBS.check_size(44)
|
|
||||||
records.REFLIBS.check_size(88)
|
|
||||||
records.REFLIBS.check_size(0)
|
|
||||||
|
|
||||||
with pytest.raises(KlamathError, match="Expected size to be multiple of 44"):
|
|
||||||
records.REFLIBS.check_size(10)
|
|
||||||
|
|
||||||
def test_generations_format_validation() -> None:
|
|
||||||
# GENERATIONS expects exactly one integer
|
|
||||||
records.GENERATIONS.check_data(3)
|
|
||||||
records.GENERATIONS.check_data([1])
|
|
||||||
|
|
||||||
with pytest.raises(KlamathError, match="Expected exactly one integer"):
|
|
||||||
records.GENERATIONS.check_data([1, 2])
|
|
||||||
|
|
||||||
def test_attrtable_validation() -> None:
|
|
||||||
# ATTRTABLE size <= 44
|
|
||||||
records.ATTRTABLE.check_size(44)
|
|
||||||
records.ATTRTABLE.check_size(10)
|
|
||||||
|
|
||||||
with pytest.raises(KlamathError, match="Expected size <= 44"):
|
|
||||||
records.ATTRTABLE.check_size(45)
|
|
||||||
|
|
||||||
def test_nodata_records() -> None:
|
|
||||||
stream = io.BytesIO()
|
|
||||||
records.ENDLIB.write(stream, None)
|
|
||||||
stream.seek(0)
|
|
||||||
assert records.ENDLIB.read(stream) is None
|
|
||||||
|
|
||||||
stream = io.BytesIO()
|
|
||||||
records.BOUNDARY.write(stream, None)
|
|
||||||
stream.seek(0)
|
|
||||||
assert records.BOUNDARY.read(stream) is None
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue