Files
wehub-resource-sync 6b7e6b44f1
Python Build and Type Check / python-ci (ubuntu-latest, 3.11) (push) Has been cancelled
Python Build and Type Check / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Build and Type Check / python-ci (windows-latest, 3.11) (push) Has been cancelled
Python Build and Type Check / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Integration Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Integration Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Notebook Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Notebook Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Smoke Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Smoke Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Unit Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Unit Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
gh-pages / build (push) Has been cancelled
Python Publish (pypi) / Upload release to PyPI (push) Has been cancelled
Spellcheck / spellcheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:37:31 +08:00

293 lines
8.7 KiB
Python

# Copyright (C) 2025 Microsoft
# Licensed under the MIT License
"""Unit tests for load_docs_in_chunks function."""
import logging
from dataclasses import dataclass
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from graphrag.prompt_tune.loader.input import load_docs_in_chunks
from graphrag.prompt_tune.types import DocSelectionType
@dataclass
class MockTextDocument:
"""Mock TextDocument for testing."""
id: str
text: str
title: str
creation_date: str
raw_data: dict[str, Any] | None = None
class MockTokenizer:
"""Mock tokenizer for testing."""
def encode(self, text: str) -> list[int]:
"""Encode text to tokens (simple char-based)."""
return [ord(c) for c in text]
def decode(self, tokens: list[int]) -> str:
"""Decode tokens to text."""
return "".join(chr(t) for t in tokens)
@dataclass
class MockChunk:
"""Mock chunk result."""
text: str
class MockChunker:
"""Mock chunker for testing."""
def chunk(self, text: str, transform: Any = None) -> list[MockChunk]:
"""Split text into sentence-like chunks."""
sentences = [s.strip() for s in text.split(".") if s.strip()]
return [MockChunk(text=s + ".") for s in sentences]
class MockEmbeddingModel:
"""Mock embedding model for testing."""
def __init__(self):
"""Initialize with mock tokenizer."""
self.tokenizer = MockTokenizer()
@pytest.fixture
def mock_config():
"""Create a mock GraphRagConfig."""
config = MagicMock()
config.embed_text.embedding_model_id = "test-model"
config.embed_text.batch_size = 10
config.embed_text.batch_max_tokens = 1000
config.concurrent_requests = 1
config.get_embedding_model_config.return_value = MagicMock()
return config
@pytest.fixture
def mock_logger():
"""Create a mock logger."""
return logging.getLogger("test")
@pytest.fixture
def sample_documents():
"""Create sample documents for testing."""
return [
MockTextDocument(
id="doc1",
text="First sentence. Second sentence. Third sentence.",
title="Doc 1",
creation_date="2025-01-01",
),
MockTextDocument(
id="doc2",
text="Another document. With content.",
title="Doc 2",
creation_date="2025-01-02",
),
]
class TestLoadDocsInChunks:
"""Tests for load_docs_in_chunks function."""
@pytest.mark.asyncio
async def test_top_selection_returns_limited_chunks(
self, mock_config, mock_logger, sample_documents
):
"""Test TOP selection method returns the first N chunks."""
mock_reader = AsyncMock()
mock_reader.read_files.return_value = sample_documents
with (
patch(
"graphrag.prompt_tune.loader.input.create_embedding",
return_value=MockEmbeddingModel(),
),
patch(
"graphrag.prompt_tune.loader.input.create_storage",
return_value=MagicMock(),
),
patch(
"graphrag.prompt_tune.loader.input.create_input_reader",
return_value=mock_reader,
),
patch(
"graphrag.prompt_tune.loader.input.create_chunker",
return_value=MockChunker(),
),
):
result = await load_docs_in_chunks(
config=mock_config,
select_method=DocSelectionType.TOP,
limit=2,
logger=mock_logger,
)
assert len(result) == 2
assert result[0] == "First sentence."
assert result[1] == "Second sentence."
@pytest.mark.asyncio
async def test_random_selection_returns_correct_count(
self, mock_config, mock_logger, sample_documents
):
"""Test RANDOM selection method returns the correct number of chunks."""
mock_reader = AsyncMock()
mock_reader.read_files.return_value = sample_documents
with (
patch(
"graphrag.prompt_tune.loader.input.create_embedding",
return_value=MockEmbeddingModel(),
),
patch(
"graphrag.prompt_tune.loader.input.create_storage",
return_value=MagicMock(),
),
patch(
"graphrag.prompt_tune.loader.input.create_input_reader",
return_value=mock_reader,
),
patch(
"graphrag.prompt_tune.loader.input.create_chunker",
return_value=MockChunker(),
),
):
result = await load_docs_in_chunks(
config=mock_config,
select_method=DocSelectionType.RANDOM,
limit=3,
logger=mock_logger,
)
assert len(result) == 3
@pytest.mark.asyncio
async def test_escapes_braces_in_output(self, mock_config, mock_logger):
"""Test that curly braces are escaped for str.format() compatibility."""
docs_with_braces = [
MockTextDocument(
id="doc1",
text="Some {latex} content.",
title="Doc 1",
creation_date="2025-01-01",
),
]
mock_reader = AsyncMock()
mock_reader.read_files.return_value = docs_with_braces
with (
patch(
"graphrag.prompt_tune.loader.input.create_embedding",
return_value=MockEmbeddingModel(),
),
patch(
"graphrag.prompt_tune.loader.input.create_storage",
return_value=MagicMock(),
),
patch(
"graphrag.prompt_tune.loader.input.create_input_reader",
return_value=mock_reader,
),
patch(
"graphrag.prompt_tune.loader.input.create_chunker",
return_value=MockChunker(),
),
):
result = await load_docs_in_chunks(
config=mock_config,
select_method=DocSelectionType.TOP,
limit=1,
logger=mock_logger,
)
assert len(result) == 1
assert "{{latex}}" in result[0]
@pytest.mark.asyncio
async def test_limit_out_of_range_uses_default(
self, mock_config, mock_logger, sample_documents
):
"""Test that invalid limit falls back to default LIMIT."""
mock_reader = AsyncMock()
mock_reader.read_files.return_value = sample_documents
with (
patch(
"graphrag.prompt_tune.loader.input.create_embedding",
return_value=MockEmbeddingModel(),
),
patch(
"graphrag.prompt_tune.loader.input.create_storage",
return_value=MagicMock(),
),
patch(
"graphrag.prompt_tune.loader.input.create_input_reader",
return_value=mock_reader,
),
patch(
"graphrag.prompt_tune.loader.input.create_chunker",
return_value=MockChunker(),
),
patch(
"graphrag.prompt_tune.loader.input.LIMIT",
3,
),
):
result = await load_docs_in_chunks(
config=mock_config,
select_method=DocSelectionType.TOP,
limit=-1,
logger=mock_logger,
)
assert len(result) == 3
@pytest.mark.asyncio
async def test_chunks_all_documents(
self, mock_config, mock_logger, sample_documents
):
"""Test that all documents are chunked correctly."""
mock_reader = AsyncMock()
mock_reader.read_files.return_value = sample_documents
with (
patch(
"graphrag.prompt_tune.loader.input.create_embedding",
return_value=MockEmbeddingModel(),
),
patch(
"graphrag.prompt_tune.loader.input.create_storage",
return_value=MagicMock(),
),
patch(
"graphrag.prompt_tune.loader.input.create_input_reader",
return_value=mock_reader,
),
patch(
"graphrag.prompt_tune.loader.input.create_chunker",
return_value=MockChunker(),
),
):
result = await load_docs_in_chunks(
config=mock_config,
select_method=DocSelectionType.TOP,
limit=5,
logger=mock_logger,
)
assert len(result) == 5
assert "First sentence." in result
assert "Another document." in result