"""업종 스키마 — 4개 업종 파일이 규약대로 로드되는지. 업종 추가 = resources/ 에 JSON 1개 + PlaceCategory 코드 1줄. 이 테스트는 그 규약이 깨지면 잡는다. """ import pytest from common.category_schema import CategorySchemaError, all_schemas, get_schema, is_valid_key from common.enums import PlaceCategory def test_all_categories_have_schema(): """검증: PlaceCategory 의 모든 업종에 스키마 파일이 있는지. 기대결과: 4개 업종(숙박·카페·음식점·관광체험)이 모두 로드되고 code 가 1:1로 맞는다.""" schemas = all_schemas() assert set(schemas) == {c.value for c in PlaceCategory} for code, schema in schemas.items(): assert schema.code == code assert schema.category == PlaceCategory(code) assert schema.fields, f"{schema.name}: 필드가 비었다" def test_keys_unique_within_category(): """검증: 업종 안에서 fact key 가 유일한지. 기대결과: 중복 없음 (facts 의 (place,unit,key) 유니크가 의미를 가지려면 필수).""" for schema in all_schemas().values(): keys = list(schema.fields) assert len(keys) == len(set(keys)), f"{schema.name}: key 중복" def test_place_and_unit_scopes_exist(): """검증: 업종마다 place 스코프 필드가 있는지. 기대결과: 전 업종에 place 필드 존재. unit 필드는 업종별로 있을 수도 없을 수도 있다.""" for schema in all_schemas().values(): assert schema.keys_by_scope("place"), f"{schema.name}: place 스코프 필드가 없다" def test_lodging_has_claim_critical_fields(): """검증: 숙박 업종에 예약 클레임 직결 항목이 critical 로 잡혀 있는지. 기대결과: 체크인·체크아웃·취사·반려동물·취소규정이 모두 critical=True 이고 LLM 이 못 쓴다.""" schema = get_schema(PlaceCategory.LODGING) for key in ("check_in_time", "check_out_time", "cooking_allowed", "pet_allowed", "cancel_policy"): spec = schema.get(key) assert spec is not None, f"숙박 스키마에 {key} 가 없다" assert spec.critical is True, f"{key} 는 critical 이어야 한다" assert spec.allow_llm is False, f"{key} 는 LLM 이 값을 만들면 안 된다" def test_llm_writable_fields_are_sentences_only(): """검증: LLM 이 값을 만들 수 있는 필드가 '문장' 필드뿐인지 (절대규칙 7 — LLM 은 사실을 만들지 않는다). 기대결과: allow_llm=True 인 필드는 전부 type=text 이고 critical 이 아니다.""" for schema in all_schemas().values(): for key in schema.llm_writable_keys(): spec = schema.get(key) assert spec.type == "text", f"{schema.name}.{key}: LLM 이 쓸 수 있는 필드는 text 여야 한다" assert spec.critical is False, f"{schema.name}.{key}: critical 필드를 LLM 이 쓰면 안 된다" def test_required_fields_are_never_llm_written(): """검증: 발행 필수 항목을 LLM 이 채우지 못하는지. 기대결과: required=True 인 필드는 전부 allow_llm=False.""" for schema in all_schemas().values(): for key in schema.required_keys(): assert schema.get(key).allow_llm is False, f"{schema.name}.{key}: 필수 항목을 LLM 이 채우면 안 된다" def test_is_valid_key_rejects_cross_category_key(): """검증: 업종에 없는 key 를 걸러내는지 (facts 쓰기 전 FACT_INVALID_KEY 판정). 기대결과: 숙박의 check_in_time 은 카페 스키마에서 거부된다.""" assert is_valid_key(PlaceCategory.LODGING, "check_in_time") is True assert is_valid_key(PlaceCategory.CAFE, "check_in_time") is False assert is_valid_key(PlaceCategory.CAFE, "break_time") is True def test_unknown_category_raises(): """검증: 지원하지 않는 업종 코드 조회. 기대결과: CategorySchemaError.""" with pytest.raises(CategorySchemaError): get_schema(99)