snapshot 2021-07-30 01:22:37.525646
parent
a64f2726d0
commit
dcab922699
@ -0,0 +1,3 @@
|
||||
"""
|
||||
Tests (run with `python3 -m pytest -rxPXs | tee results.txt`)
|
||||
"""
|
@ -0,0 +1,91 @@
|
||||
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,176 @@
|
||||
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]])
|
||||
|
||||
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]])
|
||||
|
||||
assert_equal(geometry[4].point_list,
|
||||
[[40, -760], [490, -50], [110, 800]])
|
||||
|
||||
assert_equal(geometry[5].point_list,
|
||||
[[140, -380],
|
||||
[340, -10],
|
||||
[30, -100],
|
||||
[-320, 20],
|
||||
[130, -460],
|
||||
[-480, -20],
|
||||
[-210, 910]])
|
||||
|
||||
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]])
|
||||
|
||||
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]])
|
||||
|
||||
assert_equal(geometry[8].point_list,
|
||||
[[330, 0], [-10, 480], [620, -20], [-10, 330], [-930, 60]])
|
||||
|
||||
assert_equal(geometry[9].point_list,
|
||||
[[-140, -410],
|
||||
[10, -140],
|
||||
[270, 0],
|
||||
[130, 1030],
|
||||
[-500, 50],
|
||||
[10, -330],
|
||||
[210, -10]])
|
@ -0,0 +1,273 @@
|
||||
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,115 @@
|
||||
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,245 @@
|
||||
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,183 @@
|
||||
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,336 @@
|
||||
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,258 @@
|
||||
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,203 @@
|
||||
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,893 @@
|
||||
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,447 @@
|
||||
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) == 4, msg
|
||||
assert_equal(geometry[0].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50]], err_msg=msg)
|
||||
assert len(geometry[4].point_list) == 4
|
||||
assert_equal(geometry[4].point_list, [[0, 150], [50, 0], [0, -50], [50, 0]])
|
||||
|
||||
assert len(geometry[5].point_list) == 7
|
||||
assert_equal(geometry[5].point_list, [[150, 0], [0, 50], [-50, 0], [0, 50], [-50, 0], [0, -50], [-50, 0]])
|
||||
assert len(geometry[6].point_list) == 8
|
||||
assert_equal(geometry[6].point_list, [[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [0, -50], [50, -50]])
|
||||
assert len(geometry[7].point_list) == 8
|
||||
assert_equal(geometry[7].point_list, [[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25]])
|
||||
assert len(geometry[8].point_list) == 8
|
||||
assert_equal(geometry[8].point_list,
|
||||
numpy.cumsum([[25, 0], [50, 50], [0, 50], [-50, 50], [-50, 0], [-50, -50], [10, -75], [25, -25]], axis=0))
|
||||
|
||||
for ii in range(9, 12):
|
||||
msg = f'Fail on poly {ii}'
|
||||
assert len(geometry[ii].point_list) == 4, msg
|
||||
assert_equal(geometry[ii].point_list, [[0, 150], [50, 0], [0, -50], [50, 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
|
||||
assert poly.point_list == (
|
||||
[[-1000, 0]]
|
||||
+ [[(-1) ** nn * 10, 20] for nn in range(8000)]
|
||||
+ [[1000, 0]])
|
||||
|
||||
|
||||
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,277 @@
|
||||
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,736 @@
|
||||
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,232 @@
|
||||
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()
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
from io import BytesIO
|
||||
import fatamorgana
|
||||
failed = []
|
||||
for i in range(1, 16):
|
||||
for j in range(1, 20):
|
||||
print(i, j)
|
||||
try:
|
||||
with open(f'/home/jan/software/layout/klayout-source/testdata/oasis/t{i}.{j}.oas', 'rb') as f:
|
||||
a = f.read()
|
||||
b = fatamorgana.OasisLayout.read(BytesIO(a[:-253]))
|
||||
except FileNotFoundError:
|
||||
print('failed to open', i,'.',j)
|
||||
break
|
||||
except Exception as e:
|
||||
failed.append((i, j, e))
|
||||
|
||||
if (i, j) == (9, 2):
|
||||
continue
|
||||
|
||||
with open(f'/tmp/t{i}.{j}.oas', 'wb') as f:
|
||||
b.write(f)
|
||||
[print(f) for f in failed]
|
Loading…
Reference in New Issue