Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
165 lines
6.3 KiB
Python
165 lines
6.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""계획노선 편집 창 — **측점 법선 길이 · 고름 연동**(계획서 22-1 · 382-2) 회귀검증.
|
|
|
|
법선 = 그 측점 발자국 비탈 끝 좌 · 우(382-2) · 기록이 없으면 「횡단 반폭(m)」 적용값 양쪽 · 그것도 없으면 원지반 선 범위
|
|
(계산 묶음 그 측점 표본 · 365-3).
|
|
Node 헬퍼(`helper_b05_routeedit_cross_width.cjs`)가 TS 를 트랜스파일해 돌린다.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def results():
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_b05_routeedit_cross_width.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_측점을_고르기_전에는_선이_없다(results):
|
|
assert results["before"] is None
|
|
|
|
|
|
def test_적용한_적_없으면_원지반_범위_양쪽(results):
|
|
assert results["empty"]["watched"] == {"chainageM": 100, "leftM": 20, "rightM": 20}
|
|
|
|
|
|
def test_적용값이_있으면_그_값_양쪽(results):
|
|
assert results["applied15"]["watched"] == {"chainageM": 100, "leftM": 15, "rightM": 15}
|
|
|
|
|
|
def test_페이지_노선_값만_다른_노선_프로젝트는_무시(results):
|
|
# 노선 = 페이지 노선 id 한 칸(386-2b · 옛 「가장 큰 노선 번호」 훑기 지움)
|
|
assert results["otherRoute"]["watched"]["leftM"] == 15
|
|
assert results["latestRoute"]["watched"]["leftM"] == 8.5
|
|
|
|
|
|
def test_망가진_값은_기본값으로(results):
|
|
assert results["badValue"]["watched"]["rightM"] == 20
|
|
|
|
|
|
# ── 382-2 법선 = 발자국 비탈 끝 · 측점 열쇠 · 공용 고름 연동 ──────────────────────
|
|
|
|
|
|
def test_발자국_기록이면_비탈_끝_좌우와_깎기(results):
|
|
assert results["footprint"] == {
|
|
"chainageM": 100,
|
|
"leftM": 7.5,
|
|
"rightM": 6,
|
|
"leftCut": True,
|
|
"rightCut": False,
|
|
}
|
|
|
|
|
|
def test_노선_고친_뒤_같은_열쇠_측점의_새_발자국(results):
|
|
assert results["afterEdit"] == {
|
|
"chainageM": 102,
|
|
"leftM": 9,
|
|
"rightM": 4,
|
|
"leftCut": False,
|
|
"rightCut": True,
|
|
}
|
|
|
|
|
|
def test_평면_눈금_클릭은_공용_고름에_적고_판을_편다(results):
|
|
click = results["planClick"]
|
|
assert click["selection"] == {"chainageM": 40, "structureId": None}
|
|
assert click["heard"] == [{"at": 40, "from": "b05-plan"}]
|
|
assert click["panel"] == "cross"
|
|
assert click["watched"]["chainageM"] == 40
|
|
|
|
|
|
def test_다른_보기_일반측점_고름은_평면_판(results):
|
|
assert results["otherGrid"]["watched"]["chainageM"] == 60
|
|
assert "structure" not in results["otherGrid"]["watched"]
|
|
assert results["otherGrid"]["panel"] == "cross"
|
|
|
|
|
|
def test_관_구조물_고름은_마름모만(results):
|
|
assert results["otherPipe"] == {"chainageM": 80, "leftM": 0, "rightM": 0, "structure": True}
|
|
assert results["otherStructure"]["structure"] is True
|
|
assert results["otherStructure"]["chainageM"] == 60
|
|
|
|
|
|
def test_고름을_풀면_법선도_없다(results):
|
|
assert results["cleared"] == {"watched": None, "redrawn": True}
|
|
|
|
|
|
def test_393_판_그림은_B06_카드_사본_노선_고치면_전후(results):
|
|
# 노선 고친 차례 — 아래 판 = 고치기 전 측점(이전 사본 id) · 위 판 = 새 측점 · B06 카드 id 와 안 겹침
|
|
assert results["cardsAfterEdit"] == ["b05-prev-s100", "b05-cur-s102"]
|
|
|
|
|
|
def test_393_1_눈금이_연_판은_기억_안_함(results):
|
|
assert results["planClick"]["panel"] == "cross"
|
|
assert results["planClick"]["remember"] is False
|
|
|
|
|
|
def test_393_3_판_칸은_그래프만():
|
|
b05 = os.path.join(os.path.dirname(os.path.dirname(HERE)), "B05_Profile")
|
|
|
|
def read(name):
|
|
with open(os.path.join(b05, name), encoding="utf-8") as file:
|
|
return file.read()
|
|
|
|
card = read("B05_Profile_UI_RouteEdit_Cross_Card.ts")
|
|
# 카드 머리(측점 · 알약) · 발(암 경계 · 요약) · 줌 단추 걷음 · 누름 전부 막음
|
|
assert ':scope > header, :scope > footer, .b06-cross-card__zoom"' in card
|
|
assert '"click", (event) => event.stopPropagation(), true' in card
|
|
cross = read("B05_Profile_UI_RouteEdit_Cross.ts")
|
|
assert 'foot.textContent = source ? "" : summarizeCross(preview);' in cross
|
|
css = read("B05_Profile_UI_Style_RouteEdit.css")
|
|
assert ".b05-routeedit__cross-box:has(> .b06-cross-card) {" in css
|
|
assert ".b05-routeedit__cross-foot:empty {\n display: none;" in css
|
|
assert "footer button" not in css
|
|
|
|
|
|
def test_393_4_보기_반폭_한_벌(results):
|
|
# 세션 조절값([보기 반폭 적용]) > 측점 저장 표시 반폭 최댓값 > 기본 10 · 노선 단위
|
|
assert results["halfWidth"] == {
|
|
"none": 10,
|
|
"saved": 14,
|
|
"session": 18,
|
|
"otherRoute": 10,
|
|
"noRoute": 14,
|
|
}
|
|
|
|
|
|
def test_393_4_제목_행_없음_반폭은_B06_값_같이_읽음():
|
|
root = os.path.dirname(os.path.dirname(HERE))
|
|
|
|
def read(*parts):
|
|
with open(os.path.join(root, *parts), encoding="utf-8") as file:
|
|
return file.read()
|
|
|
|
cross = read("B05_Profile", "B05_Profile_UI_RouteEdit_Cross.ts")
|
|
pane = cross.split("function createPane(", 1)[1].split("const station", 1)[0]
|
|
assert "cross-head" not in pane and "cross-title" not in pane
|
|
assert '<div class="b05-routeedit__cross-box"></div>' in pane
|
|
assert "station.textContent = `${tag}${formatStation(" in cross
|
|
assert '"이전 횡단",\n "이전 ",' in cross
|
|
css = read("B05_Profile", "B05_Profile_UI_Style_RouteEdit.css")
|
|
assert ".b05-routeedit__side-wrap .ui-side-panels__head {\n display: none;" in css
|
|
assert "cross-head" not in css
|
|
# 반폭 = B06 입력칸과 같은 함수(사본 상수 없음) · 그릴 때마다 읽음
|
|
card = read("B05_Profile", "B05_Profile_UI_RouteEdit_Cross_Card.ts")
|
|
assert (
|
|
"halfWidthM: () => displayHalfWidth(projectId, pageRouteId(projectId), sections)," in card
|
|
)
|
|
assert "source.halfWidthM()," in card
|
|
assert "DISPLAY_HALF_WIDTH" not in card
|
|
b06 = read("A00_Common", "design", "design_view_cross.ts")
|
|
assert "displayHalfWidth(projectId, currentRouteId, sectionDetail.cross_sections)" in b06
|
|
assert "const DISPLAY_HALF_WIDTH_DEFAULT_M" not in b06
|