Add tests

master
Jan Petykiewicz 3 years ago
parent 9c5b902a33
commit f3be3deadb

5
.gitignore vendored

@ -7,3 +7,8 @@ build
dist
fatamorgana.egg-info
docs
*.gds
*.gds.gz
*.oas
*.oas.gz

@ -0,0 +1,7 @@
"""
Tests (run with `python3 -m pytest -rxPXs | tee results.txt`)
The test_files_* modules are meant to mimic the test cases used by KLayout,
in order to provide a secondary validation mechanism.
"""

@ -0,0 +1,96 @@
'''
Build files equivalent to the test cases used by KLayout.
'''
# type: ignore
from typing import Callable
from io import BufferedIOBase
from . import (
test_files_properties, test_files_cblocks, test_files_layernames,
test_files_circles, test_files_ctrapezoids, test_files_trapezoids,
test_files_placements, test_files_paths, test_files_modals,
test_files_polygons, test_files_rectangles, test_files_empty,
test_files_texts, test_files_cells)
def build_file(num: str, func: Callable[[BufferedIOBase], BufferedIOBase]) -> None:
with open('t' + num + '.oas', 'wb') as f:
func(f)
def write_all_files() -> None:
build_file('1.1', test_files_empty.write_file_1)
build_file('1.2', test_files_empty.write_file_2)
build_file('1.3', test_files_empty.write_file_3)
build_file('1.4', test_files_empty.write_file_4)
build_file('1.5', test_files_empty.write_file_5)
build_file('2.1', test_files_cells.write_file_1)
build_file('2.2', test_files_cells.write_file_2)
build_file('2.3', test_files_cells.write_file_3)
build_file('2.4', test_files_cells.write_file_4)
build_file('2.5', test_files_cells.write_file_5)
build_file('2.6', test_files_cells.write_file_6)
build_file('2.7', test_files_cells.write_file_7)
build_file('3.1', lambda f: test_files_texts.write_file_common(f, 1))
build_file('3.2', lambda f: test_files_texts.write_file_common(f, 2))
build_file('3.3', test_files_texts.write_file_3)
build_file('3.4', test_files_texts.write_file_4)
build_file('3.5', lambda f: test_files_texts.write_file_common(f, 5))
build_file('3.6', test_files_texts.write_file_6)
build_file('3.7', test_files_texts.write_file_7)
build_file('3.8', test_files_texts.write_file_8)
build_file('3.9', test_files_texts.write_file_9)
build_file('3.10', test_files_texts.write_file_10)
build_file('3.11', test_files_texts.write_file_11)
build_file('4.1', lambda f: test_files_rectangles.write_file_common(f, 1))
build_file('4.2', lambda f: test_files_rectangles.write_file_common(f, 2))
build_file('5.1', lambda f: test_files_polygons.write_file_common(f, 1))
build_file('5.2', test_files_polygons.write_file_2)
build_file('5.3', lambda f: test_files_polygons.write_file_common(f, 3))
build_file('6.1', test_files_paths.write_file_1)
build_file('7.1', test_files_trapezoids.write_file_1)
build_file('8.1', test_files_placements.write_file_1)
build_file('8.2', lambda f: test_files_placements.write_file_common(f, 2))
build_file('8.3', lambda f: test_files_placements.write_file_common(f, 3))
build_file('8.4', test_files_placements.write_file_4)
build_file('8.5', lambda f: test_files_placements.write_file_common(f, 5))
build_file('8.6', test_files_placements.write_file_6)
build_file('8.7', lambda f: test_files_placements.write_file_common(f, 7))
build_file('8.8', test_files_placements.write_file_8)
build_file('9.1', test_files_ctrapezoids.write_file_1)
build_file('9.2', test_files_ctrapezoids.write_file_2)
build_file('10.1', test_files_modals.write_file_1)
build_file('11.1', lambda f: test_files_properties.write_file_common(f, 1))
build_file('11.2', lambda f: test_files_properties.write_file_common(f, 2))
build_file('11.3', test_files_properties.write_file_3)
build_file('11.4', lambda f: test_files_properties.write_file_4_6(f, 4))
build_file('11.5', lambda f: test_files_properties.write_file_common(f, 5))
build_file('11.6', lambda f: test_files_properties.write_file_4_6(f, 6))
build_file('11.7', lambda f: test_files_properties.write_file_7_8_9(f, 7))
build_file('11.8', lambda f: test_files_properties.write_file_7_8_9(f, 8))
build_file('11.9', lambda f: test_files_properties.write_file_7_8_9(f, 9))
build_file('12.1', test_files_circles.write_file_1)
build_file('13.1', test_files_layernames.write_file_1)
build_file('13.2', test_files_layernames.write_file_2)
build_file('13.3', test_files_layernames.write_file_3)
build_file('13.4', test_files_layernames.write_file_4)
build_file('14.1', test_files_cblocks.write_file_1)
if __name__ == '__main__':
write_all_files()

@ -0,0 +1,183 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'ABCDH'
assert not layout.cells[0].properties
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABCDH') # Cell name
cblock_data = bytes.fromhex('''
22 00 b0 02 b2 02 13
a9 66 60 98 c3 32 89 e5 0e e3 1b 61 91 4a c6 15
ac 8f 58 3a f8 be f0 8a 5a b0 30 57 5f 64 6d e4
4f bd c8 7a 87 ed 81 f8 02 79 a0 88 68 f5 42 b6
4e be 80 99 4c 3b 99 35 97 30 4f 14 d7 3c 14 f4
52 50 e4 24 e3 0b f6 9b c2 1a 9a 27 18 57 4b 8a
04 ae 65 3f 12 04 24 36 0b 8b 2c f2 e9 14 16 3d
c6 73 92 4d 64 21 e3 0b 9e cf 9a 15 4f 59 6f 08
83 cc 5d c8 f8 91 7b 25 7f ea 4e e6 03 3c 5b a4
66 88 01 85 d8 37 b2 fc 64 bd c8 25 5a 79 92 b1
99 4b a3 93 65 26 7b 33 bf e6 69 b6 39 7c a9 4b
40 2e e1 3b 28 a6 79 82 69 41 98 f6 14 ae 60 9b
d7 4c a2 9a 3d 8c 37 f9 6c 03 3f 32 b6 68 2c 64
5c cb f3 9a 49 f3 33 e3 0c a6 dd da 29 2f 98 76
80 d4 73 df 64 f9 cb b3 58 33 60 36 d3 13 d6 9b
9c b6 9a 3b 98 5f b2 07 2e 64 dc c9 7c 91 4b 24
f8 08 cb 6e 45 8d 47 32 1d 12 77 b8 81 4a 59 17
68 6a 1f 60 df 28 ac a9 3d 85 b5 5b b6 62 0a ff
0c 69 90 7b 36 b3 6c 65 d3 9c c9 f4 40 b1 93 a5
47 e0 32 7f 8a e6 54 d6 93 6c a2 0f 14 17 c8 03
00''')
for byte in cblock_data:
write_byte(buf, byte)
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == 10
for ii, gg in enumerate(geometry):
msg = f'Failed on geometry {ii}'
assert gg.x == [110, 900, 1520, -370, 1690, -50, 180, 1540, 970, 2160][ii], msg
assert gg.y == [1270, 890, 2000, 1260, 1420, 850, 860, 750, 1740, 2000][ii], msg
if ii == 0:
assert gg.layer == 0, msg
else:
assert gg.layer == 1, msg
assert gg.datatype == 0, msg
assert not gg.properties, msg
assert gg.repetition is None, msg
assert geometry[0].height == 530
assert geometry[0].width == 540
assert geometry[1].height == 610
assert geometry[1].width == 680
assert_equal(geometry[2].point_list,
[[-30, -360], [480, -50], [180, 430], [-630, -20]])
assert_equal(geometry[3].point_list,
[[-30, -400],
[450, 40],
[70, -220],
[10, 210],
[740, -20],
[0, 660],
[570, 10],
[50, 500],
[630, 20],
[10, 100],
[-810, 10],
[20, -470],
[-660, 0],
[20, -470],
[-620, 10],
[0, 610],
[610, -10],
[0, -100],
[210, 10],
[40, 820],
[-1340, 60],
[30, -1370]])
assert_equal(geometry[4].point_list,
[[40, -760], [490, -50], [110, 800], [-640, 10]])
assert_equal(geometry[5].point_list,
[[140, -380],
[340, -10],
[30, -100],
[-320, 20],
[130, -460],
[-480, -20],
[-210, 910],
[370, 40]])
assert_equal(geometry[6].point_list,
[[720, -20],
[20, 20],
[690, 0],
[-10, 650],
[-20, 30],
[-90, -10],
[10, 70],
[470, -30],
[20, -120],
[-320, 0],
[40, -790],
[-90, -20],
[-60, 140],
[-1390, 50],
[10, 30]])
assert_equal(geometry[7].point_list,
[[150, -830],
[-1320, 40],
[-70, 370],
[310, -30],
[10, 220],
[250, -40],
[40, -220],
[340, 10],
[-20, 290],
[-1070, 20],
[0, 230],
[1380, -60]])
assert_equal(geometry[8].point_list,
[[330, 0], [-10, 480], [620, -20], [-10, 330], [-930, 60], [0, -850]])
assert_equal(geometry[9].point_list,
[[-140, -410],
[10, -140],
[270, 0],
[130, 1030],
[-500, 50],
[10, -330],
[210, -10],
[10, -190]])

@ -0,0 +1,275 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.propstrings
assert not layout.layers
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
Single cell with explicit name 'XYZ'
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'XYZ') # Cell name
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'XYZ'
assert not layout.cellnames
def write_file_2(buf: BufferedIOBase) -> BufferedIOBase:
'''
Two cellnames ('XYZ', 'ABC') and two cells with name references.
'''
buf.write(HEADER)
write_uint(buf, 3) # CELLNAME record (implicit id 0)
write_bstring(buf, b'XYZ')
write_uint(buf, 3) # CELLNAME record (implicit id 1)
write_bstring(buf, b'ABC')
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 1) # Cell name 1 (ABC)
buf.write(FOOTER)
return buf
def test_file_2() -> None:
buf = write_file_2(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cellnames) == 2
assert len(layout.cells) == 2
assert layout.cellnames[0].nstring.string == 'XYZ'
assert layout.cellnames[1].nstring.string == 'ABC'
assert layout.cells[0].name == 0
assert layout.cells[1].name == 1
def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
'''
Invalid file, contains a mix of explicit and implicit cellnames
'''
buf.write(HEADER)
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'ABC')
write_uint(buf, 1) # id 1
write_uint(buf, 3) # CELLNAME record (implicit id 0) -- Expect failure due to mix of explicit/implicit ids
write_bstring(buf, b'XYZ')
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 1) # Cell name 1 (ABC)
buf.write(FOOTER)
return buf
def test_file_3() -> None:
buf = write_file_3(BytesIO())
buf.seek(0)
with pytest.raises(InvalidRecordError):
layout = OasisLayout.read(buf)
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
'''
Two cells referencing two names with explicit ids (unsorted)
'''
buf.write(HEADER)
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'ABC')
write_uint(buf, 1) # id 1
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'XYZ')
write_uint(buf, 0) # id 0
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 1) # Cell name 1 (ABC)
buf.write(FOOTER)
return buf
def test_file_4() -> None:
buf = write_file_4(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cellnames) == 2
assert len(layout.cells) == 2
assert layout.cellnames[0].nstring.string == 'XYZ'
assert layout.cellnames[1].nstring.string == 'ABC'
assert layout.cells[0].name == 0
assert layout.cells[1].name == 1
def write_file_5(buf: BufferedIOBase) -> BufferedIOBase:
'''
Reference to non-existent cell name.
'''
buf.write(HEADER)
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'ABC')
write_uint(buf, 1) # id 1
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'XYZ')
write_uint(buf, 0) # id 0
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 2) # Cell name 2 -- Reference to non-existent CELLNAME!!!
buf.write(FOOTER)
return buf
def test_file_5() -> None:
buf = write_file_5(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cellnames) == 2
assert len(layout.cells) == 2
assert layout.cellnames[0].nstring.string == 'XYZ'
assert layout.cellnames[1].nstring.string == 'ABC'
assert layout.cells[0].name == 0
assert layout.cells[1].name == 2
#TODO add optional error checking for this case
def write_file_6(buf: BufferedIOBase) -> BufferedIOBase:
'''
Cellname with invalid n-string.
'''
buf.write(HEADER)
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'ABC')
write_uint(buf, 1) # id 1
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b' XYZ')
write_uint(buf, 0) # id 0
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 1) # Cell name 1
buf.write(FOOTER)
return buf
def test_file_6() -> None:
buf = write_file_6(BytesIO())
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)
#base_tests(layout)
#assert len(layout.cellnames) == 2
#assert len(layout.cells) == 2
#assert layout.cellnames[0].nstring.string == ' XYZ'
#assert layout.cellnames[1].nstring.string == 'ABC'
#assert layout.cells[0].name == 0
#assert layout.cells[1].name == 1
def write_file_7(buf: BufferedIOBase) -> BufferedIOBase:
'''
Unused cellname.
'''
buf.write(HEADER)
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'ABC')
write_uint(buf, 1) # id 1
write_uint(buf, 4) # CELLNAME record (explicit id)
write_bstring(buf, b'XYZ')
write_uint(buf, 0) # id 0
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (XYZ)
buf.write(FOOTER)
return buf
def test_file_7() -> None:
buf = write_file_7(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cellnames) == 2
assert len(layout.cells) == 1
assert layout.cellnames[0].nstring.string == 'XYZ'
assert layout.cellnames[1].nstring.string == 'ABC'
assert layout.cells[0].name == 0

