"""스모크 테스트. `pip install fastapi httpx pytest` 후 실행.""" from __future__ import annotations from fastapi.testclient import TestClient from app.main import app def test_health(): with TestClient(app) as client: resp = client.get("/v1/health") assert resp.status_code == 200 body = resp.json() assert body["status"] == "ok" assert body["corpus_size"] >= 0 def test_detect_no_auth_required(): """인증 제거 - 키 없이도 200 응답.""" with TestClient(app) as client: resp = client.post( "/v1/plagiarism/detect", json={"doc_id": "x", "text": "테스트 본문"}, ) assert resp.status_code == 200 def test_detect_returns_schema(): with TestClient(app) as client: resp = client.post( "/v1/plagiarism/detect", json={ "doc_id": "t-1", "text": "어린왕자는 작은 별에서 온 소년이다. 그는 여우를 만나 길들임을 배운다.", }, ) assert resp.status_code == 200 body = resp.json() assert body["doc_id"] == "t-1" assert "matches" in body assert "extracted_elements" in body assert "engine_version" in body def test_copyright_review_returns_only_mobile_tab_fields(): with TestClient(app) as client: resp = client.post( "/v1/plagiarism/review", json={"doc_id": "mobile-1", "text": "창밖으로 보이는 숲은 오늘따라 푸르게 보였다."}, ) assert resp.status_code == 200 body = resp.json() assert set(body) == { "doc_id", "copyright", "similar_sentences", "ai_generation_suspicion", "legal_judgment", "analyzed_at", } assert 0 <= body["copyright"]["originality_percent"] <= 100 assert body["copyright"]["description"] assert body["similar_sentences"]["label"].endswith("건") assert body["ai_generation_suspicion"]["label"] in { "낮음", "중간", "높음", "확인 불가", } assert "matches" not in body assert "extracted_elements" not in body assert "score_semantics" not in body def test_batch_flow(): with TestClient(app) as client: resp = client.post( "/v1/plagiarism/batch", json={ "items": [ {"doc_id": "b-1", "text": "앤 셜리는 초록 지붕 집에 입양된 소녀다."}, ] }, ) assert resp.status_code == 202 job_id = resp.json()["job_id"] status = client.get(f"/v1/plagiarism/batch/{job_id}") assert status.status_code == 200 def test_detect_exposes_score_semantics(): """#9 — 점수/임계값의 의미가 응답에 명시되어야 한다.""" with TestClient(app) as client: resp = client.post( "/v1/plagiarism/detect", json={"doc_id": "s-1", "text": "어린왕자는 작은 별에서 온 소년이다."}, ) assert resp.status_code == 200 sem = resp.json()["score_semantics"] assert sem["threshold_source"] == "server_default" assert sem["threshold_calibrated"] is False assert sem["provisional"] is True, "캘리브레이션 전에는 잠정값으로 노출" assert 0.0 <= sem["union_coverage"] <= 1.0 assert sem["query_chars"] > 0 assert "침해 확률이 아닙니다" in sem["note"] def test_detect_reports_request_threshold_override(): with TestClient(app) as client: resp = client.post( "/v1/plagiarism/detect", json={"doc_id": "s-2", "text": "앤 셜리는 초록 지붕 집에 입양된 소녀다.", "options": {"threshold": 0.4}}, ) sem = resp.json()["score_semantics"] assert sem["threshold_source"] == "request_override" assert sem["threshold_used"] == 0.4 def test_detect_accepts_legal_context(): """#10 — 사람이 확인한 사실을 전달하면 missing_factors 에서 빠진다.""" with TestClient(app) as client: base = client.post( "/v1/plagiarism/detect", json={"doc_id": "l-1", "text": "홍길동은 활빈당을 만들어 재물을 나누었다."}, ).json()["legal_risk"] assert base["access_evidence"] == "not_provided" assert len(base["missing_factors"]) == 3 supplied = client.post( "/v1/plagiarism/detect", json={ "doc_id": "l-2", "text": "홍길동은 활빈당을 만들어 재물을 나누었다.", "legal_context": { "work_type": "literary", "access_evidence": True, "protected_expression_reviewed": True, "rights_verified": True, }, }, ).json()["legal_risk"] assert supplied["access_evidence"] == "provided" assert supplied["protected_expression"] == "reviewed" assert supplied["missing_factors"] == [] def test_matches_carry_match_reasons(): with TestClient(app) as client: resp = client.post( "/v1/plagiarism/detect", json={"doc_id": "r-1", "text": "어린왕자는 작은 별에서 온 소년이다. 그는 여우를 만난다.", "options": {"threshold": 0.01}}, ) for match in resp.json()["matches"]: assert match["match_reasons"], "채택 이유가 비어 있으면 안 된다" assert set(match["match_reasons"]) <= {"score_threshold", "exact_span", "coverage"}