test(시험 정리 둘): 구조물 정책 시험 = 사용자 구조물정의 판 23 을 읽어 판정 · 취향 저장소 시험 = 저장소 고르는 자리만

- test_b05_structures_registry_policy: 우클릭 목록 수 28 · 끈 종류 목록 · 바닥막이 켬 단언 → 마스터 파일(켬 · 끔 · managed_by)과 같은지로(수 · 이름 안 박음) · 맹암거 암거 높이 3 m · 경사 3 % = 사용자 지시(요구 223 · 4baf49ba4) 근거로 허용 목록
- test_prefs_persist_across_tabs: 388-3 세션 넘침 때 결과 칸 비우는 글(setOrMakeRoom)을 저장소 가름으로 오판 → storageFor 안만 판정

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 09:46:03 +09:00
co-authored by Claude Opus 5.5
parent 31175dd58e
commit b43c4f1060
2 changed files with 37 additions and 25 deletions
@@ -6,7 +6,9 @@
미사용으로 완전 삭제. 배관·BOX암거는 부속 옵션 정의를 갖는다.
"""
from B05_Profile.B05_Profile_Structures_Schema import load_structure_types
import json
from B05_Profile.B05_Profile_Structures_Schema import DEFINITION_PATH, load_structure_types
# 기본값을 남겨 둘 수 있는 항목 — 법정 단일값·사용자 확정값·표시용 문자열뿐이다.
ALLOWED_DEFAULT_KEYS = {
@@ -156,20 +158,17 @@ ALLOWED_DEFAULT_KEYS = {
("box_culvert", "wing_out_height_m"),
("box_culvert", "wing_out_length_m"),
("box_culvert", "wing_out_angle_deg"),
# A군 맹암거 암거 높이 3 m · 암거 경사 3 % — 사용자 지시(요구 223 · 4baf49ba4 · M02 판 21).
("cross_underdrain", "culvert_height_m"),
("cross_underdrain", "culvert_slope_pct"),
}
# B06 이관 보류 — 정의 보존을 위해 삭제하지 않고 enabled=False로 숨긴다.
DISABLED_TYPE_IDS = {
"ditch_side",
"ditch_ridge",
"ditch_berm",
"chute",
"slope_drain",
"underdrain",
"wildlife_path",
"revegetation",
"gravel_surfacing",
}
def _master_types() -> list[dict]:
"""사용자 M02 구조물정의(정본 파일) 그대로 — 켬 · 끔 · 수는 이 표가 정함(시험이 박지 않음)."""
with open(DEFINITION_PATH, encoding="utf-8") as handle:
return json.load(handle)["types"]
# 임도 미사용 확정 — 레지스트리에서 완전 삭제. 바닥막이(bed_sill)는 2026-08-19
# 사용자 지시로 부활해 D군(계류 사방)에 되살렸다.
@@ -189,7 +188,7 @@ def test_quick_add_types_exclude_pipe_family():
def test_all_enabled_non_managed_types_are_quick_addable():
"""잔존 B05 선택지 = A군 3(노출형·개거·맹암거) + C군 5 + D군 3 + E군 14 + G군 1(콘크리트 포장) + 기타 1.
"""잔존 B05 선택지 = 표에서 켠 정본 관리 밖 종류 전부(수는 표가 정함 · 아래는 옛 수 이력).
콘크리트 포장은 2026-08-28 사용자 지시로 되살렸다 — 포장 구간을 기준측점+길이+전/후로
받는 정본이 됐다(종단경사 자동 포장 적용을 대체).
@@ -203,8 +202,17 @@ def test_all_enabled_non_managed_types_are_quick_addable():
아니라 여기 수에 안 잡힌다.)
E군이 10에서 14로 늘었다 — 표 07(PLAN 52-7) 대피로 · 경계석 · 위험표시 · 취수정.
판 23(2026-10-19 · 사용자 M02 저장)부터 켬 · 끔을 구조물마다 표에 적음 — 수는 표가 정함.
판정 = 우클릭 목록 = 표에서 켜고 정본 관리(managed_by) 아닌 종류 전부(빠짐 · 더함 없음).
"""
assert len(_quick_add_types()) == 28
expected = {
row["type_id"]
for row in _master_types()
if not row.get("managed_by") and row.get("enabled", True)
}
assert {item.type_id for item in _quick_add_types()} == expected
assert expected, "우클릭으로 넣을 종류가 하나도 없음"
def test_removed_types_are_absent():
@@ -215,14 +223,12 @@ def test_removed_types_are_absent():
def test_b06_deferred_types_are_disabled_but_preserved():
"""B·F·G군은 B05 선택지에서 빠지되 정의는 남는다(B06 횡단도 옵션 재사용)."""
"""끈 종류도 정의는 남는다(B06 횡단도 옵션 재사용) — 켬 · 끔은 사용자 표(판 23) 그대로."""
by_id = {item.type_id: item for item in load_structure_types()}
for type_id in DISABLED_TYPE_IDS:
assert type_id in by_id, f"{type_id} 정의가 삭제됨 — 보존 대상"
assert by_id[type_id].enabled is False, f"{type_id} enabled=False여야 함"
for type_id, item in by_id.items():
if type_id not in DISABLED_TYPE_IDS:
assert item.enabled is True, f"{type_id}는 활성이어야 함"
rows = _master_types()
assert set(by_id) == {row["type_id"] for row in rows}, "끈 종류를 읽기에서 버림"
for row in rows:
assert by_id[row["type_id"]].enabled is row.get("enabled", True), row["type_id"]
def test_b05_phase_options_are_never_required():
@@ -521,7 +527,7 @@ def test_bed_sill_revived_as_point_type():
옵션 = 형태(돌붙임 찰/메)·면적·높이, 기본 돌붙임(메)·10㎡·0.3m."""
by_id = {item.type_id: item for item in load_structure_types()}
item = by_id["bed_sill"]
assert item.group == "D" and item.placement == "point" and item.enabled
assert item.group == "D" and item.placement == "point" # 켬 · 끔 = 사용자 표(판 23)
options = {option.key: option for option in item.options}
assert options["form"].choices == ["돌붙임(찰)", "돌붙임(메)"]
assert options["form"].default == "돌붙임(메)" and options["form"].phase == "b05"
@@ -31,10 +31,16 @@ def test_취향만_브라우저_저장소로_간다():
def test_설계값은_세션_그대로다():
"""초안·결과가 브라우저 저장소로 새면 프로젝트를 옮겨도 남는다 — 그 경계를 지킨다."""
"""초안·결과가 브라우저 저장소로 새면 프로젝트를 옮겨도 남는다 — 그 경계를 지킨다.
판정 = 저장소를 고르는 자리(`storageFor`)만 — 세션 한도 넘침 때 결과 칸을 비우는 자리(388-3
`setOrMakeRoom`)는 세션 안에서 지울 열쇠를 고를 뿐 저장소를 가르지 않음.
"""
source = _STATE.read_text(encoding="utf-8")
chooser = re.search(r"function storageFor\(key: string\): Storage \{(.*?)\}", source, re.S)
assert chooser, "저장소를 고르는 자리가 없음"
for bucket in ("aislo:draft:", "aislo:result:"):
assert f'startsWith("{bucket}")' not in source, f"{bucket} 까지 저장소를 갈랐음"
assert bucket not in chooser.group(1), f"{bucket} 까지 저장소를 갈랐음"
def test_화면_공용_부품도_같은_판단을_쓴다():