Files
Aislo/resources/tester/test_54_2_help_files.py
T
eomsangdonandClaude Opus 5.5 0f32c241ca feat(가이드): 538-1 글 자리 A05_EduDetail/guide 로 옮김 + GET /api/help 한 가이드 읽기
- resources/help → A05_EduDetail/guide (git mv · 이력 남김) · 참조 고침(서버 · 시험 · B03 주석 · ui_checks)
- GET /api/help = 모든 페이지 [{page, title, items:[{key, title, text, version}]}] + admin
  · 페이지 = ^[BDE]\d{2}$ 폴더 · `_` 파일 · 그림 뺌 · version = sha256 앞 16자 · 페이지 제목 = 00_설명서 제목
- GET /api/help/{page} 는 538-2 까지 살림 · B01 폴더 허용
- 시험: 글 내용 검사(명사형 · 400 자) 걷음 — 시스템 관리자가 화면에서 바로 고친 글이
  지킴 시험을 빨갛게 하지 않게(요구서 359 4장 6) · 차례 · 판 · `_` 파일 · 나쁜 폴더 · 경로 탈출 시험 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 08:37:33 +09:00

89 lines
3.6 KiB
Python

"""54-2 · 538 [?] 가이드 — 서버가 A05_EduDetail/guide/<페이지>/*.md 를 부를 때마다 읽음.
글 내용 검사(명사형 · 길이)는 두지 않음 — 관리자가 화면에서 고친 글이 시험을 빨갛게 안 하게.
"""
import shutil
import tempfile
from pathlib import Path
import pytest
from fastapi import HTTPException
from common_util.common_util_help_router import HELP_ROOT, file_version, read_guide, read_help
@pytest.fixture
def tmp_path(): # 기본 pytest 임시 폴더가 이 PC 에서 막힘 — 직접 만듦
path = Path(tempfile.mkdtemp())
yield path
shutil.rmtree(path, ignore_errors=True)
def test_every_page_has_manual_first():
for page in [f"B0{n}" for n in range(2, 10)] + [f"D0{n}" for n in range(1, 5)]:
items = read_help(page)
assert items and items[0]["key"] == "00_설명서", page
for n in range(1, 8):
assert read_help(f"E0{n}")[0]["key"] == "00_설명서"
def test_title_order_and_live_edit(tmp_path):
page = tmp_path / "B05"
page.mkdir()
(page / "10_배관.md").write_text("# 배관\n\n본문", encoding="utf-8")
(page / "00_설명서.md").write_text("제목 없음", encoding="utf-8")
items = read_help("B05", tmp_path)
assert [i["key"] for i in items] == ["00_설명서", "10_배관"]
assert [i["title"] for i in items] == ["00_설명서", "배관"]
(page / "10_배관.md").write_text("# 배관\n\n고친 글", encoding="utf-8")
assert "고친 글" in read_help("B05", tmp_path)[1]["text"]
def test_version_is_file_hash_and_changes(tmp_path):
page = tmp_path / "B05"
page.mkdir()
path = page / "00_설명서.md"
path.write_text("# 종단\n", encoding="utf-8")
first = read_help("B05", tmp_path)[0]["version"]
assert first == file_version(path.read_bytes()) and len(first) == 16
path.write_text("# 종단\n고침\n", encoding="utf-8")
assert read_help("B05", tmp_path)[0]["version"] != first
def test_guide_pages_order_title_and_skips(tmp_path):
for name in ["E02", "B05", "B01", "b03", "X01", "B5", "_B04", "D01"]:
(tmp_path / name).mkdir()
(tmp_path / "B05" / "00_설명서.md").write_text("# 종단 설계\n", encoding="utf-8")
(tmp_path / "B05" / "_scenes.md").write_text("# 장면\n", encoding="utf-8")
(tmp_path / "B05" / "그림.webp").write_bytes(b"x")
(tmp_path / "B01" / "00_설명서.md").write_text("# 대시보드\n", encoding="utf-8")
(tmp_path / "E02" / "10_칸_뜻.md").write_text("# 칸\n", encoding="utf-8")
for name in ["b03", "X01", "B5", "_B04"]:
(tmp_path / name / "00_설명서.md").write_text("# 나쁨\n", encoding="utf-8")
pages = read_guide(tmp_path)
assert [p["page"] for p in pages] == ["B01", "B05", "E02"] # D01 = 글 없음 · 나쁜 폴더 뺌
assert [p["title"] for p in pages] == ["대시보드", "종단 설계", "E02"]
assert [i["key"] for i in pages[1]["items"]] == ["00_설명서"] # `_` 파일 · 그림은 항목 아님
def test_real_guide_reads_all_pages():
pages = {p["page"] for p in read_guide()}
assert {"B02", "B05", "B06", "D01", "E02", "E07"} <= pages
@pytest.mark.parametrize("page", ["../B05", "b05", "B5", "C01", "B05/..", "..", "B100"])
def test_bad_page_refused(page):
with pytest.raises(HTTPException):
read_help(page)
def test_missing_page_opens_empty(tmp_path):
assert read_help("D02", tmp_path) == [] and read_help("B10", tmp_path) == []
def test_root_is_a05_guide():
assert HELP_ROOT.parts[-2:] == ("A05_EduDetail", "guide")
assert HELP_ROOT.is_dir()
assert not (Path(HELP_ROOT).parents[1] / "resources" / "help").exists()