Merge remote-tracking branch 'origin/sub_laptop_6' into main_laptop_1
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
"""534-2 — 내장 엑셀 내보내기: 인쇄 HTML(Node 번들 `printHtml`) · xlsx 되읽기 · SVG → PNG · PDF 쪽 수.
|
||||
|
||||
책 하나(시트 둘 · 병합 · 열 폭 · 숨긴 열 · 머리 행 · 쪽 나눔 둘 · 그림 · 식)로 셋을 함께 봄.
|
||||
"""
|
||||
|
||||
import io
|
||||
import re
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
from openpyxl import load_workbook
|
||||
|
||||
from common_util import common_util_spreadsheet as spreadsheet
|
||||
from common_util.common_util_print_pdf import PrintError
|
||||
from common_util.common_util_svg_png import svgs_to_pngs
|
||||
from common_util.common_util_workbook_xlsx import workbook_to_xlsx
|
||||
|
||||
pytestmark = pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
||||
|
||||
SVG = (
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" width="120" height="60">'
|
||||
'<rect width="120" height="60" fill="#0a0"/></svg>'
|
||||
)
|
||||
BREAKS = [6, 12]
|
||||
|
||||
|
||||
def _book() -> dict:
|
||||
cells = {"A1": {"값": "제목", "서식": 1}, "A2": {"값": "측점", "서식": 2}, "B2": {"값": "Fs"}}
|
||||
for r in range(3, 31):
|
||||
cells[f"A{r}"] = {"값": f"No.{r}"}
|
||||
cells[f"B{r}"] = {"값": r / 10, "서식": 3}
|
||||
cells["C3"] = {"식": "SUM(B3:B30)", "서식": 3}
|
||||
cells["D3"] = {"값": "숨김"}
|
||||
return {
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "stab_report",
|
||||
"서식": [
|
||||
{},
|
||||
{"크기": 14, "굵게": True},
|
||||
{"채움": "#EEEEEE", "테두리": {"아래": {"선": "medium"}}},
|
||||
{"형식": "0.00"},
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "측점표",
|
||||
"칸": cells,
|
||||
"병합": ["A1:C1", "E5:E8"],
|
||||
"열": {"A": {"폭": 12}, "B": {"폭": 6}, "D": {"숨김": True}},
|
||||
"행": {"1": {"높이": 24}},
|
||||
"틀고정": {"행": 2},
|
||||
"인쇄": {
|
||||
"방향": "landscape",
|
||||
"맞춤": {"폭": 1, "높이": 0},
|
||||
"머리행": [2, 2],
|
||||
"쪽나눔": BREAKS,
|
||||
},
|
||||
"그림": [{"열쇠": "fig/a.png", "닻": "F3:H10", "이름": "단면"}],
|
||||
},
|
||||
{"id": "s2", "이름": "숨김", "칸": {"A1": {"값": 1}}, "숨김": True},
|
||||
],
|
||||
"활성": "s1",
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def png() -> bytes:
|
||||
try:
|
||||
return svgs_to_pngs([SVG])[0]
|
||||
except PrintError as error:
|
||||
pytest.skip(f"브라우저 없음 — {error}")
|
||||
|
||||
|
||||
def test_svg_png_크기(png):
|
||||
from PIL import Image
|
||||
|
||||
assert Image.open(io.BytesIO(png)).size == (240, 120) # scale 2
|
||||
|
||||
|
||||
def test_인쇄_html(png):
|
||||
html = spreadsheet.print_htmls([{"book": _book(), "figures": {"fig/a.png": png}}])[0]
|
||||
sheets = re.findall(r'<section class="sheet" data-sheet="(\w+)"', html)
|
||||
assert sheets == ["s1"] # 숨긴 시트 안 찍음
|
||||
chunks = html.split('<div class="chunk">')[1:]
|
||||
assert len(chunks) == len(BREAKS) + 1
|
||||
for chunk in chunks: # 덩이마다 머리 행 한 줄
|
||||
thead = re.search(r"<thead>(.*?)</thead>", chunk).group(1)
|
||||
assert thead.count("<tr") == 1 and "측점" in thead
|
||||
# 열 폭 = 화면 px 환산(글자 × 7 + 5) · 숨긴 D 빠짐(A B C E F G H = 7)
|
||||
widths = re.findall(r'<col style="width:(\d+)px">', chunks[0])
|
||||
assert widths[:3] == ["89", "47", "64"] and len(widths) == 7 * 2 # 앞 표(제목) + 본 표
|
||||
# 병합 A1:C1 · E5:E8 = 쪽 나눔(6 아래)에서 잘림 — 첫 덩이 5~6 · 둘째 덩이 7~8
|
||||
assert 'colspan="3"' in chunks[0] and 'rowspan="2"' in chunks[0] and 'rowspan="2"' in chunks[1]
|
||||
assert "rowspan" not in chunks[2]
|
||||
assert html.count("<img ") == 1 and "data:image/png;base64," in html
|
||||
assert "@page p0{size:A4 landscape" in html
|
||||
assert ">46.20<" in html # 식 값 = 화면 엔진 · 형식 0.00(SUM 0.3..3.0)
|
||||
|
||||
|
||||
def test_xlsx_되읽기(png):
|
||||
data = workbook_to_xlsx(_book(), {"fig/a.png": png})
|
||||
wb = load_workbook(io.BytesIO(data))
|
||||
assert wb.sheetnames == ["측점표", "숨김"]
|
||||
ws = wb["측점표"]
|
||||
assert sorted(str(m) for m in ws.merged_cells.ranges) == ["A1:C1", "E5:E8"]
|
||||
assert [b.id for b in ws.row_breaks.brk] == BREAKS
|
||||
assert len(ws._images) == 1
|
||||
assert ws.print_title_rows == "$2:$2"
|
||||
assert ws["C3"].value == "=SUM(B3:B30)"
|
||||
assert ws["B3"].number_format == "0.00" and ws["A1"].font.b
|
||||
assert ws.column_dimensions["A"].width == 12 and ws.column_dimensions["D"].hidden
|
||||
assert ws.row_dimensions[1].height == 24 and ws.freeze_panes == "A3"
|
||||
assert ws.page_setup.orientation == "landscape" and ws.page_setup.fitToWidth == 1
|
||||
assert wb["숨김"].sheet_state == "hidden"
|
||||
|
||||
|
||||
def test_pdf_쪽수(png):
|
||||
book = _book()
|
||||
try:
|
||||
pdf = spreadsheet.workbook_pdf(book, {"fig/a.png": png})
|
||||
except PrintError as error:
|
||||
pytest.skip(f"브라우저 없음 — {error}")
|
||||
from pypdf import PdfReader
|
||||
|
||||
pages = PdfReader(io.BytesIO(pdf)).pages
|
||||
assert len(pages) == len(BREAKS) + 1
|
||||
assert all(float(p.mediabox.width) > float(p.mediabox.height) for p in pages) # 가로
|
||||
assert all("측점" in p.extract_text() for p in pages) # 머리 행 쪽마다
|
||||
Reference in New Issue
Block a user