"""搜索关键词高亮与正文命中片段的单元测试。""" from __future__ import annotations import sys from pathlib import Path import pytest BACKEND_ROOT = Path(__file__).resolve().parents[2] if str(BACKEND_ROOT) not in sys.path: sys.path.insert(0, str(BACKEND_ROOT)) from dms.services.document_query_service import _content_snippet class TestContentSnippet: """_content_snippet 纯函数测试。""" def test_returns_none_when_no_content(self): assert _content_snippet(None, "关键词") is None def test_returns_none_when_no_keyword(self): assert _content_snippet("一些正文内容", None) is None assert _content_snippet("一些正文内容", "") is None assert _content_snippet("一些正文内容", " ") is None def test_returns_none_when_keyword_not_in_content(self): assert _content_snippet("这是一段正文", "不存在") is None def test_keyword_at_start_no_prefix_ellipsis(self): content = "关键词在开头,后面有很多内容" * 10 result = _content_snippet(content, "关键词") assert result is not None assert not result.startswith("……") assert result.endswith("……") assert "关键词" in result def test_keyword_at_end_no_suffix_ellipsis(self): content = "前面有很多内容" * 20 + "尾部关键词" result = _content_snippet(content, "尾部关键词") assert result is not None assert result.startswith("……") assert not result.endswith("……") assert "尾部关键词" in result def test_keyword_in_middle_both_ellipsis(self): content = "前面的内容。" * 20 + "目标词" + "后面的内容。" * 20 result = _content_snippet(content, "目标词") assert result is not None assert result.startswith("……") assert result.endswith("……") assert "目标词" in result def test_short_content_no_ellipsis(self): content = "很短的关键词" result = _content_snippet(content, "关键词") assert result is not None assert not result.startswith("……") assert not result.endswith("……") assert result == content def test_case_insensitive_match(self): content = "Hello World Test" result = _content_snippet(content, "hello") assert result is not None assert "Hello" in result def test_chinese_case_insensitive(self): """中文无大小写,但函数不应崩溃。""" content = "这是一段包含关键词的正文内容" result = _content_snippet(content, "关键词") assert result is not None assert "关键词" in result def test_snippet_length_bounded(self): content = "A" * 500 + "目标" + "B" * 500 result = _content_snippet(content, "目标") assert result is not None # 40 before + keyword + 80 after + 2 ellipsis chars assert len(result) <= 40 + 2 + 80 + 4 # 126 def test_strips_keyword_whitespace(self): content = "前面的内容目标词后面的内容" result = _content_snippet(content, " 目标词 ") assert result is not None assert "目标词" in result