Первый настоящий автоматический тест-суит проекта — раньше регрессии ловились руками. Покрыта чистая логика детекции и форматирования (без БД/Redis/GPU/Ollama): - worker-indexer: L1 Winnowing (точные совпадения, идемпотентность отпечатка, диапазон signed int64) и L2 MinHash LSH (шинглы, Jaccard, near-duplicate + upsert через in-memory-фолбэк). - worker-gpu: L3 FAISS — возврат doc_id из PostgreSQL (IndexIDMap2), идемпотентность add_vectors (remove-before-add, без дублей), self-match ≈ 1, ранжирование. Прямо стережёт баги, из-за которых индекс переписывался. - worker-gost: ГОСТ 7.1-2003 и 7.0.5-2008 — авторы (≤3 / 4+ «и др.»/et al.), статья/книга/web, DOI, порядок сортировки кириллица→латиница, стр. в ссылке. Обвязка: per-service pytest.ini/conftest/requirements-test. scripts/run_tests.sh гоняет тесты в изолированных python:3.11-slim контейнерах (не засоряя хост), через Tsinghua-зеркало. CI: job `test` теперь гейтит `deploy` (needs: test) — падение тестов блокирует прод-деплой. make test / make test-one SVC=... Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
"""Юнит-тесты полного библиографического описания по ГОСТ 7.1-2003."""
|
||
|
||
from app.formatters.gost_7_1 import (
|
||
GOST71Formatter,
|
||
_format_author,
|
||
_format_authors,
|
||
_get_sort_key,
|
||
format_full,
|
||
)
|
||
|
||
|
||
def test_author_with_initials():
|
||
assert _format_author({"last_name": "Иванов", "initials": "И. И."}) == "Иванов И. И."
|
||
|
||
|
||
def test_author_initials_get_trailing_dot():
|
||
assert _format_author({"last_name": "Иванов", "initials": "И. И"}) == "Иванов И. И."
|
||
|
||
|
||
def test_author_from_first_name():
|
||
assert (
|
||
_format_author({"last_name": "Петров", "first_name": "Пётр Петрович"})
|
||
== "Петров П.П."
|
||
)
|
||
|
||
|
||
def test_author_last_name_only():
|
||
assert _format_author({"last_name": "Сидоров"}) == "Сидоров"
|
||
|
||
|
||
def test_author_empty():
|
||
assert _format_author({}) == ""
|
||
|
||
|
||
def test_authors_up_to_three_all_listed():
|
||
authors = [{"last_name": "А"}, {"last_name": "Б"}, {"last_name": "В"}]
|
||
assert _format_authors(authors) == "А, Б, В"
|
||
|
||
|
||
def test_authors_four_plus_truncated_ru():
|
||
authors = [{"last_name": n} for n in ("А", "Б", "В", "Г")]
|
||
assert _format_authors(authors, lang="ru") == "А, Б, В, и др."
|
||
|
||
|
||
def test_authors_four_plus_truncated_en():
|
||
authors = [{"last_name": n} for n in ("A", "B", "C", "D")]
|
||
assert _format_authors(authors, lang="en") == "A, B, C, et al."
|
||
|
||
|
||
def test_article_has_journal_year_and_doi():
|
||
doc = {
|
||
"title": "Заголовок статьи",
|
||
"journal": "Вестник науки",
|
||
"year": 2023,
|
||
"volume": "5",
|
||
"issue": "2",
|
||
"pages": "10-20",
|
||
"doi": "10.1234/abc",
|
||
"authors": [{"last_name": "Иванов", "initials": "И.И."}],
|
||
}
|
||
out = format_full(doc)
|
||
assert out.startswith("Иванов И.И.. Заголовок статьи")
|
||
assert "// Вестник науки" in out
|
||
assert "— 2023" in out
|
||
assert "Т. 5" in out and "№ 2" in out
|
||
assert "С. 10-20" in out
|
||
assert out.endswith("DOI: 10.1234/abc")
|
||
|
||
|
||
def test_web_resource_marked_and_has_url():
|
||
doc = {"title": "Портал", "url": "https://example.org", "year": 2024}
|
||
out = GOST71Formatter().format_full(doc)
|
||
assert "[Электронный ресурс]" in out
|
||
assert "URL: https://example.org" in out
|
||
|
||
|
||
def test_sort_key_cyrillic_before_latin():
|
||
ru = _get_sort_key({"authors": [{"last_name": "Яковлев"}]})
|
||
en = _get_sort_key({"authors": [{"last_name": "Adams"}]})
|
||
assert ru < en # кириллица (префикс 0) сортируется раньше латиницы (префикс 1)
|