@ -0,0 +1,117 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0011_1011) # 00rX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 150) # radius
write_sint(buf, -100) # geometry-x (absolute)
write_sint(buf, 200) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0000_1000) # 00rX_YRDL
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0010_1000) # 00rX_YRDL
write_uint(buf, 0) # radius
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0010_1000) # 00rX_YRDL
write_uint(buf, 1) # radius
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0010_1000) # 00rX_YRDL
write_uint(buf, 6) # radius
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0010_1000) # 00rX_YRDL
write_uint(buf, 20) # radius
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0010_1100) # 00rX_YRDL
write_uint(buf, 100) # radius
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 400) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == 7
for ii, gg in enumerate(geometry):
msg = f'Failed on circle {ii}'
assert gg.x == -100, msg
assert gg.y == 200 + 400 * ii, msg
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
assert not gg.properties, msg
assert gg.radius == [150, 150, 0, 1, 6, 20, 100][ii], msg
if ii != 6:
assert gg.repetition is None, msg
assert geometry[6].repetition.a_count == 3, msg
assert geometry[6].repetition.b_count == 4, msg
assert geometry[6].repetition.a_vector == [400, 0], msg
assert geometry[6].repetition.b_vector == [0, 300], msg

@ -0,0 +1,247 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b1111_1011) # TWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 24) # ctrapezoid type
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, -100) # geometry-x (absolute)
write_sint(buf, 200) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b0000_1000) # TWHX_YRDL
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0000_0011) # SWHX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
h = [250, 100]
v = [100, 250]
wh = [h] * 8 + [v] * 8 + [h] * 6 + [v] * 2 + [h] * 2
wh_en = ([0b11] * 16
+ [0b10] * 4
+ [0b01] * 2
+ [0b10] * 2
+ [0b11, 0b10])
for t, (x, x_en) in enumerate(zip(wh, wh_en)):
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b1000_1011 | (x_en << 5)) # TWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, t) # ctrapezoid type
if x_en & 0b10:
write_uint(buf, x[0]) # width
if x_en & 0b01:
write_uint(buf, x[1]) # height
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0000_0011) # SWHX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b0000_1100) # TWHX_YRDL
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 400) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(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) == 3 + 26 * 2 + 1
for ii, gg in enumerate(geometry):
msg = f'Failed on shape {ii}'
assert gg.x == -100, msg
assert gg.y == 200 + 400 * ((ii + 1) // 2), msg
if ii < 2 or (3 <= ii < 55 and ii % 2 == 1):
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
else:
assert gg.layer == 2, msg
assert gg.datatype == 3, msg
if ii < 3:
assert gg.width == 100, msg
assert gg.height == 200, msg
assert not gg.properties, msg
if 3 <= ii < 55:
ct_type = (ii - 3) // 2
is_ctrapz = ii % 2 == 1
if is_ctrapz:
assert gg.ctrapezoid_type == ct_type, msg
if ct_type in range(16, 20):
assert gg.height == [250, None][is_ctrapz], msg
elif ct_type in (20, 21):
assert gg.width == [250, None][is_ctrapz], msg
elif ct_type in range(22, 24) or ct_type == 25:
assert gg.height == [100, None][is_ctrapz], msg
else:
if ct_type < 8 or 16 <= ct_type < 25 or 26 <= ct_type :
assert gg.width == 250, msg
assert gg.height == 100, msg
else:
assert gg.width == 100, msg
assert gg.height == 250, msg
elif ii < 3 and ii % 2:
assert gg.ctrapezoid_type == 24, msg
elif ii == 55:
assert gg.ctrapezoid_type == 25, msg
assert geometry[55].repetition.a_count == 3
assert geometry[55].repetition.b_count == 4
assert geometry[55].repetition.a_vector == [400, 0]
assert geometry[55].repetition.b_vector == [0, 300]
def write_file_2(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
# Shouldn't access (undefined) height modal, despite not having a height.
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b1101_1011) # TWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 16) # ctrapezoid type
write_uint(buf, 200) # width
write_sint(buf, -100) # geometry-x (absolute)
write_sint(buf, 200) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b0000_1000) # TWHX_YRDL
write_sint(buf, 400) # geometry-y (relative)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'B') # Cell name
# Shouldn't access (undefined) width modal, despite not having a width.
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b1011_1011) # TWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 20) # ctrapezoid type
write_uint(buf, 200) # height
write_sint(buf, -100) # geometry-x (absolute)
write_sint(buf, 200) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
write_uint(buf, 26) # CTRAPEZOID record
write_byte(buf, 0b0000_1000) # TWHX_YRDL
write_sint(buf, 400) # geometry-y (relative)
buf.write(FOOTER)
return buf
def test_file_2() -> None:
buf = write_file_2(BytesIO())
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 == 'B'
assert not layout.cells[0].properties
assert not layout.cells[1].properties
for ii, cc in enumerate(layout.cells):
for jj, gg in enumerate(cc.geometry):
msg = f'Fail in cell {ii}, ctrapezoid {jj}'
assert not gg.properties, msg
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
assert gg.x == -100, msg
geometry = layout.cells[0].geometry
assert geometry[0].width == 200
assert geometry[1].width == 200
assert geometry[0].ctrapezoid_type == 16
assert geometry[1].ctrapezoid_type == 16
assert geometry[0].y == 200
assert geometry[1].y == 600
geometry = layout.cells[1].geometry
assert geometry[0].height == 200
assert geometry[1].height == 200
assert geometry[0].ctrapezoid_type == 20
assert geometry[1].ctrapezoid_type == 20
assert geometry[0].y == 200
assert geometry[1].y == 600

