You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fatamorgana/fatamorgana/test/test_files_properties.py

1079 lines
39 KiB
Python

# type: ignore
from io import BytesIO, BufferedIOBase
import pytest
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, write_bstring, write_byte
from ..basic import InvalidDataError
from ..main import OasisLayout
def base_tests(layout: OasisLayout) -> None:
assert layout.version.string == '1.0'
assert layout.unit == 1000
assert layout.validation.checksum_type == 0
assert not layout.properties
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
'''
include_repetitions = variant in (2, 5)
def var_byte(buf, byte):
if include_repetitions:
byte |= 0b0100
write_byte(buf, byte)
buf.write(HEADER)
if variant in (1, 2):
write_uint(buf, 10) # PROPSTRING (explicit id)
write_bstring(buf, b'PropStringId12')
write_uint(buf, 12) # id
write_uint(buf, 10) # PROPSTRING record (explicit id)
write_bstring(buf, b'Property string value for ID 13')
write_uint(buf, 13) # id
write_uint(buf, 7) # PROPNAME record (implicit id 0)
write_bstring(buf, b'PROP0')
write_uint(buf, 7) # PROPNAME record (implicit id 1)
write_bstring(buf, b'PROP1')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_uint(buf, 16) # XYRELATIVE record
# RECTANGLE 0
write_uint(buf, 20) # RECTANGLE record
var_byte(buf, 0b0110_0011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
if include_repetitions:
write_uint(buf, 1) # repetition (3x2 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 0) # (repetition) y-dimension
write_uint(buf, 300) # (repetition) x-spacing
write_uint(buf, 320) # (repetition) y-spacing
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_0100) # UUUU_VCNS
write_bstring(buf, b'PROPX')
# RECTANGLE 1
write_uint(buf, 20) # RECTANGLE record
var_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0001_0110) # UUUU_VCNS
write_uint(buf, 0) # propname id
write_uint(buf, 1) # property value 0 (real type 1, negative int)
write_uint(buf, 5) # (real 1)
# RECTANGLE 2
write_uint(buf, 20) # RECTANGLE record
var_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0100_0110) # UUUU_VCNS
write_uint(buf, 0) # propname id
write_uint(buf, 8) # prop value 0 (unsigned int)
write_uint(buf, 25) # (prop value)
write_uint(buf, 9) # prop value 1 (signed int)
write_sint(buf, -124) # (prop value)
write_uint(buf, 10) # prop value 2 (a-string)
write_bstring(buf, b'PROP_VALUE2')
write_uint(buf, 13) # prop value 3 (propstring ref.)
write_uint(buf, 12)
# RECTANGLE 3
write_uint(buf, 20) # RECTANGLE record
var_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b1111_0000) # UUUU_VCNS
write_uint(buf, 3) # number of values
write_uint(buf, 0) # prop value 0 (unsigned int)
write_uint(buf, 25) # (prop value)
write_uint(buf, 9) # prop value 1 (signed int)
write_sint(buf, -124) # (prop value)
write_uint(buf, 14) # prop value 2 (propstring ref.)
write_uint(buf, 13)
# RECTANGLE 4
write_uint(buf, 20) # RECTANGLE record
var_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_1000) # UUUU_VCNS
write_uint(buf, 15) # XYABSOLUTE record
# TEXT 5
write_uint(buf, 19) # TEXT record
var_byte(buf, 0b0101_1011) # 0CNX_YRTL
write_bstring(buf, b'A') # text-string
write_uint(buf, 2) # text-layer
write_uint(buf, 1) # text-datatype
write_sint(buf, 1000) # geometry-x (absolute)
write_sint(buf, 0) # geometry-y (absolute)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 29) # PROPERTY (reuse)
# PATH 6
write_uint(buf, 22) # PATH record
var_byte(buf, 0b1111_1011) # EWPX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 10) # half-width
write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE
write_sint(buf, 5) # (extension-scheme)
write_sint(buf, -5) # (extension-scheme)
write_uint(buf, 0) # pointlist (1-delta, horiz. first)
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 2000) # geometry-x (absolute)
write_sint(buf, 0) # geometry-y (absolute)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 29) # PROPERTY (reuse)
# POLYGON 7
write_uint(buf, 21) # POLYGON record
var_byte(buf, 0b0011_1011) # 00PX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 0) # pointlist (1-delta, horiz. first)
write_uint(buf, 4) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, 3000) # geometry-x (absolute)
write_sint(buf, 0) # geometry-y (absolute)
if include_repetitions:
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 29) # PROPERTY (reuse)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_0110) # UUUU_VCNS
write_uint(buf, 1) # propname id
if variant == 5:
write_uint(buf, 10) # PROPSTRING (explicit id)
write_bstring(buf, b'PropStringId12')
write_uint(buf, 12) # id
write_uint(buf, 10) # PROPSTRING record (explicit id)
write_bstring(buf, b'Property string value for ID 13')
write_uint(buf, 13) # id
write_uint(buf, 7) # PROPNAME record (implicit id 0)
write_bstring(buf, b'PROP0')
write_uint(buf, 7) # PROPNAME record (implicit id 1)
write_bstring(buf, b'PROP1')
buf.write(FOOTER)
return buf
def common_geometry_tests(layout: OasisLayout) -> None:
geometry = layout.cells[0].geometry
assert len(geometry) == 8
for ii, gg in enumerate(geometry):
msg = f'Failed on element {ii}'
assert gg.x == [0, 0, 0, 0, 0, 1000, 2000, 3000][ii], msg
assert gg.y == [0, 1000, 2000, 3000, 4000, 0, 0, 0][ii], msg
if ii == 5:
assert gg.layer == 2, msg
assert gg.datatype == 1, msg
else:
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
if ii < 5:
assert gg.width == 100, msg
assert gg.height == 200, msg
assert geometry[5].string.string == 'A'
assert_equal(geometry[6].point_list, [(150, 0), (0, 50), (-50, 0)])
assert_equal(geometry[7].point_list, [(150, 0), (0, 50), (-50, 0),
(0, 50), (-100, 0), (0, -100)])
def common_property_tests(layout: OasisLayout) -> None:
geometry = layout.cells[0].geometry
assert len(geometry[0].properties) == 1
assert geometry[0].properties[0].name.string == 'PROPX'
assert len(geometry[0].properties[0].values) == 0
assert len(geometry[1].properties) == 1
assert geometry[1].properties[0].name == 0
assert len(geometry[1].properties[0].values) == 1
assert geometry[1].properties[0].values[0] == -5
assert len(geometry[2].properties) == 1
assert geometry[2].properties[0].name == 0
assert len(geometry[2].properties[0].values) == 4
assert geometry[2].properties[0].values[0] == 25
assert geometry[2].properties[0].values[1] == -124
assert geometry[2].properties[0].values[2].string == 'PROP_VALUE2'
assert geometry[2].properties[0].values[3].ref == 12
for ii in range(3, 8):
msg = f'Failed on element {ii}'
assert geometry[ii].properties[0].name == 0, msg
assert len(geometry[ii].properties[0].values) == 3, msg
assert geometry[ii].properties[0].values[0] == 25, msg
assert geometry[ii].properties[0].values[1] == -124, msg
assert geometry[ii].properties[0].values[2].ref == 13, msg
for ii in range(3, 7):
msg = f'Failed on element {ii}'
assert len(geometry[ii].properties) == 1, msg
assert len(geometry[7].properties) == 2
assert geometry[7].properties[1].name == 1
def test_file_1() -> None:
buf = write_file_common(BytesIO(), 1)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
common_geometry_tests(layout)
common_property_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
msg = f'Failed on element {ii}'
assert gg.repetition is None, msg
def test_file_2() -> None:
buf = write_file_common(BytesIO(), 2)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
common_geometry_tests(layout)
common_property_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
msg = f'Failed on element {ii}'
assert gg.repetition.a_count == 3, msg
assert gg.repetition.b_count == 2, msg
assert gg.repetition.a_vector == [300, 0], msg
assert gg.repetition.b_vector == [0, 320], msg
def test_file_5() -> None:
buf = write_file_common(BytesIO(), 5)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
common_geometry_tests(layout)
common_property_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
msg = f'Failed on element {ii}'
assert gg.repetition.a_count == 3, msg
assert gg.repetition.b_count == 2, msg
assert gg.repetition.a_vector == [300, 0], msg
assert gg.repetition.b_vector == [0, 320], msg
def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 10) # PROPSTRING (explicit id)
write_bstring(buf, b'PropStringId12')
write_uint(buf, 12) # id
write_uint(buf, 10) # PROPSTRING record (explicit id)
write_bstring(buf, b'Property string value for ID 13')
write_uint(buf, 13) # id
write_uint(buf, 7) # PROPNAME record (implicit id 0)
write_bstring(buf, b'S_GDS_PROPERTY')
# ** CELL **
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_uint(buf, 16) # XYRELATIVE record
# RECTANGLE 0
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0010_0111) # UUUU_VCNS
write_uint(buf, 0) # propname id
write_uint(buf, 8) # property value 0 (unsigned int)
write_uint(buf, 25) # (...)
write_uint(buf, 10) # property value 1 (a-string)
write_bstring(buf, b'PROP_VALUE2')
# RECTANGLE 1
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b1111_0001) # UUUU_VCNS
write_uint(buf, 2) # number of values
write_uint(buf, 8) # property value 0 (unsigned int)
write_uint(buf, 10) # (...)
write_uint(buf, 14) # property value 1 (prop-string ref.)
write_uint(buf, 13) # (...)
# RECTANGLE 2
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_1001) # UUUU_VCNS
# RECTANGLE 3
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
write_uint(buf, 29) # PROPERTY (reuse)
# RECTANGLE 4
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 0) # geometry-x (relative)
write_sint(buf, 1000) # geometry-y (relative)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_1001) # UUUU_VCNS
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0010_0111) # UUUU_VCNS
write_uint(buf, 0) # propname id
write_uint(buf, 8) # prop value 0 (unsigned int)
write_uint(buf, 25) # (...)
write_uint(buf, 10) # prop-value 1 (a-string)
write_bstring(buf, b'PROP_VALUE2') # (...)
write_uint(buf, 15) # XYABSOLUTE record
# TEXT 5
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0101_1011) # 0CNX_YRTL
write_bstring(buf, b'A') # text-string
write_uint(buf, 2) # text-layer
write_uint(buf, 1) # text-datatype
write_sint(buf, 1000) # geometry-x (absolute)
write_sint(buf, 0) # geometry-y (absolute)
write_uint(buf, 29) # PROPERTY (reuse)
# PATH 6
write_uint(buf, 22) # PATH record
write_byte(buf, 0b1111_1011) # EWPX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 10) # half-width
write_byte(buf, 0b0000_1111) # extension-scheme 0000_SSEE
write_sint(buf, 5) # (extension-scheme)
write_sint(buf, -5) # (extension-scheme)
write_uint(buf, 0) # pointlist (1-delta, horiz. first)
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 2000) # geometry-x (absolute)
write_sint(buf, 0) # geometry-y (absolute)
write_uint(buf, 29) # PROPERTY (reuse)
# POLYGON 7
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_1011) # 00PX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 0) # pointlist (1-delta, horiz. first)
write_uint(buf, 4) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, 3000) # geometry-x (absolute)
write_sint(buf, 0) # geometry-y (absolute)
write_uint(buf, 29) # PROPERTY (reuse)
buf.write(FOOTER)
return buf
def test_file_3() -> None:
buf = write_file_3(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
geometry = layout.cells[0].geometry
assert len(geometry) == 8
for ii, gg in enumerate(geometry):
msg = f'Failed on element {ii}'
assert gg.x == [0, 0, 0, 0, 0, 1000, 2000, 3000][ii], msg
assert gg.y == [1000, 2000, 3000, 4000, 5000, 0, 0, 0][ii], msg
if ii == 5:
assert gg.layer == 2, msg
assert gg.datatype == 1, msg
else:
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
if ii < 5:
assert gg.width == 100, msg
assert gg.height == 200, msg
assert gg.repetition is None, msg
assert geometry[5].string.string == 'A'
assert_equal(geometry[6].point_list, [(150, 0), (0, 50), (-50, 0)])
assert_equal(geometry[7].point_list, [(150, 0), (0, 50), (-50, 0),
(0, 50), (-100, 0), (0, -100)])
assert len(geometry[0].properties) == 1
assert geometry[0].properties[0].name == 0
assert len(geometry[0].properties[0].values) == 2
assert geometry[0].properties[0].values[0] == 25
assert geometry[0].properties[0].values[1].string == 'PROP_VALUE2'
for ii in range(1, 4):
msg = f'Failed on element {ii}'
assert len(geometry[ii].properties) == 1, msg
assert geometry[ii].properties[0].name == 0, msg
assert len(geometry[ii].properties[0].values) == 2, msg
assert geometry[ii].properties[0].values[0] == 10, msg
assert geometry[ii].properties[0].values[1].ref == 13, msg
assert len(geometry[4].properties) == 2
assert geometry[4].properties[0].name == 0
assert geometry[4].properties[1].name == 0
assert len(geometry[4].properties[0].values) == 2
assert len(geometry[4].properties[1].values) == 2
assert geometry[4].properties[0].values[0] == 10
assert geometry[4].properties[0].values[1].ref == 13
assert geometry[4].properties[1].values[0] == 25
assert geometry[4].properties[1].values[1].string == 'PROP_VALUE2'
for ii in range(5, 8):
msg = f'Failed on element {ii}'
assert len(geometry[ii].properties) == 1, msg
assert geometry[ii].properties[0].name == 0, msg
assert len(geometry[ii].properties[0].values) == 2, msg
assert geometry[ii].properties[0].values[0] == 25, msg
assert geometry[ii].properties[0].values[1].string == 'PROP_VALUE2', msg
def write_file_4_6(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 10) # PROPSTRING (explicit id)
write_bstring(buf, b'PropStringId12')
write_uint(buf, 12) # id
write_uint(buf, 10) # PROPSTRING record (explicit id)
write_bstring(buf, b'Property string value for ID 13')
write_uint(buf, 13) # id
if variant == 4:
write_uint(buf, 7) # PROPNAME record (implicit id 0)
write_bstring(buf, b'S_GDS_PROPERTY')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
# RECTANGLE 0
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 300) # geometry-x (relative)
write_sint(buf, -400) # geometry-y (relative)
# ** CELL **
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOP') # Cell name
# PLACEMENT 0
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b1011_0000) # CNXY_RAAF
write_bstring(buf, b'A') # cell name
write_sint(buf, -300) # placement-x
write_sint(buf, 400) # placement-y
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0010_0111) # UUUU_VCNS
write_uint(buf, 0) # propname-id
write_uint(buf, 8) # prop-value 0 (unsigned int)
write_uint(buf, 25) # (...)
write_uint(buf, 10) # prop-value 1 (a-string)
write_bstring(buf, b'PROP_VALUE2')
if variant == 6:
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0010_0111) # UUUU_VCNS
write_uint(buf, 0) # propname-id
write_uint(buf, 8) # prop-value 0 (unsigned int)
write_uint(buf, 26) # (...)
write_uint(buf, 10) # prop-value 1 (a-string)
write_bstring(buf, b'PROP_VALUE26')
# PLACEMENT 1
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_0000) # CNXY_RAAF
write_sint(buf, 0) # placement-x
if variant == 4:
write_sint(buf, 200) # placement-y
else:
write_sint(buf, 400) # placement-y
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b1111_0001) # UUUU_VCNS
write_uint(buf, 2) # number of values
write_uint(buf, 8) # prop-value 0 (unsigned int)
write_uint(buf, 10) # (...)
write_uint(buf, 14) # prop-value 1 (prop-string ref.)
write_uint(buf, 13) # (...)
# PLACEMENT 2
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0001_0000) # CNXY_RAAF
write_sint(buf, 400) # placement-y
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_1001) # UUUU_VCNS
# PLACEMENT 3
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0010_0000) # CNXY_RAAF
write_sint(buf, 300) # placement-x
write_uint(buf, 29) # PROPERTY (reuse)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 4
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_0001) # CNXY_RAAF
write_sint(buf, 700) # placement-x (absolute)
write_sint(buf, 400) # placement-y (absolute)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0000_1001) # UUUU_VCNS
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 5
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0001_0010) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0010_0111) # UUUU_VCNS
write_uint(buf, 0) # propname-id
write_uint(buf, 8) # prop-value 0 (unsigned int)
write_uint(buf, 25) # (...)
write_uint(buf, 10) # prop-value 1 (a-string)
write_bstring(buf, b'PROP_VALUE2')
# PLACEMENT 6
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0001_0011) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 29) # PROPERTY (reuse)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 7
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x (absolute)
write_sint(buf, 0) # placement-y (absolute)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 300) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
write_uint(buf, 29) # PROPERTY (reuse)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 8
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x
write_sint(buf, 0) # placement-y
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 29) # PROPERTY (reuse)
# PLACEMENT 9
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x
write_sint(buf, 0) # placement-y
write_uint(buf, 2) # repetition (3 cols.)
write_uint(buf, 1) # (repetition) dimension
write_uint(buf, 320) # (repetition) offset
write_uint(buf, 29) # PROPERTY (reuse)
# PLACEMENT 10
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x
write_sint(buf, 0) # placement-y
write_uint(buf, 3) # repetition (4 rows)
write_uint(buf, 2) # (repetition) dimension
write_uint(buf, 310) # (repetition) offset
write_uint(buf, 29) # PROPERTY (reuse)
# PLACEMENT 11
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x
write_sint(buf, 0) # placement-y
write_uint(buf, 4) # repetition (4 arbitrary cols.)
write_uint(buf, 2) # (repetition) dimension
write_uint(buf, 320) # (repetition)
write_uint(buf, 330) # (repetition)
write_uint(buf, 340) # (repetition)
write_uint(buf, 29) # PROPERTY (reuse)
# PLACEMENT 12
write_uint(buf, 17) # PLACEMENT record (no mag, manhattan)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x
write_sint(buf, 0) # placement-y
write_uint(buf, 8) # repetition (3x4 matrix, arbitrary vectors)
write_uint(buf, 1) # (repetition) n-dimension
write_uint(buf, 2) # (repetition) m-dimension
write_uint(buf, 310 << 2 | 0b01) # (repetition) n-displacement g-delta (310, 320)
write_sint(buf, 320)
write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-dispalcement g-delta 330/northwest = (-330, 330)
write_uint(buf, 29) # PROPERTY (reuse)
if variant == 6:
write_uint(buf, 7) # PROPNAME record (implicit id 0)
write_bstring(buf, b'S_GDS_PROPERTY')
buf.write(FOOTER)
return buf
def test_file_4() -> None:
'''
'''
buf = write_file_4_6(BytesIO(), 4)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 2
assert layout.cells[0].name.string == 'A'
assert layout.cells[1].name.string == 'TOP'
assert not layout.cells[0].properties
assert not layout.cells[1].properties
assert not layout.cells[0].placements
assert not layout.cells[1].geometry
geometry = layout.cells[0].geometry
assert len(geometry) == 1
assert geometry[0].x == 300
assert geometry[0].y == -400
assert geometry[0].layer == 1
assert geometry[0].datatype == 2
assert geometry[0].width == 100
assert geometry[0].height == 200
assert layout.propstrings[12].string == 'PropStringId12'
assert layout.propstrings[13].string == 'Property string value for ID 13'
assert layout.propnames[0].string == 'S_GDS_PROPERTY'
placements = layout.cells[1].placements
assert len(placements) == 13
for ii, pp in enumerate(placements):
msg = f'Failed on placement {ii}'
assert pp.x == [-300, 0, 0, 300, 700, 700, 700, 2000, 4000, 6000, 8000, 10000, 12000][ii], msg
assert pp.y == [400, 200, 400, 400, 400, 1400, 2400, 0, 0, 0, 0, 0, 0][ii], msg
if ii == 4 or 6 <= ii:
assert pp.flip, msg
else:
assert not pp.flip, msg
if ii < 7:
assert pp.repetition is None, msg
assert len(placements[0].properties) == 1
assert placements[0].properties[0].name == 0
assert len(placements[0].properties[0].values) == 2
assert placements[0].properties[0].values[0] == 25
assert placements[0].properties[0].values[1].string == 'PROP_VALUE2'
for ii in range(1, 5):
msg = f'Failed on placement {ii}'
assert len(placements[ii].properties) == 1, msg
assert placements[ii].properties[0].name == 0, msg
assert len(placements[ii].properties[0].values) == 2, msg
assert placements[ii].properties[0].values[0] == 10, msg
assert placements[ii].properties[0].values[1].ref == 13, msg
for ii in range(5, 13):
msg = f'Failed on placement {ii}'
assert len(placements[ii].properties) == 1, msg
assert placements[ii].properties[0].name == 0, msg
assert len(placements[ii].properties[0].values) == 2, msg
assert placements[ii].properties[0].values[0] == 25, msg
assert placements[ii].properties[0].values[1].string == 'PROP_VALUE2', msg
def test_file_6() -> None:
'''
'''
buf = write_file_4_6(BytesIO(), 6)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 2
assert layout.cells[0].name.string == 'A'
assert layout.cells[1].name.string == 'TOP'
assert not layout.cells[0].properties
assert not layout.cells[1].properties
assert not layout.cells[0].placements
assert not layout.cells[1].geometry
geometry = layout.cells[0].geometry
assert len(geometry) == 1
assert geometry[0].x == 300
assert geometry[0].y == -400
assert geometry[0].layer == 1
assert geometry[0].datatype == 2
assert geometry[0].width == 100
assert geometry[0].height == 200
assert layout.propstrings[12].string == 'PropStringId12'
assert layout.propstrings[13].string == 'Property string value for ID 13'
assert layout.propnames[0].string == 'S_GDS_PROPERTY'
placements = layout.cells[1].placements
assert len(placements) == 13
for ii, pp in enumerate(placements):
msg = f'Failed on placement {ii}'
assert pp.x == [-300, 0, 0, 300, 700, 700, 700, 2000, 4000, 6000, 8000, 10000, 12000][ii], msg
assert pp.y == [400, 400, 400, 400, 400, 1400, 2400, 0, 0, 0, 0, 0, 0][ii], msg
if ii == 4 or 6 <= ii:
assert pp.flip, msg
else:
assert not pp.flip, msg
if ii < 7:
assert pp.repetition is None, msg
assert len(placements[0].properties) == 2
assert placements[0].properties[0].name == 0
assert len(placements[0].properties[0].values) == 2
assert placements[0].properties[0].values[0] == 25
assert placements[0].properties[0].values[1].string == 'PROP_VALUE2'
assert placements[0].properties[1].name == 0
assert len(placements[0].properties[1].values) == 2
assert placements[0].properties[1].values[0] == 26
assert placements[0].properties[1].values[1].string == 'PROP_VALUE26'
for ii in range(1, 5):
msg = f'Failed on placement {ii}'
assert len(placements[ii].properties) == 1, msg
assert placements[ii].properties[0].name == 0, msg
assert len(placements[ii].properties[0].values) == 2, msg
assert placements[ii].properties[0].values[0] == 10, msg
assert placements[ii].properties[0].values[1].ref == 13, msg
for ii in range(5, 13):
msg = f'Failed on placement {ii}'
assert len(placements[ii].properties) == 1, msg
assert placements[ii].properties[0].name == 0, msg
assert len(placements[ii].properties[0].values) == 2, msg
assert placements[ii].properties[0].values[0] == 25, msg
assert placements[ii].properties[0].values[1].string == 'PROP_VALUE2', msg
def write_file_7_8_9(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0001_0100) # UUUU_VCNS
write_bstring(buf, b'FileProp1') # property name
write_uint(buf, 10) # prop-value 0 (a-string)
write_bstring(buf, b'FileProp1Value')
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0001_0110) # UUUU_VCNS
write_uint(buf, 13) # prop-name reference
write_uint(buf, 10) # prop-value 0 (a-string)
write_bstring(buf, b'FileProp1Value')
write_uint(buf, 8) # PROPNAME record (explicit id)
write_bstring(buf, b'FileProp2')
write_uint(buf, 13) # id
# associated with PROPNAME?
write_uint(buf, 28) # PROPERTY record
if variant == 8:
# Will give an error since the value modal variable is reset by PROPNAME_ID
write_byte(buf, 0b0001_1110) # UUUU_VCNS
else:
write_byte(buf, 0b0001_0110) # UUUU_VCNS
write_uint(buf, 13) # prop-name reference
if variant != 8:
write_uint(buf, 8) # prop-value 0 (unsigned int)
write_uint(buf, 17) # (...)
write_uint(buf, 10) # PROPSTRING (explicit id)
write_bstring(buf, b'FileProp2Value')
write_uint(buf, 12) # id
# associated with PROPSTRING?
write_uint(buf, 28) # PROPERTY record
if variant == 9:
# Will give an error since the value modal variable is unset
write_byte(buf, 0b0001_1110) # UUUU_VCNS
else:
write_byte(buf, 0b0001_0110) # UUUU_VCNS
write_uint(buf, 13) # prop-name reference
if variant != 9:
write_uint(buf, 8) # prop-value 0 (unsigned int)
write_uint(buf, 42) # (...)
write_uint(buf, 3) # CELLNAME record (implicit id 0)
write_bstring(buf, b'A')
# associated with cell A, through CELLNAME # TODO
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0001_0100) # UUUU_VCNS
write_bstring(buf, b'CellProp0') # prop name
write_uint(buf, 10) # prop-value 0 (a-string)
write_bstring(buf, b'CPValue0')
# ** CELL **
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
# associated with cell A
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0001_0100) # UUUU_VCNS
write_bstring(buf, b'CellProp1') # prop name
write_uint(buf, 10) # prop-value 0 (a-string)
write_bstring(buf, b'CPValue')
write_uint(buf, 28) # PROPERTY record
write_byte(buf, 0b0001_1100) # UUUU_VCNS
write_bstring(buf, b'CellProp2') # prop name
# RECTANGLE 0
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_1011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, 300) # geometry-x
write_sint(buf, -400) # geometry-y
buf.write(FOOTER)
return buf
def test_file_7() -> None:
buf = write_file_7_8_9(BytesIO(), 7)
buf.seek(0)
layout = OasisLayout.read(buf)
assert len(layout.properties) == 4
assert layout.properties[0].name.string == 'FileProp1'
assert layout.properties[1].name == 13
assert layout.properties[2].name == 13
assert layout.properties[3].name == 13
assert len(layout.properties[0].values) == 1
assert len(layout.properties[1].values) == 1
assert len(layout.properties[2].values) == 1
assert len(layout.properties[3].values) == 1
assert layout.properties[1].values[0].string == 'FileProp1Value'
assert layout.properties[1].values[0].string == 'FileProp1Value'
assert layout.properties[2].values[0] == 17
assert layout.properties[3].values[0] == 42
assert len(layout.cells) == 1
cprops = layout.cells[0].properties
assert len(cprops) == 2
assert cprops[0].name.string == 'CellProp1'
assert cprops[1].name.string == 'CellProp2'
assert len(cprops[0].values) == 1
assert len(cprops[1].values) == 1
assert cprops[0].values[0].string == 'CPValue'
assert cprops[1].values[0].string == 'CPValue'
assert len(layout.cellnames) == 1
cnprops = layout.cellnames[0].properties
assert len(cnprops) == 1
assert cnprops[0].name.string == 'CellProp0'
assert len(cnprops[0].values) == 1
assert cnprops[0].values[0].string == 'CPValue0'
# TODO Document that cell properties can be attached to both
# the cell and the cellname
# TODO Document that value count is ignored when using modal
def test_file_8() -> None:
'''
'''
buf = write_file_7_8_9(BytesIO(), 8)
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)
def test_file_9() -> None:
'''
'''
buf = write_file_7_8_9(BytesIO(), 9)
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)