Files
Aislo/resources/tester/test_553_4_de_parts.py
T
eomsangdonandClaude Opus 5.5 f6cfaf446c feat(760-1): 암상 지질도 겹 · 노선 따라 바위 종류 구간 · 밖 겹 출처 줄
- 서버: 지오빅데이터(KIGAM) 수치지질도 1:50,000 — WFS 암상 면(깨진 한글 칸은 기호별 점 조회로 채움) · 받은 범위 ∪ 노선으로 자름 · 저장본 · 노선 따라 1 m 표본 구간 · 키는 서버만(.env GEOBIGDATA_API_KEY · 쿼리 key)
- 그림 조각 대리에 geology(키 쿼리 이름 칸 key_param · 옛 겹 serviceKey 그대로)
- 화면(D03 · B05): 「제한·재해」에 「암상 지질도」 — 그림 조각 + 갈래 색 면 · 「기호 · 암상」 글 · 범례 · 노선 구간 표(참고 — 토사 · 암 판정 아님)
- 켠 밖 겹마다 범례 맨 아래 출처 줄(브이월드 · 국토지리정보원 · 산림청 · 환경부 · 생활안전지도 공공누리 · 한국지질자원연구원 CC BY-NC)
- 범례 칸 높이 한도 · 밀기(낮은 화면)
- 시험: test_760_1 새로 · test_634_2 · test_553_4 겹 차례 표에 geology 한 줄 더함(새 겹 · 낡은 표)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 08:32:53 +09:00

288 lines
14 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_d03_points_parts():
"""591-2 — D02 걷음 · 지점 칸 = 목록 줄 · 아이콘 단추 · 우클릭 메뉴 부품(598-2 = `UI_Menu`)."""
assert not (ROOT / "D02_PlanBase" / "D02_PlanBase_UI_Page.ts").exists()
ts = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Points.ts")
assert "createListRow(" in ts and "createIconButton(" in ts
assert "createMapContextMenu(" in _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Menu.ts")
for raw in ('createElement("button")', 'createElement("input")', 'el("input"'):
assert raw not 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")
draw_panel = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPanel.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(" not in ts
assert (
"createProgressCircle({ size: 16, inline: true })" in ts
) # 604-3 받기 = 위치 칸 제목 서클
site = _src(
"D03_PlanAnalysis/D03_PlanAnalysis_UI_Site.ts"
) # 596-2 위치 칸 · 596-5 등록 찾기 = 같은 부품
assert "createFindList(" in site and "searchPlaces(" in site and "createPlanSite(" in ts
assert "createPlaceFind(" in _src("D01_PlanRegister/D01_PlanRegister_UI_Page.ts")
for raw in ('createElement("button")', 'createElement("input")'):
assert raw not in site, raw
# 562-3 — 날 단추 · 입력 · 고르기 없음 · 도구줄 · 제약 칸 · 연도 고름은 부품
for src in (ts, draw, draw_panel, 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
table = _src("A00_Common/map/map_toolbar.ts") # 624-2 — 차례 · 보임 = 공용 도구줄 표
assert 'mapToolGroups("d03"' in tools and re.search(r'key: "rotate-ccw".*pages: BOTH', table)
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("A00_Common/map/map_layer_list.ts") # 624-2 공용 겹 목록
bar = _src("A00_Common/map/map_layer_bar.ts")
assert (
"createMapTools({" in bar
and "createIconButton({" in bar
and "createMapLayerBar({" in layers
)
assert "createToolbar(" not in layers and "createToolbar(" not in bar
assert '"aislo:pref:d03.layers"' in defs and "writeByKey(MAP_LAYER_PAGES[page].pref" in bar
# 634-2 — 표 차례(요구 546 그룹1 22 + 도로300m) · row(열쇠, 아이콘, 호버제목, 묶음[, true])
rows = re.findall(r'row\("(\w+)", "\w+", "[^"]+", (?:"\w+"|null)(, true)?\)', defs)
keys = [(key, "true" if first else "false") for key, first in rows]
on = {"satellite", "contour", "stream"}
order = "satellite hillshade contour slope stream water zeroOrder bands road nationalRoad"
order += " forestRoadFile roadBands cadastral building place zones soils ecoForest ecology"
order += " landslide landslideZones geology faults lineaments" # 760-1 암상 더함
assert keys == [(key, str(key in on).lower()) for key in order.split()], keys
assert ".d03-plan__icons" in css and ".d03-plan__legend" in css # 634-3 한 행
# 599-1 — 방식 칸 = 마디 고름 2 × 2 · 길이 · 기울기 두 열 · 노드 판(598-4)과 같은 함수
# 626-3 — 방식 칸은 공용 `A00_Common/map/map_draw_kind`(B05 평면도 씀) · D03 칸은 다시 내보냄
kind = _src("A00_Common/map/map_draw_kind.ts")
kind_css = _src("A00_Common/map/map_draw_kind.css")
assert "createSegment({" in kind and kind.count("createInputField(") == 2
assert "columns: 2" in kind and "export function createDrawKindFields(" in kind
assert (
"createDrawKindFields," in draw_panel
and 'from "../A00_Common/map/map_draw_kind"' in draw_panel
)
assert ".map-draw-kind__fields" in kind_css and "createDrawKindFields(" in draw
assert '"길이·기울기 고정"' in kind and '"둘 다"' not in kind
assert "d03-plan__hint" not in draw # 칸 설명 글 걷음(요구 463-6)
# 599-4 — 연도 구역 마커 = 그리기 칸 단추(끌어 놓기) · 지도 도구줄에서 뺌
assert "YEAR_MARK_DRAG" in draw_panel and '"year-mark"' not in tools
props = _src("D03_PlanAnalysis/D03_PlanAnalysis_UI_Props.ts") # 585-2 조각 연도 = 속성 판
assert "createSelectField(" in props and "createFloatPanel(" in props and "createKv(" in props
assert 'createElement("button")' not in props and 'createElement("select")' not in props
assert (
'createElement("select")' not in three and "createSelectField" not in three
) # 601 선 고름 걷음
assert (
"createCheckbox" not in three and "setCorridors(" in three
) # 601 노선망 예상 코리도 한 번에
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