@ -0,0 +1,185 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
from .utils import MAGIC_BYTES, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring
from ..main import OasisLayout
def base_tests(layout: OasisLayout) -> None:
assert layout.version.string == '1.0'
assert layout.validation.checksum_type == 0
assert not layout.properties
assert not layout.cells
assert not layout.cellnames
assert not layout.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.propstrings
assert not layout.layers
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
File contains one PAD record.
1000 units/micron
Offset table inside START.
'''
buf.write(MAGIC_BYTES)
write_uint(buf, 1) # START record
write_bstring(buf, b'1.0') # version
write_uint(buf, 0) # dbu real type: uint
write_uint(buf, 1000) # dbu value: 1000 per micron
write_uint(buf, 0) # offset table is present here
for _ in range(6):
write_uint(buf, 0) # offset table (0: not strict)
write_uint(buf, 0) # offset table (0: no entry present)
write_uint(buf, 0) # PAD record
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert layout.unit == 1000
def write_file_2(buf: BufferedIOBase) -> BufferedIOBase:
'''
File contains no records.
1/2 unit/micron
Offset table inside START.
'''
buf.write(MAGIC_BYTES)
write_uint(buf, 1) # START record
write_bstring(buf, b'1.0') # version
write_uint(buf, 2) # dbu real type: fraction 1/x
write_uint(buf, 2) # dbu value: 1/2 per micron
write_uint(buf, 0) # offset table is present here
for _ in range(6):
write_uint(buf, 0) # offset table (0: not strict)
write_uint(buf, 0) # offset table (0: no entry present)
buf.write(FOOTER)
return buf
def test_file_2() -> None:
buf = write_file_2(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert layout.unit == 0.5
def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
'''
File contains no records.
10/4 unit/micron
Offset table inside START.
'''
buf.write(MAGIC_BYTES)
write_uint(buf, 1) # START record
write_bstring(buf, b'1.0') # version
write_uint(buf, 4) # dbu real type: fraction a/b
write_uint(buf, 10) # dbu value a
write_uint(buf, 4) # dbu value b: 10/4 per micron
write_uint(buf, 0) # offset table is present here
for _ in range(6):
write_uint(buf, 0) # offset table (0: not strict)
write_uint(buf, 0) # offset table (0: no entry present)
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 layout.unit == 10 / 4
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
'''
File contains no records.
12.5 unit/micron (float32)
Offset table inside START.
'''
buf.write(MAGIC_BYTES)
write_uint(buf, 1) # START record
write_bstring(buf, b'1.0') # version
write_uint(buf, 6) # dbu real type: float32
buf.write(struct.pack("<f", 12.5)) # dbu value: 12.5
write_uint(buf, 0) # offset table is present here
for _ in range(6):
write_uint(buf, 0) # offset table (0: not strict)
write_uint(buf, 0) # offset table (0: no entry present)
buf.write(FOOTER)
return buf
def test_file_4() -> None:
buf = write_file_4(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert layout.unit == 12.5
def write_file_5(buf: BufferedIOBase) -> BufferedIOBase:
'''
File contains no records.
12.5 unit/micron (float64)
Offset table inside START.
'''
buf.write(MAGIC_BYTES)
write_uint(buf, 1) # START record
write_bstring(buf, b'1.0') # version
write_uint(buf, 7) # dbu real type: float64
buf.write(struct.pack("<d", 12.5)) # dbu value: 12.5
write_uint(buf, 0) # offset table is present here
for _ in range(6):
write_uint(buf, 0) # offset table (0: not strict)
write_uint(buf, 0) # offset table (0: no entry present)
buf.write(FOOTER)
return buf
def test_file_5() -> None:
buf = write_file_5(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert layout.unit == 12.5

@ -0,0 +1,338 @@
# type: ignore
from typing import List, Tuple, Iterable, Sequence
from itertools import chain
from io import BytesIO, BufferedIOBase
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, InvalidDataError
from ..main import OasisLayout
LAYERS = [(1, 2), (1, 5), (1, 6), (1, 8),
(5, 2), (5, 5), (5, 6), (5, 8),
(6, 2), (6, 5), (6, 6), (6, 8),
(7, 2), (7, 5), (7, 6), (7, 8),
]
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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
def write_names_geom(buf: BufferedIOBase, short: bool = False) -> BufferedIOBase:
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'AA') # name
write_uint(buf, 0) # all layers
write_uint(buf, 0) # all datatypes
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'L5A') # name
write_uint(buf, 1) # layer <=5
write_uint(buf, 5) # (...)
write_uint(buf, 0) # all datatypes
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'H5A') # name
write_uint(buf, 2) # layer >=5
write_uint(buf, 5) # (...)
write_uint(buf, 0) # all datatypes
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'E5A') # name
write_uint(buf, 3) # layer ==5
write_uint(buf, 5) # (...)
write_uint(buf, 0) # all datatypes
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'I56A') # name
write_uint(buf, 4) # layer 5 to 6
write_uint(buf, 5) # (...)
write_uint(buf, 6) # (...)
write_uint(buf, 0) # all datatypes
if short:
return buf
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'E5L4') # name
write_uint(buf, 3) # layer ==5
write_uint(buf, 5) # (...)
write_uint(buf, 1) # datatype <=4
write_uint(buf, 4) # (...)
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'E5H4') # name
write_uint(buf, 3) # layer ==5
write_uint(buf, 5) # (...)
write_uint(buf, 2) # datatype >=4
write_uint(buf, 4) # (...)
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'E5E4') # name
write_uint(buf, 3) # layer ==5
write_uint(buf, 5) # (...)
write_uint(buf, 3) # datatype ==4
write_uint(buf, 4) # (...)
write_uint(buf, 11) # LAYERNAME record (geometry)
write_bstring(buf, b'E5I47') # name
write_uint(buf, 3) # layer ==5
write_uint(buf, 5) # (...)
write_uint(buf, 4) # datatype 4 to 7
write_uint(buf, 4) # (...)
write_uint(buf, 7) # (...)
return buf
def write_names_text(buf: BufferedIOBase, prefix: bytes = b'') -> BufferedIOBase:
write_uint(buf, 12) # LAYERNAME record (geometry)
write_bstring(buf, prefix + b'AA') # name
write_uint(buf, 0) # all layers
write_uint(buf, 0) # all datatypes
write_uint(buf, 12) # LAYERNAME record (geometry)
write_bstring(buf, prefix + b'L5A') # name
write_uint(buf, 1) # layer <=5
write_uint(buf, 5) # (...)
write_uint(buf, 0) # all datatypes
write_uint(buf, 12) # LAYERNAME record (geometry)
write_bstring(buf, prefix + b'H5A') # name
write_uint(buf, 2) # layer >=5
write_uint(buf, 5) # (...)
write_uint(buf, 0) # all datatypes
write_uint(buf, 12) # LAYERNAME record (geometry)
write_bstring(buf, prefix + b'E5A') # name
write_uint(buf, 3) # layer ==5
write_uint(buf, 5) # (...)
write_uint(buf, 0) # all datatypes
write_uint(buf, 12) # LAYERNAME record (geometry)
write_bstring(buf, prefix + b'I56A') # name
write_uint(buf, 4) # layer 5 to 6
write_uint(buf, 5) # (...)
write_uint(buf, 6) # (...)
write_uint(buf, 0) # all datatypes
return buf
def write_geom(buf: BufferedIOBase) -> BufferedIOBase:
for ll, dt in LAYERS:
write_uint(buf, 27) # CIRCLE record
write_byte(buf, 0b0011_1011) # 00rX_YRDL
write_uint(buf, ll) # layer
write_uint(buf, dt) # datatype
write_uint(buf, 150) # radius
write_sint(buf, ll * 1000) # geometry-x (absolute)
write_sint(buf, dt * 1000) # geometry-y (absolute)
return buf
def write_text(buf: BufferedIOBase) -> BufferedIOBase:
for ll, dt in LAYERS:
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0101_1011) # 0CNX_YRTL
write_bstring(buf, b'A') # text-string
write_uint(buf, ll) # text-layer
write_uint(buf, dt) # text-datatype
write_sint(buf, ll * 1000) # geometry-x
write_sint(buf, dt * 1000) # geometry-y
return buf
def name_test(layers: Sequence, is_textlayer: bool) -> None:
for ii, nn in enumerate(layers):
assert is_textlayer == nn.is_textlayer, f'Fail on layername {ii}'
assert nn.nstring.string == ['AA', 'L5A', 'H5A', 'E5A', 'I56A',
'E5L4', 'E5H4', 'E5E4', 'E5I47'][ii], msg
assert nn.layer_interval[0] == [None, None, 5, 5, 5, 5, 5, 5, 5][ii], msg
assert nn.layer_interval[1] == [None, 5, None, 5, 6, 5, 5, 5, 5][ii], msg
assert nn.type_interval[0] == [None, None, None, None, None, None, 4, 4, 4][ii], msg
assert nn.type_interval[1] == [None, None, None, None, None, 4, None, 4, 7][ii], msg
def name_test_text(layers: Sequence) -> None:
for ii, nn in enumerate(layers):
assert nn.is_textlayer, f'Fail on layername {ii}'
assert nn.nstring.string == ['TAA', 'TL5A', 'TH5A', 'TE5A', 'TI56A'][ii], msg
assert nn.layer_interval[0] == [None, None, 5, 5, 5][ii], msg
assert nn.layer_interval[1] == [None, 5, None, 5, 6][ii], msg
assert nn.type_interval[0] == [None, None, None, None, None][ii], msg
assert nn.type_interval[1] == [None, None, None, None, None][ii], msg
def elem_test_geom(geometry: Sequence) -> None:
for ii, gg in enumerate(geometry):
msg = f'Failed on circle ({ii})'
assert gg.x == 1000 * LAYERS[ii][0], msg
assert gg.y == 1000 * LAYERS[ii][1], msg
assert gg.radius == 150, msg
assert gg.layer == LAYERS[ii][0], msg
assert gg.datatype == LAYERS[ii][1], msg
assert gg.repetition is None, msg
assert not gg.properties, msg
def elem_test_text(geometry: Sequence) -> None:
for ii, gg in enumerate(geometry):
msg = f'Failed on text ({ii})'
assert gg.x == 1000 * LAYERS[ii][0], msg
assert gg.y == 1000 * LAYERS[ii][1], msg
assert gg.string.string == 'A', msg
assert gg.layer == LAYERS[ii][0], msg
assert gg.datatype == LAYERS[ii][1], msg
assert gg.repetition is None, msg
assert not gg.properties, msg
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_names_geom(buf)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_geom(buf)
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == len(LAYERS)
elem_test_geom(geometry)
assert len(layout.layers) == 9
name_test(layout.layers, is_textlayer=False)
def write_file_2(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_names_text(buf)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_text(buf)
buf.write(FOOTER)
return buf
def test_file_2() -> None:
buf = write_file_2(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == len(LAYERS)
elem_test_text(geometry)
assert len(layout.layers) == 5
name_test(layout.layers, is_textlayer=True)
def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_names_text(buf, prefix=b'T')
write_names_geom(buf, short=True)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_text(buf)
write_geom(buf)
buf.write(FOOTER)
return buf
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_text(buf)
write_geom(buf)
write_names_text(buf, prefix=b'T')
write_names_geom(buf, short=True)
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)
geometry = layout.cells[0].geometry
assert len(geometry) == 2 * len(LAYERS)
elem_test_text(geometry[:len(LAYERS)])
elem_test_geom(geometry[len(LAYERS):])
assert len(layout.layers) == 2 * 5
name_test_text(layout.layers[:5])
name_test(layout.layers[5:], is_textlayer=False)
def test_file_4() -> None:
buf = write_file_4(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == 2 * len(LAYERS)
elem_test_text(geometry[:len(LAYERS)])
elem_test_geom(geometry[len(LAYERS):])
assert len(layout.layers) == 2 * 5
name_test_text(layout.layers[:5])
name_test(layout.layers[5:], is_textlayer=False)

@ -0,0 +1,260 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
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, 0b0110_0011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 10) # width
write_uint(buf, 20) # height
# TEXT 1
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0100_0011) # 0CNX_YRTL
write_bstring(buf, b'A') # text string
write_uint(buf, 2) # layer
write_uint(buf, 1) # datatype
# RECTANGLE 2
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0001_1000) # SWHX_YRDL
write_sint(buf, 100) # geometry-x (absolute)
write_sint(buf, -100) # geometry-y (absolute)
# TEXT 3
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1000) # 0CNX_YRTL
write_sint(buf, 100) # text-x (absolute)
write_sint(buf, -100) # text-y (absolute)
# RECTANGLE 4
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0001_1000) # SWHX_YRDL
write_sint(buf, 200) # geometry-x (absolute)
write_sint(buf, -200) # geometry-y (absolute)
# TEXT 5
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1000) # 0CNX_YRTL
write_sint(buf, 200) # text-x (absolute)
write_sint(buf, -200) # text-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# RECTANGLE 6
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0001_1000) # SWHX_YRDL
write_sint(buf, 100) # geometry-x (relative)
write_sint(buf, -100) # geometry-y (relative)
# TEXT 7
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1000) # 0CNX_YRTL
write_sint(buf, 100) # text-x (relative)
write_sint(buf, -100) # text-y (relative)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'B') # Cell name
# RECTANGLE 0
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0110_0011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 20) # width
write_uint(buf, 10) # height
# TEXT 1
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0100_0011) # 0CNX_YRTL
write_bstring(buf, b'B') # text string
write_uint(buf, 2) # layer
write_uint(buf, 1) # datatype
# RECTANGLE 2
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0001_1000) # SWHX_YRDL
write_sint(buf, 100) # geometry-x (absolute)
write_sint(buf, 100) # geometry-y (absolute)
# TEXT 3
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1000) # 0CNX_YRTL
write_sint(buf, 100) # text-x (absolute)
write_sint(buf, 100) # text-y (absolute)
# RECTANGLE 4
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0001_1000) # SWHX_YRDL
write_sint(buf, 200) # geometry-x (absolute)
write_sint(buf, 200) # geometry-y (absolute)
# TEXT 5
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1000) # 0CNX_YRTL
write_sint(buf, 200) # text-x (absolute)
write_sint(buf, 200) # text-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# RECTANGLE 6
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0001_1000) # SWHX_YRDL
write_sint(buf, 100) # geometry-x (relative)
write_sint(buf, 100) # geometry-y (relative)
# TEXT 7
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1000) # 0CNX_YRTL
write_sint(buf, 100) # text-x (relative)
write_sint(buf, 100) # text-y (relative)
# PLACEMENT 0
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b1000_0000) # CNXY_RAAF
write_bstring(buf, b'A') # Cell reference
# PLACEMENT 1
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_0000) # CNXY_RAAF
write_sint(buf, 50) # placement-x (relative)
write_sint(buf, 50) # placement-y (relative)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOP') # Cell name
# PLACEMENT 0
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b1000_0000) # CNXY_RAAF
write_bstring(buf, b'B') # Cell reference
# RECTANGLE 0
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0110_0011) # SWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 50) # width
write_uint(buf, 5) # height
# TEXT 1
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0100_0011) # 0CNX_YRTL
write_bstring(buf, b'TOP') # text string
write_uint(buf, 2) # layer
write_uint(buf, 1) # datatype
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 3
assert layout.cells[0].name.string == 'A'
assert layout.cells[1].name.string == 'B'
assert layout.cells[2].name.string == 'TOP'
assert not layout.cells[0].properties
assert not layout.cells[1].properties
assert not layout.cells[2].properties
geometry = layout.cells[0].geometry
assert len(geometry) == 8
for ii, gg in enumerate(geometry):
msg = f'Failed on geometry {ii} in cell A'
if ii % 2 == 0:
assert gg.width == 10, msg
assert gg.height == 20, msg
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
else:
assert gg.string.string == 'A', msg
assert gg.layer == 2, msg
assert gg.datatype == 1, msg
assert not gg.properties, msg
assert gg.x == (ii // 2) * 100, msg
assert gg.y == (ii // 2) * -100, msg
geometry = layout.cells[1].geometry
assert len(geometry) == 8
for ii, gg in enumerate(geometry):
msg = f'Failed on geometry {ii} in cell B'
if ii % 2 == 0:
assert gg.width == 20, msg
assert gg.height == 10, msg
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
else:
assert gg.string.string == 'B', msg
assert gg.layer == 2, msg
assert gg.datatype == 1, msg
assert not gg.properties, msg
assert gg.x == (ii // 2) * 100, msg
assert gg.y == (ii // 2) * 100, msg
assert layout.cells[1].placements[0].name.string == 'A'
assert layout.cells[1].placements[1].name.string == 'A'
assert layout.cells[1].placements[0].x == 0
assert layout.cells[1].placements[0].y == 0
assert layout.cells[1].placements[1].x == 50
assert layout.cells[1].placements[1].y == 50
assert layout.cells[2].placements[0].name.string == 'B'
assert layout.cells[2].placements[0].x == 0
assert layout.cells[2].placements[0].y == 0
assert layout.cells[2].geometry[0].layer == 1
assert layout.cells[2].geometry[0].datatype == 2
assert layout.cells[2].geometry[0].width == 50
assert layout.cells[2].geometry[0].height == 5
assert layout.cells[2].geometry[0].x == 0
assert layout.cells[2].geometry[0].y == 0
assert layout.cells[2].geometry[1].layer == 2
assert layout.cells[2].geometry[1].datatype == 1
assert layout.cells[2].geometry[1].string.string == 'TOP'
assert layout.cells[2].geometry[1].x == 0
assert layout.cells[2].geometry[1].y == 0

@ -0,0 +1,205 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'ABC'
assert not layout.cells[0].properties
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
# PATH 0
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) start
write_sint(buf, -5) # (extension-scheme) end
write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 0) # geometry-x (absolute)
write_sint(buf, 100) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# PATH 1
write_uint(buf, 22) # PATH record
write_byte(buf, 0b1110_1011) # EWPX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 10) # half-width
write_byte(buf, 0b0000_0000) # extension-scheme 0000_SSEE
write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 200) # geometry-y (relative)
# PATH 2
write_uint(buf, 22) # PATH record
write_byte(buf, 0b1110_1001) # EWPX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 10) # half-width
write_byte(buf, 0b0000_0100) # extension-scheme 0000_SSEE
write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 200) # geometry-y (relative)
# PATH 3
write_uint(buf, 22) # PATH record
write_byte(buf, 0b1110_1010) # EWPX_YRDL
write_uint(buf, 2) # datatype
write_uint(buf, 12) # half-width
write_byte(buf, 0b0000_0101) # extension-scheme 0000_SSEE
write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 200) # geometry-y (relative)
# PATH 4
write_uint(buf, 22) # PATH record
write_byte(buf, 0b1010_1011) # EWPX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_byte(buf, 0b0000_1010) # extension-scheme 0000_SSEE
write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt
write_uint(buf, 3) # (pointlist) dimension
write_sint(buf, 150) # (pointlist)
write_sint(buf, 50) # (pointlist)
write_sint(buf, -50) # (pointlist)
write_sint(buf, 200) # geometry-y (relative)
# PATH 5
write_uint(buf, 22) # PATH record
write_byte(buf, 0b0000_1011) # EWPX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_sint(buf, 200) # geometry-y (relative)
# PATH 6
write_uint(buf, 22) # PATH record
write_byte(buf, 0b0000_1111) # EWPX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_sint(buf, 200) # geometry-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
write_uint(buf, 16) # XYRELATIVE record
# PATH 7
write_uint(buf, 22) # PATH record
write_byte(buf, 0b0001_0101) # EWPX_YRDL
write_uint(buf, 1) # layer #NOTE: fixed
write_sint(buf, 1000) # geometry-x (relative)
write_uint(buf, 0) # repetition (reuse)
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == 8
for ii, gg in enumerate(geometry):
msg = f'Failed on path {ii}'
if ii < 7:
assert gg.y == 100 + ii * 200, msg
assert gg.x == 0, msg
else:
assert gg.x == 1000, msg
assert gg.y == 1300, msg
if ii < 5:
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
elif ii < 7:
assert gg.layer == 2, msg
assert gg.datatype == 3, msg
else:
assert gg.layer == 1, msg
assert gg.datatype == 3, msg
if ii < 6:
assert gg.repetition is None, msg
elif ii in (7, 8):
assert gg.repetition.a_count == 3, msg
assert gg.repetition.b_count == 4, msg
assert gg.repetition.a_vector == [200, 0], msg
assert gg.repetition.b_vector == [0, 300], msg
assert not gg.properties, msg
if ii < 3:
assert gg.half_width == 10, msg
else:
assert gg.half_width == 12, msg
assert len(gg.point_list) == 3, msg
assert_equal(gg.point_list, [[150, 0], [0, 50], [-50, 0]], err_msg=msg)
if ii >= 4:
assert gg.extension_start == (PathExtensionScheme.HalfWidth, None)
assert gg.extension_end == (PathExtensionScheme.HalfWidth, None)
assert geometry[0].extension_start == (PathExtensionScheme.Arbitrary, 5)
assert geometry[1].extension_start == (PathExtensionScheme.Arbitrary, 5)
assert geometry[2].extension_start == (PathExtensionScheme.Flush, None)
assert geometry[3].extension_start == (PathExtensionScheme.Flush, None)
assert geometry[0].extension_end == (PathExtensionScheme.Arbitrary, -5)
assert geometry[1].extension_end == (PathExtensionScheme.Arbitrary, -5)
assert geometry[2].extension_end == (PathExtensionScheme.Arbitrary, -5)
assert geometry[3].extension_end == (PathExtensionScheme.Flush, None)

@ -0,0 +1,895 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, InvalidDataError, write_float32, write_float64
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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.layers
def write_rectangle(buf: BufferedIOBase, pos: Tuple[int, int] = (300, -400)) -> None:
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, pos[0]) # geometry-x (absolute)
write_sint(buf, pos[1]) # geometry-y (absolute)
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_rectangle(buf)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOP') # Cell name
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 0
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b1011_0000) # CNXY_RAAF
write_bstring(buf, b'A') # cell reference
write_sint(buf, -300) # placement-x (relative)
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 1
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_0000) # CNXY_RAAF
write_sint(buf, 0) # placement-x (relative)
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 2
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_0000) # CNXY_RAAF
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 3
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0010_0000) # CNXY_RAAF
write_sint(buf, 300) # placement-x (relative)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 4
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_0001) # CNXY_RAAF
write_sint(buf, 700) # placement-x (absolute)
write_sint(buf, 400) # placement-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 5
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_0010) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
# PLACEMENT 6
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_0011) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 7
write_uint(buf, 17) # PLACEMENT (simple)
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, 16) # XYRELATIVE record
# PLACEMENT 8
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x (relative)
write_sint(buf, 0) # placement-y (relative)
write_uint(buf, 0) # repetition (reuse)
# PLACEMENT 9
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x (relative)
write_sint(buf, 0) # placement-y (relative)
write_uint(buf, 2) # repetition (3 cols.)
write_uint(buf, 1) # (repetition) count
write_uint(buf, 320) # (repetition) spacing
# PLACEMENT 10
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x (relative)
write_sint(buf, 0) # placement-y (relative)
write_uint(buf, 3) # repetition (4 rows)
write_uint(buf, 2) # (repetition) count
write_uint(buf, 310) # (repetition) spacing
# PLACEMENT 11
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x (relative)
write_sint(buf, 0) # placement-y (relative)
write_uint(buf, 4) # repetition (4 arbitrary cols.)
write_uint(buf, 2) # (repetition) dimension
write_uint(buf, 320) # (repetition) spacing
write_uint(buf, 330) # (repetition) spacing
write_uint(buf, 340) # (repetition) spacing
# PLACEMENT 12
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1111) # CNXY_RAAF
write_sint(buf, 2000) # placement-x (relative)
write_sint(buf, 0) # placement-y (relative)
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) # (repetition g-delta)
write_uint(buf, 330 << 4 | 0b1010) # (repetition) m-displacement g-delta: 330-northwest (-330, 330)
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 2
assert layout.cells[0].name.string == 'A'
assert not layout.cells[0].properties
assert not layout.cells[0].placements
assert layout.cells[1].name.string == 'TOP'
assert not layout.cells[1].properties
assert not layout.cells[1].geometry
geometry = layout.cells[0].geometry
assert len(geometry) == 1
assert geometry[0].layer == 1
assert geometry[0].datatype == 2
assert geometry[0].width == 100
assert geometry[0].height == 200
assert geometry[0].x == 300
assert geometry[0].y == -400
placements = layout.cells[1].placements
assert len(placements) == 13
for ii, pp in enumerate(placements):
msg = f'Failed on placement {ii}'
assert not pp.properties, msg
assert pp.name.string == 'A', msg
if ii < 3:
assert pp.x == -300, msg
elif ii == 3:
assert pp.x == 0, msg
elif 4 <= ii < 7:
assert pp.x == 700, msg
else:
assert pp.x == 2000 * (ii - 6), msg
if ii < 3:
assert pp.y == 400 * (ii + 1), msg
elif 7 <= ii:
assert pp.y == 0, msg
if ii < 4 or ii == 5:
assert pp.flip == False, msg
else:
assert pp.flip == True, msg
if ii < 5:
assert pp.angle == 0, msg
elif ii in (5, 6):
assert pp.angle == 90, msg
elif 7 <= ii:
assert pp.angle == 270, msg
if ii < 7:
assert pp.repetition is None, msg
elif ii in (7, 8):
assert pp.repetition.a_count == 3, msg
assert pp.repetition.b_count == 4, msg
assert pp.repetition.a_vector == [300, 0], msg
assert pp.repetition.b_vector == [0, 300], msg
assert placements[3].y == 1200
assert placements[4].y == 400
assert placements[5].y == 1400
assert placements[6].y == 2400
assert placements[9].repetition.a_count == 3
assert placements[9].repetition.b_count is None
assert placements[9].repetition.a_vector == [320, 0]
assert placements[9].repetition.b_vector is None
assert placements[10].repetition.a_count == 4
assert placements[10].repetition.b_count is None
assert placements[10].repetition.a_vector == [0, 310]
assert placements[10].repetition.b_vector is None
assert_equal(placements[11].repetition.x_displacements, [320, 330, 340])
assert_equal(placements[11].repetition.y_displacements, [0, 0, 0])
assert placements[12].repetition.a_count == 3
assert placements[12].repetition.b_count == 4
assert placements[12].repetition.a_vector == [310, 320]
assert placements[12].repetition.b_vector == [-330, 330]
def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
'''
assert variant in (2, 3, 5, 7), 'Error in test definition!'
buf.write(HEADER)
if variant in (3, 5):
write_uint(buf, 3) # CELLNAME record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 3) # CELLNAME record (implicit id 1)
write_bstring(buf, b'TOP')
if variant == 3:
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (A)
write_rectangle(buf)
if variant == 2:
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOP') # Cell name
else:
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 1) # Cell name 1 (TOP)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 0
write_uint(buf, 17) # PLACEMENT (simple)
if variant == 2:
write_byte(buf, 0b1011_0000) # CNXY_RAAF
write_bstring(buf, b'A') # cell reference
else:
write_byte(buf, 0b1111_0000) # CNXY_RAAF
write_uint(buf, 0) # cell reference
write_sint(buf, -300) # placement-x (relative)
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 1
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_0000) # CNXY_RAAF
write_sint(buf, 0) # placement-x (relative)
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 2
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_0000) # CNXY_RAAF
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 3
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0010_0000) # CNXY_RAAF
write_sint(buf, 300) # placement-x (relative)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 4
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_0001) # CNXY_RAAF
write_sint(buf, 700) # placement-x (absolute)
write_sint(buf, 400) # placement-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 5
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_0010) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
# PLACEMENT 6
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_0011) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
if variant == 2:
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_rectangle(buf)
elif variant in (5, 7):
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (A)
write_rectangle(buf)
if variant == 7:
write_uint(buf, 3) # CELLNAME record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 3) # CELLNAME record (implicit id 1)
write_bstring(buf, b'TOP')
buf.write(FOOTER)
return buf
def test_file_2() -> None:
buf = write_file_common(BytesIO(), 2)
buf.seek(0)
layout = OasisLayout.read(buf)
assert len(layout.cells) == 2
assert layout.cells[0].name.string == 'TOP'
assert not layout.cells[0].properties
assert not layout.cells[0].geometry
assert layout.cells[1].name.string == 'A'
assert not layout.cells[1].properties
assert not layout.cells[1].placements
assert not layout.cellnames
common_tests(layout, 2)
def test_file_3() -> None:
buf = write_file_common(BytesIO(), 3)
buf.seek(0)
layout = OasisLayout.read(buf)
assert len(layout.cells) == 2
assert layout.cells[0].name == 0
assert not layout.cells[1].properties
assert not layout.cells[1].geometry
assert layout.cells[1].name == 1
assert not layout.cells[0].properties
assert not layout.cells[0].placements
assert len(layout.cellnames) == 2
assert layout.cellnames[0].nstring.string == 'A'
assert layout.cellnames[1].nstring.string == 'TOP'
common_tests(layout, 3)
def test_file_4() -> None:
buf = write_file_4(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
assert len(layout.cells) == 2
assert layout.cells[0].name == 1
assert not layout.cells[0].properties
assert not layout.cells[0].geometry
assert layout.cells[1].name == 0
assert not layout.cells[1].properties
assert not layout.cells[1].placements
assert len(layout.cellnames) == 2
assert layout.cellnames[0].nstring.string == 'A'
assert layout.cellnames[1].nstring.string == 'TOP'
common_tests(layout, 4)
for ii, pp in enumerate(layout.cells[0].placements):
msg = f'Fail on placement {ii}'
assert pp.repetition.a_count == 3, msg
assert pp.repetition.b_count == 4, msg
assert pp.repetition.a_vector == [20, 0], msg
assert pp.repetition.b_vector == [0, 30], msg
def test_file_5() -> None:
buf = write_file_common(BytesIO(), 5)
buf.seek(0)
layout = OasisLayout.read(buf)
assert len(layout.cells) == 2
assert layout.cells[0].name == 1
assert not layout.cells[0].properties
assert not layout.cells[0].geometry
assert layout.cells[1].name == 0
assert not layout.cells[1].properties
assert not layout.cells[1].placements
assert len(layout.cellnames) == 2
assert layout.cellnames[0].nstring.string == 'A'
assert layout.cellnames[1].nstring.string == 'TOP'
common_tests(layout, 5)
def test_file_7() -> None:
buf = write_file_common(BytesIO(), 7)
buf.seek(0)
layout = OasisLayout.read(buf)
assert len(layout.cells) == 2
assert layout.cells[0].name == 1
assert not layout.cells[0].properties
assert not layout.cells[0].geometry
assert layout.cells[1].name == 0
assert not layout.cells[1].properties
assert not layout.cells[1].placements
assert len(layout.cellnames) == 2
assert layout.cellnames[0].nstring.string == 'A'
assert layout.cellnames[1].nstring.string == 'TOP'
common_tests(layout, 7)
def common_tests(layout: OasisLayout, variant: int) -> None:
base_tests(layout)
if variant == 3:
geom_cell = 0
top_cell = 1
else:
geom_cell = 1
top_cell = 0
geometry = layout.cells[geom_cell].geometry
assert len(geometry) == 1
assert geometry[0].layer == 1
assert geometry[0].datatype == 2
assert geometry[0].width == 100
assert geometry[0].height == 200
assert geometry[0].x == 300
assert geometry[0].y == -400
placements = layout.cells[top_cell].placements
assert len(placements) == 7
for ii, pp in enumerate(placements):
msg = f'Failed on placement {ii}'
assert not pp.properties, msg
if variant == 2:
assert pp.name.string == 'A', msg
else:
assert pp.name == 0, msg
if ii < 3:
assert pp.x == -300, msg
elif ii == 3:
assert pp.x == 0, msg
else:
assert pp.x == 700, msg
if ii < 3:
assert pp.y == 400 * (ii + 1), msg
if ii in (4, 6):
assert pp.flip == True, msg
else:
assert pp.flip == False, msg
if ii in (5, 6):
assert pp.angle == 90, msg
else:
assert pp.angle == 0, msg
if variant != 4:
assert pp.repetition is None, msg
assert placements[3].y == 1200
assert placements[4].y == 400
assert placements[5].y == 1400
assert placements[6].y == 2400
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 3) # CELLNAME record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 3) # CELLNAME record (implicit id 1)
write_bstring(buf, b'TOP')
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 1) # Cell name 1 (TOP)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 0
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b1111_1000) # CNXY_RAAF
write_uint(buf, 0) # cell reference
write_sint(buf, -300) # placement-x (relative)
write_sint(buf, 400) # placement-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 20) # (repetition) x-spacing
write_uint(buf, 30) # (repetition) y-spacing
# PLACEMENT 1
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1000) # CNXY_RAAF
write_sint(buf, 0) # placement-x (relative)
write_sint(buf, 400) # placement-y (relative)
write_uint(buf, 0) # repetition (reuse)
# PLACEMENT 2
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_1000) # CNXY_RAAF
write_sint(buf, 400) # placement-y (relative)
write_uint(buf, 0) # repetition (reuse)
# PLACEMENT 3
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0010_1000) # CNXY_RAAF
write_sint(buf, 300) # placement-x (relative)
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 4
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0011_1001) # CNXY_RAAF
write_sint(buf, 700) # placement-x (absolute)
write_sint(buf, 400) # placement-y (absolute)
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 5
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_1010) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 0) # repetition (reuse)
# PLACEMENT 6
write_uint(buf, 17) # PLACEMENT (simple)
write_byte(buf, 0b0001_1011) # CNXY_RAAF
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 0) # repetition (reuse)
write_uint(buf, 13) # CELL record (name ref.)
write_uint(buf, 0) # Cell name 0 (A)
write_rectangle(buf)
buf.write(FOOTER)
return buf
def write_file_6(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOPTOP') # Cell name
write_uint(buf, 16) # XYRELATIVE record
write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan)
write_byte(buf, 0b1011_0110) # CNXY_RMAF
write_bstring(buf, b'TOP') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 0.5) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 90.0) # (angle)
write_sint(buf, 100) # placement-x (relative)
write_sint(buf, 0) # placement-y (relative)
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0011_0000) # CNXY_RMAF
write_sint(buf, 100) # placement-x (relative)
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOP') # Cell name
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 0
write_uint(buf, 18) # PLACEMENT (mag 0.5, manhattan)
write_byte(buf, 0b1011_0110) # CNXY_RMAF
write_bstring(buf, b'A') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 0.5) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 0.0) # (angle)
write_sint(buf, -150) # placement-x (relative)
write_sint(buf, 200) # placement-y (relative)
# PLACEMENT 1
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0011_0000) # CNXY_RMAF
write_sint(buf, -150) # placement-x (relative)
write_sint(buf, 600) # placement-y (relative)
# PLACEMENT 2
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0001_0000) # CNXY_RMAF
write_sint(buf, 400) # placement-y (relative)
# PLACEMENT 3
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0010_0000) # CNXY_RMAF
write_sint(buf, 300) # placement-x (relative)
write_uint(buf, 15) # XYABSOLUTE record
# PLACEMENT 4
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0011_0001) # CNXY_RMAF
write_sint(buf, 700) # placement-x (absolute)
write_sint(buf, 400) # placement-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# PLACEMENT 5
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0001_0010) # CNXY_RMAF
write_uint(buf, 0) # angle (uint, positive)
write_uint(buf, 90) # (angle)
write_sint(buf, 1000) # placement-y (relative)
# PLACEMENT 6
write_uint(buf, 18) # PLACEMENT (no mag, manhattan)
write_byte(buf, 0b0001_0011) # CNXY_RMAF
write_uint(buf, 1) # angle (uint, negative)
write_uint(buf, 90) # (angle)
write_sint(buf, 1000) # placement-y (relative)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_rectangle(buf)
buf.write(FOOTER)
return buf
def test_file_6() -> None:
buf = write_file_6(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 3
assert layout.cells[0].name.string == 'TOPTOP'
assert not layout.cells[0].properties
assert not layout.cells[0].geometry
assert layout.cells[1].name.string == 'TOP'
assert not layout.cells[1].properties
assert not layout.cells[1].geometry
assert layout.cells[2].name.string == 'A'
assert not layout.cells[2].properties
assert not layout.cells[2].placements
geometry = layout.cells[2].geometry
assert len(geometry) == 1
assert geometry[0].layer == 1
assert geometry[0].datatype == 2
assert geometry[0].width == 100
assert geometry[0].height == 200
assert geometry[0].x == 300
assert geometry[0].y == -400
placements = layout.cells[1].placements
assert len(placements) == 7
for ii, pp in enumerate(placements):
msg = f'Failed on placement {ii} in cell TOP'
assert not pp.properties, msg
assert pp.name.string == 'A', msg
assert pp.flip == (ii in (4, 6)), msg
assert pp.repetition is None, msg
if ii == 0:
assert pp.magnification == 0.5, msg
else:
assert pp.magnification is None, msg
assert pp.x == [-150, -300, -300, 0, 700, 700, 700][ii], msg
assert pp.y == [200, 800, 1200, 1200, 400, 1400, 2400][ii], msg
assert pp.angle == [0, None, None, None, None, 90, -90][ii], msg
placements2 = layout.cells[0].placements
assert len(placements2) == 2
for ii, pp in enumerate(placements2):
msg = f'Failed on placement {ii} in cell TOPTOP'
assert not pp.properties, msg
assert pp.name.string == 'TOP', msg
assert not pp.flip, msg
assert pp.repetition is None, msg
assert pp.angle == [90, None][ii], msg
assert pp.magnification == [0.5, None][ii], msg
assert pp.x == [100, 200][ii], msg
assert pp.y == [0, 1000][ii], msg
def write_file_8(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOPTOP') # Cell name
write_uint(buf, 15) # XYABSOLUTE record
write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle)
write_byte(buf, 0b1011_0110) # CNXY_RMAF
write_bstring(buf, b'TOP') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 0.5) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 22.5) # (angle)
write_sint(buf, 100) # placement-x (absolute)
write_sint(buf, 0) # placement-y (absolute)
write_uint(buf, 18) # PLACEMENT (mag 1.0, manhattan)
write_byte(buf, 0b1011_0110) # CNXY_RMAF
write_bstring(buf, b'TOP') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 1.0) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 0.0) # (angle)
write_sint(buf, 1100) # placement-x (absolute)
write_sint(buf, 0) # placement-y (absolute)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'TOP') # Cell name
write_uint(buf, 18) # PLACEMENT (mag 2.0, manhattan)
write_byte(buf, 0b1011_0110) # CNXY_RMAF
write_bstring(buf, b'A') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 2.0) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 0.0) # (angle)
write_sint(buf, -100) # placement-x (absolute)
write_sint(buf, 100) # placement-y (absolute)
write_uint(buf, 18) # PLACEMENT (mag 1.0, arbitrary angle)
write_byte(buf, 0b1011_0110) # CNXY_RMAF
write_bstring(buf, b'A') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 1.0) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 45.0) # (angle)
write_sint(buf, -150) # placement-x (absolute)
write_sint(buf, 1100) # placement-y (absolute)
write_uint(buf, 18) # PLACEMENT (mag 0.5, arbitrary angle)
write_byte(buf, 0b1011_1111) # CNXY_RMAF
write_bstring(buf, b'A') # Cell reference
write_uint(buf, 6) # magnitude, float32
write_float32(buf, 0.5) # (magnitude)
write_uint(buf, 7) # angle, float64
write_float64(buf, 135.0) # (angle)
write_sint(buf, -200) # placement-x (absolute)
write_sint(buf, 2100) # 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, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'A') # Cell name
write_rectangle(buf, pos=(30, -40))
buf.write(FOOTER)
return buf
def test_file_8() -> None:
buf = write_file_8(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells) == 3
assert layout.cells[0].name.string == 'TOPTOP'
assert not layout.cells[0].properties
assert not layout.cells[0].geometry
assert layout.cells[1].name.string == 'TOP'
assert not layout.cells[1].properties
assert not layout.cells[1].geometry
assert layout.cells[2].name.string == 'A'
assert not layout.cells[2].properties
assert not layout.cells[2].placements
geometry = layout.cells[2].geometry
assert len(geometry) == 1
assert geometry[0].layer == 1
assert geometry[0].datatype == 2
assert geometry[0].width == 100
assert geometry[0].height == 200
assert geometry[0].x == 30
assert geometry[0].y == -40
placements = layout.cells[1].placements
assert len(placements) == 3
for ii, pp in enumerate(placements):
msg = f'Failed on placement {ii} in cell TOP'
assert not pp.properties, msg
assert pp.name.string == 'A', msg
assert pp.flip == (ii == 2), msg
assert pp.magnification == [2, 1, 0.5][ii], msg
assert pp.angle == [0, 45, 135][ii], msg
assert pp.x == [-100, -150, -200][ii], msg
assert pp.y == [100, 1100, 2100][ii], msg
if ii < 2:
assert pp.repetition is None, msg
assert placements[2].repetition.a_count == 3
assert placements[2].repetition.b_count == 4
assert placements[2].repetition.a_vector == [200, 0]
assert placements[2].repetition.b_vector == [0, 300]
placements2 = layout.cells[0].placements
assert len(placements2) == 2
for ii, pp in enumerate(placements2):
msg = f'Failed on placement {ii} in cell TOPTOP'
assert not pp.properties, msg
assert pp.name.string == 'TOP', msg
assert not pp.flip, msg
assert pp.repetition is None, msg
assert pp.angle == [22.5, 0][ii], msg
assert pp.magnification == [0.5, 1.0][ii], msg
assert pp.x == [100, 1100][ii], msg
assert pp.y == [0, 0][ii], msg

