Files
Aislo/resources/tester/test_553_4_de_parts.py
T
eomsangdonandClaude Opus 5.5 cc909d107e feat(D03): 연도 구역 마커 끌어 놓기 · 선 밖으로 끌어내 지움 · 긋는 해 걷음 · 갈래 시점 지정 (PLAN 585-3 · 요구 445 A6 · 446)
- 도구줄 「연도 마커」(공용 지도 도구줄 year-mark · 깃발 아이콘)를 선 위로 끌어 놓음 = 그 자리 구간을 둘로 — 구역만 나눔 · 해 그대로
- 끄는 동안 마름모 미리보기 · 선 끝 · 다른 마커 1 m 안 · 선 밖 = 경고 색 · 못 놓음
- 놓인 마커 끌기 = 경계 옮김 · 선 밖으로 끌어냄 · 오른쪽 누름 · Delete = 지움(앞 구간과 합침) · 같은 해 양쪽 = 속 빈 마름모
- 좌측 [연도 구분] · 「긋는 해」 걷음 · 새 선 = 사업연도 시작 해 · 새 갈래 = 붙은 자리 구간 해
- 속성 판 [갈래 시점 지정] = 다른 선에 닿은 끝을 시점(No.0)으로 갈래 · 꼬리에 닿은 머리 = 한 선 · 본선 = [방향 바꾸기]
- 시험: 585-2 시험에 나눔 · 합침 · 갈래 해 · 갈래 시점 덧 · 530-3 갈래 해 · 553-4 속성 판 · 568-1 도구줄 목록 맞춤

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 18:51:04 +09:00

269 lines
12 KiB
Python

