# -*- coding: utf-8 -*- """PLAN 800-2 · 800-3 — 수식 탭 변수 정의 영역 · 바로 고침 · 새 기호 연결 (서버 몫 · 임시 쓰기 없음).""" import json import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path[:0] = [str(ROOT), str(ROOT / "resources/master_data/scripts")] from M01_MasterData import M01_MasterData_Equation as eq # noqa: E402 from M01_MasterData import M01_MasterData_Store as store # noqa: E402 KEY = "GC000211" OFF = {"폼타이": "아님", "측압": "3t/㎡"} ON = {"폼타이": "사용", "측압": "4t/㎡"} def _defs(inputs): return eq.read(KEY, inputs)["수식"]["정의"] def _text(defs): return json.dumps(defs, ensure_ascii=False) def test_defs_merge_and_clean(): defs = _defs(OFF) signs = [(d["기호"], d["위"], d["아래"]) for d in defs] assert len(signs) == len(set(signs)), "같은 변수는 한 번만" assert not re.search(r"[A-Z]{2}\d{6}", _text(defs)), "DB 열쇠 글 0" assert all( set(d) <= {"열쇠", "기호", "위", "아래", "이름", "갈래", "연결", "고침", "안씀"} for d in defs ) by = { (d["이름"], d["갈래"]): d for d in defs } # 800-1 기호가 생겨 중간 · 표 찾기는 다른 기호 = 다른 정의 sign = lambda d: (d["기호"], d["위"], d["아래"]) assert sign(by[("보통인부", "중간")]) != sign(by[("보통인부", "찾기")]) assert by[("사용횟수", "입력")]["연결"] == ["입력 — 옵션에서 고름"] def test_unpicked_branches_hidden(): off, on = _text(_defs(OFF)), _text(_defs(ON)) for col in ("4t/㎡", "5t/㎡", "6t/㎡", "폼타이 소요량"): assert col not in off assert "칸 4t/㎡" in on and "칸 3t/㎡" not in on and "칸 5t/㎡" not in on assert "측압" in on and "측압" not in off # 폼타이 아님이면 측압 갈래도 안 탐 def test_live_edit_preview_changes_total(): spot = {"할일": "식", "자리": "호표:0", "식": "형틀목공 × 2"} got = eq.preview(KEY, [spot], OFF) assert got["되나"] and got["후"]["계"] > got["전"]["계"] def test_unknown_symbol_asks_link_then_links(): spot = {"할일": "식", "자리": "호표:0", "식": "형틀목공 × 2 + Z"} got = eq.preview(KEY, [spot], OFF) assert not got["되나"] and "모르는 기호 「Z」" in got["까닭"][0] for link in ( {"갈래": "상수", "값": "0"}, {"갈래": "입력", "기본값": "0"}, {"갈래": "표", "표": "QC000431", "칸": "형틀목공", "조건": {"유형": "유형"}}, {"갈래": "요소", "요소": "LB000007"}, ): add = {"할일": "연결", "열쇠": "Z", "이름": "새값", **link} got = eq.preview(KEY, [add, spot], OFF) assert got["되나"], (link, got["까닭"]) assert any(d["기호"] == "Z" for d in got["수식"]["정의"]) def test_link_bad_input_blocked(): bad = [ {"갈래": "표", "표": "QC000431", "칸": "없는칸", "조건": {"유형": "유형"}}, {"갈래": "표", "표": "QC000431", "칸": "형틀목공", "조건": {}}, {"갈래": "요소", "요소": "GC000211"}, {"갈래": "상수", "값": "abc"}, ] for link in bad: got = eq.preview(KEY, [{"할일": "연결", "열쇠": "Z", **link}], OFF) assert not got["되나"], link def test_drop_guard_and_unused_input(): got = eq.preview(KEY, [{"할일": "지움", "열쇠": "사용횟수"}], OFF) assert not got["되나"] and "쓰는 곳" in got["까닭"][0] add = {"할일": "연결", "열쇠": "Y", "갈래": "입력"} got = eq.preview(KEY, [add], OFF) unused = [d for d in got["수식"]["정의"] if d["기호"] == "Y"] assert unused and unused[0].get("안씀") assert eq.preview(KEY, [add, {"할일": "지움", "열쇠": "Y"}], OFF)["되나"] def test_candidates(): whole = store.loaded()[1] got = eq.links({"갈래": "표", "검색": "합판거푸집 폼타이", "분류": ""}) assert got["후보"] and "조건" in got["후보"][0] assert eq.links({"갈래": "요소", "검색": "형틀목공", "분류": "인력"})["후보"] assert eq.links({"갈래": "로직", "검색": "합판거푸집", "분류": ""})["후보"] assert whole is not None def test_groups_add_up_to_total(): """800-4 — 묶음(블록 · 자원 · 덧줄) 소계 합 + 끝수 = 합계(비목마다) · 한 묶음 소계 = 노 + 재 + 경.""" for key in ("GF000089", "GC000211"): eqn = eq.read(key, {})["수식"] sub, total = eqn["소계"], eqn["합계"] for k in ("노무비", "재료비", "경비"): got = sum(float(r[k]) for r in sub["줄"]) + float(sub["끝수"][k]) assert abs(got - float(total[k])) < 1e-6, (key, k) assert all( abs(float(r["계"]) - sum(float(r[k]) for k in ("노무비", "재료비", "경비"))) < 1e-6 for r in sub["줄"] ) def test_screen_source_groups_and_inline_edit(): ui = ROOT / "ui_template" sum_ts = (ui / "ui_template_equation_sum.ts").read_text(encoding="utf-8") line_ts = (ui / "ui_template_equation_line.ts").read_text(encoding="utf-8") assert "ORDER" in sum_ts and "ui-eq__grp" in sum_ts # 가 · 나 · 다 묶음 assert "o.after?.(line)" in line_ts # 블록 식 줄 바로 아래 assert "block-key" not in line_ts # 줄 곁 DB 열쇠 글 없음 assert "ui-eq__solve" not in line_ts and "ui-eq__step" not in line_ts # 풀이 · 줄 번호 걷음