Merge remote-tracking branch 'origin/sub_laptop_2' into sub_laptop_7

This commit is contained in:
2026-11-02 20:46:20 +09:00
19 changed files with 432 additions and 11 deletions
@@ -96,6 +96,7 @@ CALC = {"줄": [{"로직": "GF1", "분모": "㎡", "배": 10, "수량": 2.09,
def test_M02_문서_calc_를_격자_줄로():
files = [GRID, "M02_MasterTemplete/M02_MasterTemplete_Labor_Calc.ts",
"M02_MasterTemplete/M02_MasterTemplete_Labor_Spec.ts",
"M02_MasterTemplete/logic/M02_Born_Tag.ts",
"M02_MasterTemplete/M02_MasterTemplete_Labor_Grid.ts"] # fmt: skip
logics = [
["GF1", {"이름": "돌쌓기 찰쌓기", "입력": [], "결과단위": "㎡"}],
@@ -146,6 +147,7 @@ def test_세_곳_같은_부품():
def test_번호는_글에_안_냄_사람_글은_그대로():
files = [GRID, "M02_MasterTemplete/M02_MasterTemplete_Labor_Calc.ts",
"M02_MasterTemplete/M02_MasterTemplete_Labor_Spec.ts",
"M02_MasterTemplete/logic/M02_Born_Tag.ts",
"M02_MasterTemplete/M02_MasterTemplete_Labor_Grid.ts"] # fmt: skip
ref = {"로직": "", "별칭": None, "입력값": {}, "수량": {"손": 1},
"참조": {"층": "personal", "주인": "1/3", "키": "SC-000002"}} # fmt: skip
+1
View File
@@ -176,6 +176,7 @@ def test_격자_규격_열_수량_칸_열마다():
files = [g.GRID, "M02_MasterTemplete/M02_MasterTemplete_Labor_Calc.ts",
"M02_MasterTemplete/M02_MasterTemplete_Labor_Spec.ts",
"M02_MasterTemplete/logic/M02_Born_Tag.ts",
"M02_MasterTemplete/M02_MasterTemplete_Labor_Grid.ts"] # fmt: skip
doc = {**g.DOC, "규격": {"이름": "H", "열": ["1.5", "2.0"], "기본": "2.0",
"수량": {"GF1": {"1.5": 1.5, "2.0": 2.09}, "MT1": {"1.5": 4}}}} # fmt: skip
@@ -9,6 +9,7 @@
"""
import json
import re
import shutil
import subprocess
from decimal import Decimal
@@ -32,7 +33,9 @@ def _text(p: Path) -> str:
def _node(body: str) -> object:
src = _text(MODEL) + "\n" + body
born = _text(M02 / "logic" / "M02_Born_Tag.ts") # 740-2 — 모델이 쓰는 꼬리표 글(import 줄은 뺌)
model = re.sub(r"^import .*$", "", _text(MODEL), flags=re.M)
src = born + "\n" + model + "\n" + body
out = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings",
"--input-type=module-typescript", "-e", src],
+7 -1
View File
@@ -206,7 +206,13 @@ def _model(ans, doc, script):
f"\nconst ans = {json.dumps(ans, ensure_ascii=False)};"
f"\nconst doc = {json.dumps(doc, ensure_ascii=False)};\n{script}"
)
return _node(["M02_MasterTemplete/logic/M02_Sangeun_Cover_Model.ts"], body)
return _node(
[
"M02_MasterTemplete/logic/M02_Born_Tag.ts",
"M02_MasterTemplete/logic/M02_Sangeun_Cover_Model.ts",
],
body,
)
def test_727_2_화면_꼴_세부_줄_고침(world): # noqa: F811
@@ -0,0 +1,93 @@
"""740-2 · 738-2 상세 머리 [초기화] [삭제] · 출처 꼬리표 지킴 시험(서버 · 화면 없음)."""
import json
import re
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
M02 = ROOT / "M02_MasterTemplete"
MAIN = (M02 / "M02_MasterTemplete_UI_Main.ts").read_text(encoding="utf-8")
ACTIONS = (M02 / "M02_MasterTemplete_Main_Actions.ts").read_text(encoding="utf-8")
HO = (ROOT / "M01_MasterData" / "M01_MasterData_UI_LogicLab_Ho.ts").read_text(encoding="utf-8")
COVER = (M02 / "logic" / "M02_Sangeun_Cover_Model.ts").read_text(encoding="utf-8")
def _born(expr: str):
"""순수 TS(`logic/M02_Born_Tag.ts`)를 Node 로 돌려 JSON 답을 받음."""
uri = (M02 / "logic" / "M02_Born_Tag.ts").as_uri()
code = (
f"import {{ bornText, bornOfCid, bornNote }} from '{uri}';"
f"console.log(JSON.stringify({expr}));"
)
out = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", "--experimental-strip-types", "--no-warnings", "--input-type=module", "-e", code],
capture_output=True,
text=True,
check=True,
cwd=ROOT,
)
return json.loads(out.stdout)
BORN = {
"층": "personal",
"주인": "u1",
"키": "SK-000012",
"이름": "강관비계",
"때": "2026-11-02T06:30:12Z",
}
def test_꼬리표_글_첫줄_짧게_둘째줄_풍선():
shown, tip = _born(f"bornText({json.dumps(BORN, ensure_ascii=False)})").split("\n")
assert shown == "본뜬 SK-000012"
assert "SK-000012 강관비계" in tip and "개인" in tip
assert re.search(r"\d{4}-\d\d-\d\d \d\d:\d\d", tip) # 이 컴퓨터 시각 · 시간대 따라 값이 다름
def test_꼬리표_없으면_빈칸_기초번호_뒤에_붙음():
assert _born("bornText(null)") == ""
assert _born("bornText(undefined, 'A1')") == "A1"
got = _born(f"bornText({json.dumps(BORN, ensure_ascii=False)}, 'A1')")
assert got.split("\n")[0] == "A1 · 본뜬 SK-000012"
def test_줄_열쇠에서_그_더한줄_출처를_찾음():
adds = json.dumps([{}, {"본뜬": BORN}], ensure_ascii=False)
assert _born(f"bornOfCid('add:#1', {adds})").startswith("본뜬 SK-000012")
assert _born(f"bornOfCid('add:#1/add:#0', {adds})").startswith("본뜬 SK-000012") # 펼침 세부
assert _born(f"bornOfCid('add:#0', {adds})") == ""
assert _born(f"bornOfCid('hopyo:X#3', {adds})") == ""
def test_머리_단추_차례_초기화_삭제_저장():
kids = MAIN[MAIN.index('className: "m02-main__head"') :]
kids = kids[: kids.index("]")]
order = [kids.index(w) for w in ("reload,", "actions.reset,", "actions.del,", "save,")]
assert order == sorted(order)
assert "actions.update(" in MAIN # 쓰기 권한 없는 층 = 안 보임
def test_삭제는_735_경고_창을_그대로_씀():
assert "askLibraryDelete(" in ACTIONS and '"delete"' in ACTIONS
assert "sure ? { 확인: true }" in ACTIONS.replace(
"ans.sure", "sure"
) # 확인 몸 = 쓰는 곳 줄까지
assert "sangeunList(" in ACTIONS and "precomboList(" in ACTIONS # 지운 뒤 목록으로
def test_초기화는_미리보기_뒤_물음_뒤_씀():
assert ACTIONS.index("미리보기: true") < ACTIONS.index("미리보기: false")
assert "ctx.confirmLeave()" in ACTIONS # 저장 안 한 고침 먼저 물음
assert "옵션 · 기본정보는 그대로" in ACTIONS
def test_공용_꼬리표_칸은_첫줄만_보이고_풍선에_나머지():
assert 'text.split("\\n")' in HO
assert "bornOfCid(" in COVER
def test_격자_비고_칸은_첫줄만():
assert _born(f"bornNote({json.dumps(BORN, ensure_ascii=False)})") == "본뜬 SK-000012"
assert _born("bornNote(null)") == ""