"""553-4 예정노선(D01~D04) · 안정성평가(E01~E07) 부품 옮김 지킴 시험 — 서버 · 화면 없이 소스만 본다.
옮긴 페이지는 날 `<input>` · `<progress>` · 날 색 · 안 쓰는 변종 CSS 가 다시 생기면 안 됨."""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
def _src(path: str) -> str:
return (ROOT / path).read_text(encoding="utf-8")
def _no_hex(path: str) -> None:
css = re.sub(r"/\*.*?\*/", "", _src(path), flags=re.S)
assert not re.search(r"#[0-9a-fA-F]{3,8}\b", css), f"{path}: 날 색"
def test_d02_parts():
ts = _src("D02_PlanBase/D02_PlanBase_UI_Page.ts")
css = _src("D02_PlanBase/D02_PlanBase_UI_Style.css")
assert 'el("input"' not in ts
assert 'createInputField({ type: "number"' in ts
assert 'classList.add("d02-info")' in ts # 촬영 장면이 `p.d02-info` 로 잡음
for dead in (".d02-info", "is-invalid", "font-size: var(--text-caption);\n}\n\n.d02-info"):
assert dead not in css
assert "data-axis" in ts or "dataset.axis" in ts
def test_d03_parts():
ts = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts")
three = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_3D.ts")
css = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css")
draw = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Draw.ts")
tools = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Map.ts")
layers = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts")
assert 'createElement("progress")' not in ts and "createProgressBar()" in ts
# 562-3 — 날 단추 · 입력 · 고르기 없음 · 도구줄 · 제약 칸 · 연도 고름은 부품
for src in (ts, draw, tools, layers):
for raw in ('createElement("button")', 'createElement("input")', 'createElement("select")'):
assert raw not in src, raw
# 568-3 — 도구줄 = 공용 지도 도구줄 · 아홉([?] · 되돌리기 · 다시하기 · 3D · 돌리기 둘 · 측점 · 기울기 · 재기)
assert "createMapTools({" in tools and "hint:" in tools and "leftPan" not in tools
assert "createToolbar(" not in tools and "createIconButton(" not in tools
for act in ("undo", "redo", "view3d", "measure", "stations", "slopes"):
assert f'mapToolButton("{act}"' in tools or f'markButton("{act}"' in tools, act
assert '"rotate-ccw", "rotate-cw"' in tools
for b05_only in ("footprint", "station-snap", "contour-minor"):
assert f'"{b05_only}"' not in tools, b05_only
paint = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPaint.ts") # 580 — 그림 나눔
assert "map.stations" in paint and "map.slopes" in paint
# 569-2 · 581-1 · 581-2 — 바탕 겹 단추(공용 지도 도구줄 한 줄 · 묶음 셋) · 처음 켬 셋 · 취향 기억
defs = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_LayerDefs.ts")
assert "createMapTools({" in layers and "createIconButton({" in layers
assert "createToolbar(" not in layers
assert '"aislo:pref:d03.layers"' in layers and "writeByKey(PREF_KEY" in layers
keys = re.findall(r'key: "(\w+)",\s+icon: "\w+",\s+title:\s+"[^"]+",\s+on: (true|false)', defs)
assert keys == [
("satellite", "true"),
("hillshade", "false"),
("contour", "true"),
("slope", "false"),
("stream", "true"),
("water", "false"),
("road", "false"),
("forestRoad", "false"),
("forestRoadFile", "false"),
("cadastral", "false"),
("zones", "false"),
("soils", "false"),
("landslide", "false"),
("landslideZones", "false"),
("faults", "false"),
("lineaments", "false"),
("zeroOrder", "false"),
("bands", "false"),
("building", "false"),
("place", "false"),
], keys
assert ".d03-plan__layers" in css and ".d03-plan__legend" in css
assert "createSegment({" in draw and draw.count("createInputField(") == 2
props = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Props.ts") # 585-2 조각 연도 = 속성 판
assert "createSelectField(" in props and "createFloatPanel(" in props
assert 'createElement("button")' not in props and 'createElement("select")' not in props
assert 'createElement("select")' not in three and "createSelectField" in three
assert "createCheckbox" not in three and "buildCorridor" not in three # 예상 코리도 걷음
for dead in (".d03-plan__bar", ".d03-plan__mode", "is-picked"):
assert dead not in css, dead
assert "b05-route__3d-modal" not in three and "b05-route__3d-body" not in three # 빌림 끊음
assert 'dialogClass: "d03-plan__3d-modal"' in three and ".d03-plan__3d-body" in css
scenes = _src("A05_EduDetail/guide/D03/_scenes.json")
assert "b05-route__3d-modal" not in scenes # 촬영 장면이 `.d03-plan__3d-modal` 로 잡음
def test_d04_parts():
ts = _src("D04_PlanConfirm/D04_PlanConfirm_UI_Page.ts")
css = _src("D04_PlanConfirm/D04_PlanConfirm_UI_Style.css")
assert 'el("input"' not in ts
assert ts.count("createInputField(") == 2 and "createCheckbox(" in ts
assert 'createBanner({ tone: "warning"' in ts
assert "input:checked" in ts # [확정] 이 고른 연도를 읽는 길
assert "border:" not in css.split(".d04-confirm__input")[1].split("}")[0]
assert ".d04-confirm__dirty" not in css
assert 'el("table"' not in ts and "tableShell(columns)" in ts
assert "d04-confirm__table" not in css # 표 모양은 표 부품 · 이름은 촬영 장면용 걸이
def test_e01_missing_is_banner_part():
ts = _src("E01_StabRegister/E01_StabRegister_UI_Missing.ts")
assert "createBanner" in ts and '"details"' not in ts
assert 'dataset.role = "missing-stations"' in ts # 시험 · 촬영이 잡음
assert not (ROOT / "E01_StabRegister/E01_StabRegister_UI_Missing.css").exists()
def test_e02_parts():
tables = _src("E02_StabGround/E02_StabGround_UI_Tables.ts")
page = _src("E02_StabGround/E02_StabGround_UI_Page.ts")
css = _src("E02_StabGround/E02_StabGround_UI_Style.css")
assert 'el("input"' not in tables and 'el("select"' not in tables
assert "createInputField(" in tables and "createSelectField(" in tables
assert "createCard({ title" in tables
assert "is-invalid" not in page + css and "is-error" in page
for dead in (".e02-card__head", ".e02-card__title", ".e02-hint", ".e02-empty"):
assert dead not in css, dead
_no_hex("E02_StabGround/E02_StabGround_UI_Style.css")
assert "createTable(" in tables and "createTHead" not in tables
assert 'className: "ui-field e02-field"' in tables # 칸 이름 줄은 입력 부품의 ui-field
assert ".e02-field" not in css and "border-collapse" not in css
def test_e03_parts():
names = [
"List", "Page", "Plan", "Prob", "ProbChart", "Reinforce", "Result", "Section", "Support", "View3D",
] # fmt: skip
ts = {n: _src(f"E03_StabSection/E03_StabSection_UI_{n}.ts") for n in names}
css = _src("E03_StabSection/E03_StabSection_UI_Style.css")
for n, src in ts.items():
assert 'el("table"' not in src, n # 표 = 표 부품(`E03_StabSection_UI_Table.ts`)
assert 'el("input"' not in src and 'el("select"' not in src, n
assert "e03-legend__item" not in src and "e03-legend__swatch" not in src, n
assert "createTable(" in _src("E03_StabSection/E03_StabSection_UI_Table.ts")
assert "dataset.role = role" in _src("E03_StabSection/E03_StabSection_UI_Table.ts")
assert "createLegend(" in _src("E03_StabSection/E03_StabSection_UI_Parts.ts")
assert "openModal(" in ts["View3D"] and 'className: "e03-view3d"' not in ts["View3D"]
for key in ("station-list", "slice-table", "methods", "whatif-table", "support-table"):
assert f'"{key}"' in "".join(ts.values()), key # 촬영 장면 · 시험이 잡는 data-role
for dead in (
".e03-legend__item", ".e03-legend__swatch", ".e03-table", ".e03-verdict", ".e03-kpi",
".e03-view3d {", ".e03-swatch-none", ".e03-list table", ".e03-list th {",
): # fmt: skip
assert dead not in css, dead
def test_e04_parts():
page = _src("E04_Stab3D/E04_Stab3D_UI_Page.ts")
view = _src("E04_Stab3D/E04_Stab3D_UI_View3D.ts")
css = _src("E04_Stab3D/E04_Stab3D_UI_Style.css")
assert 'el("progress"' not in page and "createProgressBar()" in page
for part in (
"createSegment(",
"createListRow(",
"createKv(",
"createFloatPanel(",
"createBanner(",
):
assert part in page, part
assert 'el("input"' not in view and "createCheckbox(" in view
assert (
'classList.add("e04-toggle")' in page
) # 촬영 장면이 `.e04-toggle button[data-value]` 로 잡음
assert 'row.classList.add("e04-section")' in page
for dead in (
".e04-toggle .ui-btn",
".e04-legend__row",
".e04-legend__swatch",
".e04-result__list",
".e04-section:hover",
):
assert dead not in css, dead
def test_e05_parts():
ts = _src("E05_StabReport/E05_StabReport_UI_Page.ts")
css = _src("E05_StabReport/E05_StabReport_UI_Style.css")
for part in ("createBanner(", "openModal(", "createEmpty(", "createText("):
assert part in ts, part
assert 'el("p"' not in ts and "previewBox" not in ts
assert 'classList.add("e05-stale")' in ts # 촬영 장면이 `.e05-stale .ui-btn` 으로 잡음
assert ".e05-stale[hidden]" in css # 띠 알림은 flex 라 hidden 을 덮음
for dead in (".e05-preview {", ".e05-preview__head", ".e05-status.is-error"):
assert dead not in css, dead
def test_e06_parts():
names = ["Joints", "Page", "Result", "Stereonet"]
ts = {n: _src(f"E06_StabRock/E06_StabRock_UI_{n}.ts") for n in names}
parts = _src("E06_StabRock/E06_StabRock_UI_Parts.ts")
css = _src("E06_StabRock/E06_StabRock_UI_Style.css")
for n, src in ts.items():
assert 'el("table"' not in src and 'el("input"' not in src, n
assert 'el("select"' not in src and 'el("p"' not in src, n
for part in ("createTable(", "createBadge(", "createSegment(", "createText(", "createEmpty("):
assert part in parts, part
assert "createLegend(" in ts["Stereonet"] and "createBanner(" in ts["Page"]
assert "createInputField(" in ts["Joints"] and "createSelectField(" in ts["Joints"]
assert "compact: true" in ts["Joints"] and ".e06-setting" not in css # 설정 줄 부품 좁은 꼴
assert (
'classList.add("e06-toggle")' in parts
) # 촬영 장면이 `.e06-toggle button[data-value]` 로 잡음
assert '"station-list"' in ts["Result"] # 촬영 장면 · 시험이 잡는 data-role
for dead in (
".e06-verdict",
".e06-list th",
".e06-cases",
".e06-table th",
".e06-legend__row",
".e06-toggle .ui-btn",
"is-invalid",
):
assert dead not in css, dead
assert "is-invalid" not in ts["Joints"] + ts["Page"]
def test_e07_parts():
page = _src("E07_StabArea/E07_StabArea_UI_Page.ts")
css = _src("E07_StabArea/E07_StabArea_UI_Style.css")
assert 'el("table"' not in page and 'el("progress"' not in page and 'el("p"' not in page
for part in (
"createSegment(",
"createFloatPanel(",
"createLegend(",
"createKv(",
"createTable(",
):
assert part in page, part
for part in ("createProgressBar()", "createBanner(", "createEmpty("):
assert part in page, part
assert (
'toggle.classList.add("e07-toggle")' in page
) # 촬영 장면이 `.e07-toggle button[data-value]` 로 잡음
assert "data-chainage" in css or "dataset.chainage" in page # 줄 누름 = 지도 이동
for dead in (
".e07-toggle .ui-btn",
".e07-legend__row",
".e07-summary",
".e07-table th",
".e07-progress {",
):
assert dead not in css, dead
def test_map_tips_use_tooltip_part():
for path, hook in (
("E03_StabSection/E03_StabSection_UI_Section.ts", "e03-tip"),
("E04_Stab3D/E04_Stab3D_UI_Map.ts", "e04-map__tip"),
("E07_StabArea/E07_StabArea_UI_Map.ts", "e07-map__tip"),
):
ts = _src(path)
assert 'tooltipBox("")' in ts and f'classList.add("{hook}")' in ts, path
for path, dead in (
(
"E03_StabSection/E03_StabSection_UI_Style.css",
"background: var(--color-surface);\n border:",
),
("E04_Stab3D/E04_Stab3D_UI_Style.css", "white-space: pre;"),
("E07_StabArea/E07_StabArea_UI_Style.css", "white-space: pre;"),
):
assert dead not in _src(path).replace("\r\n", "\n"), path