@ -0,0 +1,450 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte
from ..basic import InvalidRecordError, 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
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'ABC'
assert not layout.cells[0].properties
def common_tests(layout: OasisLayout) -> None:
geometry = layout.cells[0].geometry
assert len(geometry) == 12
assert geometry[0].x == 0
assert geometry[0].y == 100
assert geometry[1].x == -200
assert geometry[1].y == 400
assert geometry[2].x == 0
assert geometry[2].y == 400
assert geometry[3].x == 0
assert geometry[3].y == 1000
assert geometry[4].x == 200
assert geometry[4].y == 1000
assert geometry[5].x == 400
assert geometry[5].y == 1000
assert geometry[6].x == 700
assert geometry[6].y == 1000
assert geometry[7].x == 900
assert geometry[7].y == 1000
assert geometry[8].x == 1100
assert geometry[8].y == 1000
assert geometry[9].x == 0
assert geometry[9].y == 2000
assert geometry[10].x == 1000
assert geometry[10].y == 2000
assert geometry[11].x == 2000
assert geometry[11].y == 2000
for ii, gg in enumerate(geometry):
msg = f'Failed on polygon {ii}'
if ii < 2:
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
elif ii < 10:
assert gg.layer == 2, msg
assert gg.datatype == 3, msg
else:
assert gg.layer == 2, msg
assert gg.datatype == 1, msg
if ii < 9:
assert gg.repetition is None, msg
elif ii in (9, 10):
assert gg.repetition.a_count == 3, msg
assert gg.repetition.b_count == 4, msg
assert gg.repetition.a_vector == [200, 0], msg
assert gg.repetition.b_vector == [0, 300], msg
assert geometry[11].repetition.y_displacements == [200, 300]
for ii in range(4):
msg = f'Fail on poly {ii}'
assert len(geometry[0].point_list) == 6, msg
assert_equal(geometry[0].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50],
[-100, 0], [0, -100]], err_msg=msg)
assert len(geometry[4].point_list) == 6
assert_equal(geometry[4].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]])
assert len(geometry[5].point_list) == 8
assert_equal(geometry[5].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50], [-50, 0], [0, -50], [-50, 0], [0, -50]])
assert len(geometry[6].point_list) == 9
assert_equal(geometry[6].point_list, [[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [0, -50], [50, -50], [25, 0]])
assert len(geometry[7].point_list) == 9
assert_equal(geometry[7].point_list, [[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [40, 0]])
assert len(geometry[8].point_list) == 9
assert_equal(geometry[8].point_list,
numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25], [45, -575]], axis=0))
for ii in range(9, 12):
msg = f'Fail on poly {ii}'
assert len(geometry[ii].point_list) == 6, msg
assert_equal(geometry[ii].point_list, [[0, 150], [50, 0], [0, -50], [50, 0], [0, -100], [-100, 0]], err_msg=msg)
def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
'''
assert variant in (1, 3), 'Error in test!!'
buf.write(HEADER)
if variant == 3:
write_uint(buf, 7) # PROPNAME record (implict id 0)
write_bstring(buf, b'PROP0') # property name
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
# POLYGON 0
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-fisrt
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, 0) # geometry-x (absolute)
write_sint(buf, 100) # geometry-y (absolute)
if variant == 3:
# PROPERTY 0
write_uint(buf, 28) # PROPERTY record (explicit)
write_byte(buf, 0b0001_0110) # UUUU_VCNS
write_uint(buf, 0) # propname id
write_uint(buf, 2) # property value (real: positive reciprocal)
write_uint(buf, 5) # (real) 1/5
write_uint(buf, 16) # XYRELATIVE record
# Polygon 1
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-fisrt
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, -200) # geometry-x (relative)
write_sint(buf, 300) # geometry-y (relative)
if variant == 3:
# PROPERTY 1
write_uint(buf, 29) # PROPERTY record (repeat)
write_uint(buf, 15) # XYABSOLUTE record
# Polygon 2
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 0) # pointlist: 1-delta, horiz-fisrt
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, 0) # geometry-x (absolute)
if variant == 3:
# PROPERTY 2
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 3
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0000_1000) # 00PX_YRDL
write_sint(buf, 1000) # geometry-y (absolute)
if variant == 3:
# PROPERTY 3
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 4
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 1) # pointlist: 1-delta, vert-fisrt
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, 200) # geometry-x (absolute)
if variant == 3:
# PROPERTY 4
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 5
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 2) # pointlist: 2-delta
write_uint(buf, 7) # (pointlist) dimension
write_uint(buf, 150 << 2 | 0b00) # (pointlist)
write_uint(buf, 50 << 2 | 0b01) # (pointlist)
write_uint(buf, 50 << 2 | 0b10) # (pointlist)
write_uint(buf, 50 << 2 | 0b01) # (pointlist)
write_uint(buf, 50 << 2 | 0b10) # (pointlist)
write_uint(buf, 50 << 2 | 0b11) # (pointlist)
write_uint(buf, 50 << 2 | 0b10) # (pointlist)
write_sint(buf, 400) # geometry-x (absolute)
if variant == 3:
# PROPERTY 5
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 6
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 3) # pointlist: 3-delta
write_uint(buf, 8) # (pointlist) dimension
write_uint(buf, 25 << 3 | 0b000) # (pointlist)
write_uint(buf, 50 << 3 | 0b100) # (pointlist)
write_uint(buf, 50 << 3 | 0b001) # (pointlist)
write_uint(buf, 50 << 3 | 0b101) # (pointlist)
write_uint(buf, 50 << 3 | 0b010) # (pointlist)
write_uint(buf, 50 << 3 | 0b110) # (pointlist)
write_uint(buf, 50 << 3 | 0b011) # (pointlist)
write_uint(buf, 50 << 3 | 0b111) # (pointlist)
write_sint(buf, 700) # geometry-x (absolute)
if variant == 3:
# PROPERTY 6
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 7
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 4) # pointlist: g-delta
write_uint(buf, 8) # (pointlist) dimension
write_uint(buf, 25 << 4 | 0b0000) # (pointlist)
write_uint(buf, 50 << 4 | 0b1000) # (pointlist)
write_uint(buf, 50 << 4 | 0b0010) # (pointlist)
write_uint(buf, 50 << 2 | 0b11) # (pointlist)
write_sint(buf, 50)
write_uint(buf, 50 << 4 | 0b0100) # (pointlist)
write_uint(buf, 50 << 4 | 0b1100) # (pointlist)
write_uint(buf, 10 << 2 | 0b01) # (pointlist)
write_sint(buf, -75 )
write_uint(buf, 25 << 4 | 0b1110) # (pointlist)
write_sint(buf, 900) # geometry-x (absolute)
if variant == 3:
# PROPERTY 7
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 8
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 5) # pointlist: double g-delta
write_uint(buf, 8) # (pointlist) dimension
write_uint(buf, 25 << 4 | 0b0000) # (pointlist)
write_uint(buf, 50 << 4 | 0b1000) # (pointlist)
write_uint(buf, 50 << 4 | 0b0010) # (pointlist)
write_uint(buf, 50 << 2 | 0b11) # (pointlist)
write_sint(buf, 50)
write_uint(buf, 50 << 4 | 0b0100) # (pointlist)
write_uint(buf, 50 << 4 | 0b1100) # (pointlist)
write_uint(buf, 10 << 2 | 0b01) # (pointlist)
write_sint(buf, -75 )
write_uint(buf, 25 << 4 | 0b1110) # (pointlist)
write_sint(buf, 1100) # geometry-x (absolute)
if variant == 3:
# PROPERTY 8
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 9
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_1111) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 1) # pointlist: 1-delta (vert. 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, 0) # geometry-x (absolute)
write_sint(buf, 2000) # geometry-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, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
if variant == 3:
# PROPERTY 9
write_uint(buf, 29) # PROPERTY record (repeat)
write_uint(buf, 16) # XYRELATIVE record
# Polygon 10
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0110) # 00PX_YRDL
write_uint(buf, 1) # datatype
write_uint(buf, 1) # pointlist: 1-delta (vert. 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, 1000) # geometry-x (relative)
write_uint(buf, 0) # repetition (reuse)
if variant == 3:
# PROPERTY 10
write_uint(buf, 29) # PROPERTY record (repeat)
# Polygon 11
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0110) # 00PX_YRDL
write_uint(buf, 1) # datatype
write_uint(buf, 1) # pointlist: 1-delta (vert. 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, 1000) # geometry-x (relative)
write_uint(buf, 6) # repetition (3 rows)
write_uint(buf, 1) # (repetition) dimension
write_uint(buf, 200) # (repetition) y-delta
write_uint(buf, 300) # (repetition) y-delta
if variant == 3:
# PROPERTY 11
write_uint(buf, 29) # PROPERTY record (repeat)
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_common(BytesIO(), 1)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
common_tests(layout)
assert not layout.propnames
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
assert not gg.properties, f'Fail on polygon {ii}'
def write_file_2(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 15) # XYRELATIVE record
# POLYGON 0
write_uint(buf, 21) # POLYGON record
write_byte(buf, 0b0011_0011) # 00PX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 4) # pointlist: g-delta
write_uint(buf, 8002) # (pointlist) dimension
write_uint(buf, 1000 << 2 | 0b11) # (pointlist)
write_sint(buf, 0) # (pointlist)
for _ in range(4000):
write_uint(buf, 10 << 2 | 0b01) # (pointlist)
write_sint(buf, 20) # (pointlist)
write_uint(buf, 10 << 2 | 0b11) # (pointlist)
write_sint(buf, 20) # (pointlist)
write_uint(buf, 1000 << 2 | 0b01) # (pointlist)
write_sint(buf, 0) # (pointlist)
write_sint(buf, 0) # geometry-x (absolute)
buf.write(FOOTER)
return buf
def test_file_2() -> None:
buf = write_file_2(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.cells[0].geometry) == 1
poly = layout.cells[0].geometry[0]
assert poly.layer == 2
assert poly.datatype == 3
assert poly.x == 0
assert poly.y == 0
assert len(poly.point_list) == 8002 + 1
assert_equal(poly.point_list,
([[-1000, 0]]
+ [[(-1) ** nn * 10, 20] for nn in range(8000)]
+ [[1000, 0], [0, -20 * 8000]]))
def test_file_3() -> None:
buf = write_file_common(BytesIO(), 3)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
common_tests(layout)
assert len(layout.propnames) == 1
assert layout.propnames[0].string == 'PROP0'
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
msg = f'Fail on polygon {ii}'
assert len(gg.properties) == 1, msg
assert gg.properties[0].name == 0, msg
assert len(gg.properties[0].values) == 1, msg
assert gg.properties[0].values[0] * 5 == 1, msg

File diff suppressed because it is too large Load Diff

@ -0,0 +1,279 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte
from ..basic import InvalidRecordError, 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
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'ABC'
assert not layout.cells[0].properties
geometry = layout.cells[0].geometry
assert geometry[0].x == 300
assert geometry[0].y == -400
assert geometry[1].x == 400
assert geometry[1].y == -500
assert geometry[2].x == 600
assert geometry[2].y == -300
assert geometry[3].x == 800
assert geometry[3].y == -300
assert geometry[4].y == -600
assert geometry[5].y == -900
assert geometry[6].y == -1200
assert geometry[7].y == -1500
assert geometry[8].y == -1800
assert geometry[9].y == 500
assert geometry[10].y == 2000
for ii, gg in enumerate(geometry[3:]):
assert gg.x == 800, f'Failed on rectangle {ii + 3}'
for ii, gg in enumerate(geometry):
msg = f'Failed on rectangle {ii}'
if ii < 4:
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
else:
assert gg.layer == 2, msg
assert gg.datatype == 3, msg
if ii < 7:
assert gg.width == 100, msg
assert gg.height == 200, msg
elif ii == 7:
assert gg.width == 150, msg
assert gg.height is None, msg
else:
assert gg.width == 150, msg
assert gg.height == 150, msg
if ii < 9:
assert gg.repetition is None, msg
assert geometry[9].repetition.a_count == 3
assert geometry[9].repetition.b_count == 4
assert geometry[9].repetition.a_vector == [200, 0]
assert geometry[9].repetition.b_vector == [0, 300]
assert geometry[10].repetition.x_displacements == [200, 300]
def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
'''
assert variant in (1, 2), 'Error in test!!'
buf.write(HEADER)
if variant == 2:
write_uint(buf, 7) # PROPNAME record (implict id 0)
write_bstring(buf, b'PROP0') # property name
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # 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 (absolute)
write_sint(buf, -400) # geometry-y (absolute)
if variant == 2:
# PROPERTY 0
write_uint(buf, 28) # PROPERTY record (explicit)
write_byte(buf, 0b0001_0110) # UUUU_VCNS
write_uint(buf, 0) # propname id
write_uint(buf, 2) # property value (real: positive reciprocal)
write_uint(buf, 5) # (real) 1/5
write_uint(buf, 16) # XYRELATIVE record
# 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, 100) # geometry-x (relative)
write_sint(buf, -100) # geometry-y (relative)
if variant == 2:
# PROPERTY 1
write_uint(buf, 29) # PROPERTY record (repeat)
write_uint(buf, 15) # XYABSOLUTE record
# 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, 600) # geometry-x (absolute)
write_sint(buf, -300) # geometry-y (absolute)
if variant == 2:
# PROPERTY 2
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 3
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0111_0011) # 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, 800) # geometry-x (absolute)
if variant == 2:
# PROPERTY 3
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 4
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0110_1011) # SWHX_YRDL
write_uint(buf, 2) # layer
write_uint(buf, 3) # datatype
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, -600) # geometry-y (absolute)
if variant == 2:
# PROPERTY 4
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 5
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0110_1000) # SWHX_YRDL
write_uint(buf, 100) # width
write_uint(buf, 200) # height
write_sint(buf, -900) # geometry-y (absolute)
if variant == 2:
# PROPERTY 5
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 6
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0000_1000) # SWHX_YRDL
write_sint(buf, -1200) # geometry-y (absolute)
if variant == 2:
# PROPERTY 6
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 7
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b1100_1000) # SWHX_YRDL
write_uint(buf, 150) # width
write_sint(buf, -1500) # geometry-y (absolute)
if variant == 2:
# PROPERTY 7
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 8
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0000_1000) # SWHX_YRDL
write_sint(buf, -1800) # geometry-y (absolute)
if variant == 2:
# PROPERTY 8
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 9
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0000_1100) # SWHX_YRDL
write_sint(buf, 500) # geometry-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, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
if variant == 2:
# PROPERTY 9
write_uint(buf, 29) # PROPERTY record (repeat)
# RECTANGLE 10
write_uint(buf, 20) # RECTANGLE record
write_byte(buf, 0b0000_1100) # SWHX_YRDL
write_sint(buf, 2000) # geometry-y (absolute)
write_uint(buf, 4) # repetition (3 arbitrary cols.)
write_uint(buf, 1) # (repetition) dimension
write_uint(buf, 200) # (repetition) x-delta
write_uint(buf, 300) # (repetition) x-delta
if variant == 2:
# PROPERTY 10
write_uint(buf, 29) # PROPERTY record (repeat)
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_common(BytesIO(), 1)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert not layout.propnames
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
assert not gg.properties, f'Fail on rectangle {ii}'
def test_file_2() -> None:
buf = write_file_common(BytesIO(), 2)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
assert len(layout.propnames) == 1
assert layout.propnames[0].string == 'PROP0'
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
msg = f'Failed on rectangle {ii}'
assert len(gg.properties) == 1, msg
prop = gg.properties[0]
assert prop.name == 0, msg
assert len(prop.values) == 1, msg
assert prop.values[0].numerator == 1, msg
assert prop.values[0].denominator == 5, msg

