o2o-plagiarism-ai/tests/test_structural.py

73 lines
3.1 KiB
Python

"""구조 분석(lemma 교집합) 단위테스트.
전임자 핵심 시나리오: "원본을 복붙하고 말투/어미만 바꾼 표절" 탐지 검증.
"""
from __future__ import annotations
import pytest
from app.engine.structural import extract_lemmas, lemma_overlap_ratio
def test_extract_lemmas_includes_content_words():
lemmas = extract_lemmas("홍길동은 활빈당을 만들어 탐관오리의 재물을 빼앗았다")
# 내용어들이 기본형으로 추출되어야 함
assert "홍길동" in lemmas
assert "활빈당" in lemmas
assert "탐관오리" in lemmas
assert "재물" in lemmas
assert "만들다" in lemmas
assert "빼앗다" in lemmas
def test_extract_lemmas_excludes_function_words():
lemmas = extract_lemmas("그는 그것을 보았다")
# 조사/어미는 빠져야 함
assert "" not in lemmas
assert "" not in lemmas
# 동사 lemma는 들어가야 함
assert "보다" in lemmas
def test_lemma_overlap_endings_dont_matter():
"""전임자 핵심: 어미만 바꾼 표절은 lemma 교집합으로 100% 탐지."""
original = "홍길동은 활빈당을 만들어 탐관오리의 재물을 빼앗았다"
plagiarized_endings = "홍길동이 활빈당을 만들고 탐관오리의 재물을 빼앗는다" # 어미만 변경
paraphrased = "전혀 다른 사람이 자선단체를 조직해 부패한 관료의 돈을 가져갔다" # 어휘 전체 교체
orig_lemmas = extract_lemmas(original)
plag_lemmas = extract_lemmas(plagiarized_endings)
para_lemmas = extract_lemmas(paraphrased)
overlap_endings = lemma_overlap_ratio(plag_lemmas, orig_lemmas)
overlap_paraphrase = lemma_overlap_ratio(para_lemmas, orig_lemmas)
# 어미만 바꾼 표절은 lemma 교집합 80% 이상
assert overlap_endings >= 0.80, f"어미 변경 표절을 못 잡음: {overlap_endings}"
# 패러프레이즈는 50% 미만이어야 정상
assert overlap_paraphrase < 0.50, f"패러프레이즈에 점수가 너무 높음: {overlap_paraphrase}"
# 두 점수가 명확히 구분되어야 함
assert overlap_endings - overlap_paraphrase >= 0.40
def test_lemma_overlap_character_swap_partial():
"""인물 이름만 치환한 경우: lemma 점수가 중간."""
original = "홍길동은 활빈당을 만들어 탐관오리의 재물을 빼앗았다"
swapped = "김민수는 정의단을 만들어 탐관오리의 재물을 빼앗았다" # 인물 lemma 2개만 다름
overlap = lemma_overlap_ratio(extract_lemmas(swapped), extract_lemmas(original))
# 인물 lemma만 빠지므로 점수는 0.5~0.8 범위
assert 0.40 <= overlap <= 0.85, f"기대 범위 벗어남: {overlap}"
def test_lemma_overlap_empty():
assert lemma_overlap_ratio([], ["a"]) == 0.0
assert lemma_overlap_ratio(["a"], []) == 0.0
def test_lemma_overlap_query_basis():
"""짧은 query가 긴 reference의 부분집합일 때 100% 가까이 나와야."""
short = ["홍길동", "활빈당"]
long = ["홍길동", "활빈당", "탐관오리", "재물", "조선", ""] * 10
assert lemma_overlap_ratio(short, long) == 1.0