- 세로: 머리(제목 · 크게 보기 · 접기) · 실행 취소 · 다이어그램 · 상세 내용 · 원가 · 검증(접기) · 저장 단추 없음 - 왼쪽 가장자리 끌기 · 화살표 키 → onResize(px) · 마지막 너비 localStorage · 접기 = 얇은 띠 「흐름도 ▸」 - 크게 보기 = 같은 판을 화면 전체로 옮겨 끼움 · 닫으면 패널로(고친 것 그대로) · Esc · Ctrl+Z - 좁은 패널은 저절로 맞춤 바닥 0.5(한눈에) · 크게 보기는 0.9 — 다이어그램 opts.fitMin - 시험 test_m02_df_panel.py 2 통과 · typecheck · DataFlow 전부 검사 초록 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ly2oHAaTDYRjcniAmHR81z
84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
"""오른쪽 흐름도 패널(`M02_DF_Panel.ts`) 순수 부분 — 끌어서 정한 너비 · 저장해 둔 너비.
|
|
|
|
화면 TS 를 그 자리에서 트랜스파일해 node 로 돌림(부품 · 판은 빈 흉내 · 순수 함수만).
|
|
"""
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SOURCE = ROOT / "M02_MasterTemplete" / "DataFlow" / "M02_DF_Panel.ts"
|
|
|
|
RUNNER = r"""
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const [root, file] = process.argv.slice(1);
|
|
const ts = require(path.join(root, "config", "node_modules", "typescript"));
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const stub = new Proxy({}, { get: () => () => undefined });
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", "require", js)(box.exports, box, () => stub);
|
|
const m = box.exports;
|
|
const jobs = JSON.parse(fs.readFileSync(0, "utf8"));
|
|
const out = jobs.map((j) =>
|
|
j.op === "drag" ? m.dragWidth(j.start, j.startX, j.x, j.viewport)
|
|
: j.op === "stored" ? m.storedWidth(j.raw)
|
|
: j.op === "consts" ? [m.PANEL_MIN, m.STRIP_WIDTH]
|
|
: null,
|
|
);
|
|
process.stdout.write(JSON.stringify(out));
|
|
"""
|
|
|
|
|
|
def run(jobs: list[dict]) -> list:
|
|
if shutil.which("node") is None:
|
|
pytest.skip("node 가 없음")
|
|
done = subprocess.run(
|
|
["node", "-e", RUNNER, str(ROOT), str(SOURCE)],
|
|
input=json.dumps(jobs, ensure_ascii=False),
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
check=True,
|
|
)
|
|
return json.loads(done.stdout)
|
|
|
|
|
|
def test_왼쪽_가장자리_끌기_너비():
|
|
[consts, wider, narrower, floor, ceil] = run(
|
|
[
|
|
{"op": "consts"},
|
|
# 왼쪽으로 100 끌면 넓어짐
|
|
{"op": "drag", "start": 480, "startX": 1000, "x": 900, "viewport": 1600},
|
|
# 오른쪽으로 끌면 좁아짐
|
|
{"op": "drag", "start": 480, "startX": 1000, "x": 1060, "viewport": 1600},
|
|
# 너무 좁게 — 가장 작은 너비에서 멈춤
|
|
{"op": "drag", "start": 480, "startX": 1000, "x": 1400, "viewport": 1600},
|
|
# 너무 넓게 — 화면의 85% 에서 멈춤
|
|
{"op": "drag", "start": 480, "startX": 1000, "x": -2000, "viewport": 1600},
|
|
]
|
|
)
|
|
min_width, strip = consts
|
|
assert (min_width, strip) == (320, 40)
|
|
assert wider == 580 and narrower == 420
|
|
assert floor == min_width and ceil == 1360
|
|
|
|
|
|
def test_저장해_둔_너비():
|
|
got = run(
|
|
[
|
|
{"op": "stored", "raw": "640"},
|
|
{"op": "stored", "raw": "640.6"},
|
|
{"op": "stored", "raw": None},
|
|
{"op": "stored", "raw": "abc"},
|
|
{"op": "stored", "raw": "100"},
|
|
]
|
|
)
|
|
assert got == [640, 641, None, None, None]
|