@ -0,0 +1,738 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte
from ..basic import InvalidRecordError, InvalidDataError
from ..basic import GridRepetition, ArbitraryRepetition
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.propnames
assert not layout.xnames
assert not layout.cellnames
assert not layout.propstrings
assert not layout.layers
def common_tests(layout: OasisLayout) -> None:
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'ABC'
geometry = layout.cells[0].geometry
geometry[0].layer == 1
geometry[0].datatype == 2
for ii, gg in enumerate(geometry[1:]):
assert gg.layer == 2, f'textstring #{ii + 1}'
assert gg.datatype == 1, f'textstring #{ii + 1}'
assert geometry[0].x == 100
assert geometry[0].y == -200
assert geometry[1].x == 200
assert geometry[1].y == -400
assert geometry[2].y == -400
for ii, gg in enumerate(geometry[2:]):
assert gg.x == 300, f'textstring #{ii + 2}'
for ii, gg in enumerate(geometry[3:]):
assert gg.y == -300 - 200 * ii, f'textstring #{ii + 3}'
for ii, gg in enumerate(geometry):
if ii < 4:
assert gg.repetition is None, f'textstring #{ii}'
elif ii in (4, 5, 6, 7, 12, 13, 14, 15):
assert isinstance(gg.repetition, GridRepetition), f'textstring #{ii}'
else:
assert isinstance(gg.repetition, ArbitraryRepetition), f'textstring #{ii}'
for ii in (4, 5):
assert geometry[ii].repetition.a_count == 3, f'textstring #{ii}'
assert geometry[ii].repetition.b_count == 4, f'textstring #{ii}'
assert geometry[ii].repetition.a_vector == [10, 0], f'textstring #{ii}'
assert geometry[ii].repetition.b_vector == [0, 12], f'textstring #{ii}'
assert geometry[6].repetition.a_count == 3
assert geometry[6].repetition.a_vector == [10, 0]
assert geometry[7].repetition.a_count == 4
assert geometry[7].repetition.a_vector == [0, 12]
assert geometry[8].repetition.x_displacements == [12, 13, 14]
assert geometry[9].repetition.x_displacements == [4 * 3, 5 * 3, 6 * 3]
assert geometry[10].repetition.y_displacements == [10, 11]
assert geometry[11].repetition.y_displacements == [2 * 5, 3 * 5]
assert geometry[12].repetition.a_count == 3
assert geometry[12].repetition.b_count == 4
assert geometry[12].repetition.a_vector == [10, 0]
assert geometry[12].repetition.b_vector == [-11, -12]
assert geometry[13].repetition.a_count == 3
assert geometry[13].repetition.b_count == 4
assert geometry[13].repetition.a_vector == [11, 12]
assert geometry[13].repetition.b_vector == [-10, 10]
assert geometry[14].repetition.a_count == 3
assert geometry[14].repetition.b_count == None
assert geometry[14].repetition.a_vector == [11, 12]
assert geometry[14].repetition.b_vector is None
assert geometry[15].repetition.a_count == 4
assert geometry[15].repetition.b_count == None
assert geometry[15].repetition.a_vector == [-10, 10]
assert geometry[15].repetition.b_vector is None
assert geometry[17].repetition.x_displacements == [-11, 10]
assert geometry[17].repetition.y_displacements == [12, -10]
assert geometry[19].repetition.x_displacements == [-12, 9]
assert geometry[19].repetition.y_displacements == [12, -9]
def write_file_common(buf: BufferedIOBase, variant: int) -> BufferedIOBase:
'''
Single cell with explicit name 'XYZ'
'''
assert variant in (1, 2, 5, 12), 'Error in test!!'
buf.write(HEADER)
if variant == 2:
write_uint(buf, 6) # TEXTSTRING record (explicit id)
write_bstring(buf, b'A')
write_uint(buf, 1) # id
write_uint(buf, 6) # TEXTSTRING record (explicit id)
write_bstring(buf, b'B')
write_uint(buf, 2) # id
elif variant == 5:
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 5) # TEXTSTRING record (implicit id 1)
write_bstring(buf, b'B')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
# TEXT 0
write_uint(buf, 19) # TEXT record
if variant == 1:
write_byte(buf, 0b0101_1011) # 0CNX_YRTL
write_bstring(buf, b'TEXT_ABC') # text string
elif variant in (2, 5, 12):
write_byte(buf, 0b0111_1011) # 0CNX_YRTL
write_uint(buf, 1) # textstring id
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
write_uint(buf, 16) # XYRELATIVE
# TEXT 1
write_uint(buf, 19) # TEXT record
if variant == 1:
write_byte(buf, 0b0101_1011) # 0CNX_YRTL
write_bstring(buf, b'TEXT_ABC') # text string
elif variant in (2, 12):
write_byte(buf, 0b0111_1011) # 0CNX_YRTL
write_uint(buf, 2) # textstring id
elif variant == 5:
write_byte(buf, 0b0111_1011) # 0CNX_YRTL
write_uint(buf, 0) # textstring id
write_uint(buf, 2) # layer
write_uint(buf, 1) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
write_uint(buf, 15) # XYABSOLUTE
# TEXT 2
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_0000) # 0CNX_YRTL
write_sint(buf, 300) # x
# TEXT 3
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1000) # 0CNX_YRTL
write_sint(buf, -300) # y
write_uint(buf, 16) # XYRELATIVE
# TEXT 4
write_uint(buf, 19) # TEXT record
if variant == 1:
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
elif variant in (2, 5, 12):
write_byte(buf, 0b0110_1100) # 0CNX_YRTL
write_uint(buf, 1) # textstring id
write_sint(buf, -200) # y
write_uint(buf, 1) # repetition (3x4)
write_uint(buf, 1) # (repetition)
write_uint(buf, 2) # (repetition)
write_uint(buf, 10) # (repetition)
write_uint(buf, 12) # (repetition)
# TEXT 5
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 0) # repetition (reuse)
# TEXT 6
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 2) # repetition (3 cols.)
write_uint(buf, 1) # (repetition)
write_uint(buf, 10) # (repetition)
# TEXT 7
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 3) # repetition (4 cols.)
write_uint(buf, 2) # (repetition)
write_uint(buf, 12) # (repetition)
# TEXT 8
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 4) # repetition (4 arbitrary cols.)
write_uint(buf, 2) # (repetition)
write_uint(buf, 12) # (repetition)
write_uint(buf, 13) # (repetition)
write_uint(buf, 14) # (repetition)
# TEXT 9
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 5) # repetition (4 arbitrary cols., grid 3)
write_uint(buf, 2) # (repetition)
write_uint(buf, 3) # (repetition)
write_uint(buf, 4) # (repetition)
write_uint(buf, 5) # (repetition)
write_uint(buf, 6) # (repetition)
# TEXT 10
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 6) # repetition (4 arbitrary cols., grid 3)
write_uint(buf, 1) # (repetition)
write_uint(buf, 10) # (repetition)
write_uint(buf, 11) # (repetition)
# TEXT 11
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 7) # repetition (3 arbitrary cols., grid 5)
write_uint(buf, 1) # (repetition)
write_uint(buf, 5) # (repetition)
write_uint(buf, 2) # (repetition)
write_uint(buf, 3) # (repetition)
# TEXT 12
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 8) # repetition (3x4 matrix w/arb. vectors)
write_uint(buf, 1) # (repetition) n-dimension
write_uint(buf, 2) # (repetition) m-dimension
write_uint(buf, (10 << 4) | 0b0000) # (repetition) n-displacement g-delta: 10/east = (10, 0)
write_uint(buf, (11 << 2) | 0b11) # (repetition) m-displacement g-delta: (-11, -12)
write_sint(buf, -12) # (repetition g-delta)
# TEXT 13
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 8) # repetition (3x4 matrix w/arb. vectors)
write_uint(buf, 1) # (repetition) n-dimension
write_uint(buf, 2) # (repetition) m-dimension
write_uint(buf, (11 << 2) | 0b01) # (repetition) n-displacement g-delta: (11, 12)
write_sint(buf, 12)
write_uint(buf, (10 << 4) | 0b1010) # (repetition) n-displacement g-delta: 10/northwest = (-10, 10)
# TEXT 14
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 9) # repetition (3x arb. vector)
write_uint(buf, 1) # (repetition) dimension
write_uint(buf, (11 << 2) | 0b01) # (repetition) n-displacement g-delta: (11, 12)
write_sint(buf, 12) # (repetition g-delta)
# TEXT 15
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 9) # repetition (4x arb. vector)
write_uint(buf, 2) # (repetition) dimension
write_uint(buf, (10 << 4) | 0b1010) # (repetition) n-displacement g-delta: 10/northwest = (-10, 10)
# TEXT 16
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 10) # repetition (9x / 8 arb. displacements)
write_uint(buf, 7) # (repetition) dimension
write_uint(buf, (10 << 4) | 0b0000) # (repetition) g-delta: 10/east = (10, 0)
write_uint(buf, (10 << 4) | 0b0010) # (repetition) g-delta: 10/north = (0, 10)
write_uint(buf, (10 << 4) | 0b0100) # (repetition) g-delta: 10/west = (-10, 0)
if variant == 12:
write_uint(buf, (10 << 4) | 0b0110) # (repetition) g-delta: 10/south = (0, -10)
else:
write_uint(buf, (40 << 4) | 0b0110) # (repetition) g-delta: 40/south = (0, -40)
write_uint(buf, (10 << 4) | 0b1000) # (repetition) g-delta: 10/northeast = (10, 10)
write_uint(buf, (10 << 4) | 0b1010) # (repetition) g-delta: 10/northwest = (-10, 10)
write_uint(buf, (10 << 4) | 0b1100) # (repetition) g-delta: 10/southwest = (-10, -10)
if variant == 12:
write_uint(buf, (10 << 4) | 0b1110) # (repetition) g-delta: 20/southeast = (10, -10)
else:
write_uint(buf, (20 << 4) | 0b1110) # (repetition) g-delta: 20/southeast = (20, -20)
# TEXT 17
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 10) # repetition (3x / 2 arb. displacements)
write_uint(buf, 1) # (repetition) dimension
write_uint(buf, (11 << 2) | 0b11) # (repetition) g-delta: (-11, 12)
write_sint(buf, 12) # (repetition g-delta)
write_uint(buf, (10 << 4) | 0b1110) # (repetition) n-displacement g-delta: 10/southeast = (10, -10)
# TEXT 18
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 11) # repetition (9x / grid 2 / 8 arb. displacements)
write_uint(buf, 7) # (repetition) dimension (9)
write_uint(buf, 2) # (repetition) grid
write_uint(buf, ( 5 << 4) | 0b0000) # (repetition) g-delta: 10/east = (10, 0)
write_uint(buf, ( 5 << 4) | 0b0010) # (repetition) g-delta: 10/north = (0, 10)
write_uint(buf, ( 5 << 4) | 0b0100) # (repetition) g-delta: 10/west = (-10, 0)
if variant == 12:
write_uint(buf, (5 << 4) | 0b0110) # (repetition) g-delta: 10/south = (0, -10)
else:
write_uint(buf, (20 << 4) | 0b0110) # (repetition) g-delta: 40/south = (0, -40)
write_uint(buf, ( 5 << 4) | 0b1000) # (repetition) g-delta: 10/northeast = (10, 10)
write_uint(buf, ( 5 << 4) | 0b1010) # (repetition) g-delta: 10/northwest = (-10, 10)
write_uint(buf, ( 5 << 4) | 0b1100) # (repetition) g-delta: 10/southwest = (-10, -10)
if variant == 12:
write_uint(buf, (5 << 4) | 0b1110) # (repetition) g-delta: 20/southeast = (-10, -10)
else:
write_uint(buf, (10 << 4) | 0b1110) # (repetition) g-delta: 20/southeast = (-20, -20)
# TEXT 19
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0000_1100) # 0CNX_YRTL
write_sint(buf, -200) # y
write_uint(buf, 11) # repetition (3x / grid 3 / 2 arb. displacements)
write_uint(buf, 1) # (repetition) dimension
write_uint(buf, 3) # (repetition) grid
write_uint(buf, (4 << 2) | 0b11) # (repetition) g-delta: (-12, 12)
write_sint(buf, 4) # (repetition g-delta)
write_uint(buf, (3 << 4) | 0b1110) # (repetition) n-displacement g-delta: 9/southeast = (9, -9)
if variant == 12:
write_uint(buf, 6) # TEXTSTRING record (explicit id)
write_bstring(buf, b'A')
write_uint(buf, 1) # id
write_uint(buf, 6) # TEXTSTRING record (explicit id)
write_bstring(buf, b'B')
write_uint(buf, 2) # id
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_common(BytesIO(), 1)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
common_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
assert gg.string.string == 'TEXT_ABC', f'textstring #{ii}'
assert geometry[16].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 20]
assert geometry[16].repetition.y_displacements == [0, 10, 0, -40, 10, 10, -10, -20]
assert geometry[18].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 20]
assert geometry[18].repetition.y_displacements == [0, 10, 0, -40, 10, 10, -10, -20]
def test_file_2() -> None:
buf = write_file_common(BytesIO(), 2)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
common_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
if ii in (1, 2, 3):
assert gg.string == 2, f'textstring #{ii}'
else:
assert gg.string == 1, f'textstring #{ii}'
assert geometry[16].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 20]
assert geometry[16].repetition.y_displacements == [0, 10, 0, -40, 10, 10, -10, -20]
assert geometry[18].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 20]
assert geometry[18].repetition.y_displacements == [0, 10, 0, -40, 10, 10, -10, -20]
assert layout.textstrings[1].string == 'A'
assert layout.textstrings[2].string == 'B'
def test_file_5() -> None:
buf = write_file_common(BytesIO(), 5)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
common_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
if ii in (1, 2, 3):
assert gg.string == 0, f'textstring #{ii}'
else:
assert gg.string == 1, f'textstring #{ii}'
assert geometry[16].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 20]
assert geometry[16].repetition.y_displacements == [0, 10, 0, -40, 10, 10, -10, -20]
assert geometry[18].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 20]
assert geometry[18].repetition.y_displacements == [0, 10, 0, -40, 10, 10, -10, -20]
assert layout.textstrings[0].string == 'A'
assert layout.textstrings[1].string == 'B'
def test_file_12() -> None:
buf = write_file_common(BytesIO(), 12)
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
common_tests(layout)
geometry = layout.cells[0].geometry
for ii, gg in enumerate(geometry):
if ii in (1, 2, 3):
assert gg.string == 2, f'textstring #{ii}'
else:
assert gg.string == 1, f'textstring #{ii}'
assert geometry[16].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 10]
assert geometry[16].repetition.y_displacements == [0, 10, 0, -10, 10, 10, -10, -10]
assert geometry[18].repetition.x_displacements == [10, 0, -10, 0, 10, -10, -10, 10]
assert geometry[18].repetition.y_displacements == [0, 10, 0, -10, 10, 10, -10, -10]
assert layout.textstrings[1].string == 'A'
assert layout.textstrings[2].string == 'B'
def write_file_3(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with one textstring with explicit id, and one with an implicit id.
Should fail.
'''
buf.write(HEADER)
write_uint(buf, 6) # TEXTSTRING record (explicit id)
write_bstring(buf, b'A')
write_uint(buf, 1) # id
write_uint(buf, 5) # TEXTSTRING record (implicit id 0) (FAIL due to mix)
write_bstring(buf, b'B')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0111_1011) # 0CNX_YRTL
write_uint(buf, 1) # textstring id
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
buf.write(FOOTER)
return buf
def test_file_3() -> None:
buf = write_file_3(BytesIO())
buf.seek(0)
with pytest.raises(InvalidRecordError):
layout = OasisLayout.read(buf)
def write_file_4(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with a TEXT record that references a non-existent TEXTSTRING
TODO add an optional check for valid references
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 5) # TEXTSTRING record (implicit id 1)
write_bstring(buf, b'B')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0111_1011) # 0CNX_YRTL
write_uint(buf, 2) # textstring id # INVALID ID
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
buf.write(FOOTER)
return buf
def test_file_4() -> None:
buf = write_file_4(BytesIO())
buf.seek(0)
# with pytest.raises(InvalidRecordError):
layout = OasisLayout.read(buf)
# TODO: check for invalid textstring references
base_tests(layout)
def write_file_6(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with TEXT record that uses an un-filled modal for the repetition
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0111_1111) # 0CNX_YRTL
write_uint(buf, 0) # textstring id
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
write_uint(buf, 0) # reuse repetition (FAIL due to empty modal)
buf.write(FOOTER)
return buf
def test_file_6() -> None:
buf = write_file_6(BytesIO())
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)
def write_file_7(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with TEXT record that uses an un-filled modal for the layer
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0111_1010) # 0CNX_YRTL
write_uint(buf, 0) # textstring id
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
buf.write(FOOTER)
return buf
def test_file_7() -> None:
buf = write_file_7(BytesIO())
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)
def write_file_8(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with TEXT record that uses an un-filled modal for the datatype
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0111_1001) # 0CNX_YRTL
write_uint(buf, 0) # textstring id
write_uint(buf, 1) # layer
write_sint(buf, 100) # x
write_sint(buf, -200) # y
buf.write(FOOTER)
return buf
def test_file_8() -> None:
buf = write_file_8(BytesIO())
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)
def write_file_9(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with TEXT record that uses a default modal for the x coordinate
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0110_1011) # 0CNX_YRTL
write_uint(buf, 0) # textstring id
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, -200) # y
buf.write(FOOTER)
return buf
def test_file_9() -> None:
buf = write_file_9(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
text = layout.cells[0].geometry[0]
assert text.x == 0
assert text.layer == 1
assert text.datatype == 2
assert text.y == -200
def write_file_10(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with TEXT record that uses a default modal for the y coordinate
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0111_0011) # 0CNX_YRTL
write_uint(buf, 0) # textstring id
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
buf.write(FOOTER)
return buf
def test_file_10() -> None:
buf = write_file_10(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
text = layout.cells[0].geometry[0]
assert text.y == 0
assert text.layer == 1
assert text.datatype == 2
assert text.x == 100
def write_file_11(buf: BufferedIOBase) -> BufferedIOBase:
'''
File with TEXT record that uses an un-filled modal for the text string
'''
buf.write(HEADER)
write_uint(buf, 5) # TEXTSTRING record (implicit id 0)
write_bstring(buf, b'A')
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
write_uint(buf, 19) # TEXT record
write_byte(buf, 0b0001_1011) # 0CNX_YRTL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_sint(buf, 100) # x
write_sint(buf, -200) # y
buf.write(FOOTER)
return buf
def test_file_11() -> None:
buf = write_file_11(BytesIO())
buf.seek(0)
with pytest.raises(InvalidDataError):
layout = OasisLayout.read(buf)

@ -0,0 +1,234 @@
# type: ignore
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
import numpy
from numpy.testing import assert_equal
from .utils import HEADER, FOOTER
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring, write_byte, PathExtensionScheme
from ..basic import InvalidRecordError, 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.propnames
assert not layout.xnames
assert not layout.textstrings
assert not layout.cellnames
assert not layout.layers
assert len(layout.cells) == 1
assert layout.cells[0].name.string == 'ABC'
assert not layout.cells[0].properties
def write_file_1(buf: BufferedIOBase) -> BufferedIOBase:
'''
'''
buf.write(HEADER)
write_uint(buf, 14) # CELL record (explicit)
write_bstring(buf, b'ABC') # Cell name
# Trapezoid 0
write_uint(buf, 23) # TRAPEZOID record
write_byte(buf, 0b0111_1011) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 50) # height
write_sint(buf, -20) # delta-a
write_sint(buf, 40) # delta-b
write_sint(buf, 0) # geometry-x (absolute)
write_sint(buf, 100) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# Trapezoid 1
write_uint(buf, 23) # TRAPEZOID record
write_byte(buf, 0b1010_1011) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 50) # height
write_sint(buf, 20) # delta-a
write_sint(buf, 40) # delta-b
write_sint(buf, 300) # geometry-y (absolute)
# Trapezoid 2
write_uint(buf, 23) # TRAPEZOID record
write_byte(buf, 0b1100_1001) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 150) # width
write_sint(buf, 20) # delta-a
write_sint(buf, -20) # delta-b
write_sint(buf, 300) # geometry-y (relative)
# Trapezoid 3
write_uint(buf, 23) # TRAPEZOID record
write_byte(buf, 0b0100_1101) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 150) # width
write_sint(buf, 20) # delta-a
write_sint(buf, -20) # delta-b
write_sint(buf, 300) # geometry-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
write_uint(buf, 15) # XYABSOLUTE record
# Trapezoid 4
write_uint(buf, 24) # TRAPEZOID record
write_byte(buf, 0b0111_1011) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 50) # height
write_sint(buf, -20) # delta-a
write_sint(buf, 1000) # geometry-x (absolute)
write_sint(buf, 100) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# Trapezoid 5
write_uint(buf, 24) # TRAPEZOID record
write_byte(buf, 0b1010_1011) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 50) # height
write_sint(buf, 20) # delta-a
write_sint(buf, 300) # geometry-y (relative)
# Trapezoid 6
write_uint(buf, 24) # TRAPEZOID record
write_byte(buf, 0b1100_1001) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 150) # width
write_sint(buf, 20) # delta-a
write_sint(buf, 300) # geometry-y (relative)
# Trapezoid 7
write_uint(buf, 24) # TRAPEZOID record
write_byte(buf, 0b0100_1101) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 150) # width
write_sint(buf, 20) # delta-a
write_sint(buf, 300) # geometry-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
write_uint(buf, 15) # XYABSOLUTE record
# Trapezoid 8
write_uint(buf, 25) # TRAPEZOID record
write_byte(buf, 0b0111_1011) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 100) # width
write_uint(buf, 50) # height
write_sint(buf, 40) # delta-b
write_sint(buf, 2000) # geometry-x (absolute)
write_sint(buf, 100) # geometry-y (absolute)
write_uint(buf, 16) # XYRELATIVE record
# Trapezoid 9
write_uint(buf, 25) # TRAPEZOID record
write_byte(buf, 0b1010_1011) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 2) # datatype
write_uint(buf, 50) # height
write_sint(buf, 40) # delta-b
write_sint(buf, 300) # geometry-y (relative)
# Trapezoid 10
write_uint(buf, 25) # TRAPEZOID record
write_byte(buf, 0b1100_1001) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 150) # width
write_sint(buf, -20) # delta-b
write_sint(buf, 300) # geometry-y (relative)
# Trapezoid 11
write_uint(buf, 25) # TRAPEZOID record
write_byte(buf, 0b0100_1101) # OWHX_YRDL
write_uint(buf, 1) # layer
write_uint(buf, 150) # width
write_sint(buf, -20) # delta-b
write_sint(buf, 300) # geometry-y (relative)
write_uint(buf, 1) # repetition (3x4 matrix)
write_uint(buf, 1) # (repetition) x-dimension
write_uint(buf, 2) # (repetition) y-dimension
write_uint(buf, 200) # (repetition) x-spacing
write_uint(buf, 300) # (repetition) y-spacing
buf.write(FOOTER)
return buf
def test_file_1() -> None:
buf = write_file_1(BytesIO())
buf.seek(0)
layout = OasisLayout.read(buf)
base_tests(layout)
geometry = layout.cells[0].geometry
assert len(geometry) == 12
for ii, gg in enumerate(geometry):
msg = f'Failed on trapezoid {ii}'
assert gg.x == 1000 * (ii // 4), msg
assert gg.y == 100 + 300 * (ii % 4), msg
assert gg.layer == 1, msg
assert gg.datatype == 2, msg
if ii % 4 == 3:
assert gg.repetition.a_count == 3, msg
assert gg.repetition.b_count == 4, msg
assert gg.repetition.a_vector == [200, 0], msg
assert gg.repetition.b_vector == [0, 300], msg
else:
assert gg.repetition is None, msg
assert not gg.properties, msg
assert gg.height == 50, msg
if ii % 4 < 2:
assert gg.width == 100, msg
else:
assert gg.width == 150, msg
if ii in (0, 4):
assert gg.delta_a == -20, msg
elif 8 <= ii:
assert gg.delta_a == 0, msg
else:
assert gg.delta_a == 20, msg
if ii in (0, 1, 8, 9):
assert gg.delta_b == 40, msg
elif 4 <= ii < 8:
assert gg.delta_b == 0, msg
else:
assert gg.delta_b == -20, msg
assert gg.is_vertical == ((ii % 4) in (1, 2)), msg
assert not gg.properties

@ -0,0 +1,71 @@
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO
import pytest # type: ignore
from ..basic import read_uint, read_sint, write_uint, write_sint
uints = (
( 0, '00'),
( 127, '7f'),
( 128, '80 01'),
(16_383, 'ff 7f'),
(16_384, '80 80 01'),
)
uints_readonly = (
( 0, '80 80 00'),
)
sints = (
( 0, '00'),
( 1, '02'),
( -1, '03'),
( 63, '7e'),
( -64, '81 01'),
( 8191, 'fe 7f'),
( -8192, '81 80 01'),
)
sints_readonly = (
)
def test_read_uint() -> None:
buffer = BytesIO(bytes.fromhex(
''.join([hh for _ii, hh in chain(uints, uints_readonly)])))
for ii, _hh in chain(uints, uints_readonly):
assert read_uint(buffer) == ii
def test_write_uint() -> None:
buffer = BytesIO()
for ii, _hh in uints:
write_uint(buffer, ii)
correct_bytes = bytes.fromhex(
''.join([hh for _ii, hh in uints]))
assert buffer.getbuffer() == correct_bytes
def test_read_sint() -> None:
buffer = BytesIO(bytes.fromhex(
''.join([hh for _ii, hh in chain(sints, sints_readonly)])))
for ii, _hh in chain(sints, sints_readonly):
assert read_sint(buffer) == ii
def test_write_sint() -> None:
buffer = BytesIO()
for ii, _hh in sints:
write_sint(buffer, ii)
correct_bytes = bytes.fromhex(
''.join([hh for _ii, hh in sints]))
assert buffer.getbuffer() == correct_bytes

@ -0,0 +1,41 @@
from typing import List, Tuple, Iterable
from itertools import chain
from io import BytesIO, BufferedIOBase
import struct
import pytest # type: ignore
from ..basic import write_uint, write_sint, read_uint, read_sint, write_bstring
from ..main import OasisLayout
MAGIC_BYTES = b'%SEMI-OASIS\r\n'
def _gen_header() -> bytes:
buf = BytesIO()
buf.write(MAGIC_BYTES)
write_uint(buf, 1) # START record
write_bstring(buf, b'1.0') # version
write_uint(buf, 0) # dbu real type: uint
write_uint(buf, 1000) # dbu value: 1000 per micron
write_uint(buf, 0) # offset table is present here
for _ in range(6):
write_uint(buf, 0) # offset table (0: not strict)
write_uint(buf, 0) # offset table (0: no entry present)
return buf.getvalue()
def _gen_footer() -> bytes:
buf = BytesIO()
write_uint(buf, 2) # END record
write_bstring(buf, b'\0' * 252) # padding (1 + 1 + (2 + 252)) = 256
write_uint(buf, 0) # no validation
return buf.getvalue()
HEADER = _gen_header()
FOOTER = _gen_footer()
Loading…
Cancel
Save