_split_into_fragments жила в тяжёлой Celery-задаче (celery/sqlalchemy/minio) и не тестировалась, хотя именно она определяет, ЧТО проверяется на плагиат. Вынес в чистый app.fragments.split_into_fragments — тестируется изолированно: - пустой/пробельный текст → []; - текст короче 20 слов → отбрасывается порогом длины; - короткий текст → один фрагмент на весь объём, start=0; - скользящее окно: перекрытие ровно (window-step) слов, хвост==голова соседа; - start/end — корректные символьные офсеты в исходный текст. Поведение сохранено 1:1. Добавлен в mypy-гейт. Тестов всего: 66. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.8 KiB
Python
44 lines
1.8 KiB
Python
"""Юнит-тесты разбиения текста на фрагменты (определяет, что проверяется)."""
|
||
|
||
from app.fragments import split_into_fragments
|
||
|
||
|
||
def _text(n: int) -> str:
|
||
"""n слов одинаковой длины: 'w000 w001 ... ' (по 4 символа + пробел)."""
|
||
return " ".join(f"w{i:03d}" for i in range(n))
|
||
|
||
|
||
def test_empty_text_returns_empty():
|
||
assert split_into_fragments("") == []
|
||
assert split_into_fragments(" ") == []
|
||
|
||
|
||
def test_text_shorter_than_min_words_is_dropped():
|
||
# < 20 слов → единственный кандидат отбрасывается порогом длины
|
||
assert split_into_fragments(_text(19), window=200, overlap=50) == []
|
||
|
||
|
||
def test_short_text_single_fragment_covers_all():
|
||
frags = split_into_fragments(_text(30), window=200, overlap=50)
|
||
assert len(frags) == 1
|
||
assert frags[0]["start"] == 0
|
||
assert frags[0]["text"] == _text(30)
|
||
|
||
|
||
def test_sliding_window_overlap():
|
||
frags = split_into_fragments(_text(50), window=25, overlap=5)
|
||
# step = window - overlap = 20 → окна начинаются со слов 0 и 20
|
||
assert len(frags) == 2
|
||
words0 = frags[0]["text"].split()
|
||
words1 = frags[1]["text"].split()
|
||
assert len(words0) == 25 and len(words1) == 25
|
||
# перекрытие ровно 5 слов: хвост первого == голова второго
|
||
assert words0[-5:] == words1[:5]
|
||
|
||
|
||
def test_char_positions_are_offsets_into_source_text():
|
||
text = _text(30)
|
||
f = split_into_fragments(text, window=25, overlap=5)[0]
|
||
assert text[f["start"]:].startswith("w000") # start — символьный офсет начала
|
||
assert text[: f["end"]].endswith("w024") # end — конец 25-го слова окна
|