Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

272 lines
9.2 KiB
Python

"""High-value tests for benchmarks/datasets/base.py.
Covers BenchmarkDataset ABC enforcement, DatasetRegistry CRUD,
load() with different file formats, sampling, and get_example bounds.
"""
import json
import pytest
from local_deep_research.benchmarks.datasets.base import (
BenchmarkDataset,
DatasetRegistry,
)
class ConcreteBenchmarkDataset(BenchmarkDataset):
"""Minimal concrete implementation for testing."""
@classmethod
def get_dataset_info(cls):
return {
"id": "test-dataset",
"name": "Test",
"description": "For testing",
}
@classmethod
def get_default_dataset_path(cls):
return "/tmp/test_dataset.json"
def process_example(self, example):
return example
class TestBenchmarkDatasetABC:
"""Test abstract base class enforcement."""
def test_cannot_instantiate_directly(self):
"""BenchmarkDataset cannot be instantiated."""
with pytest.raises(TypeError):
BenchmarkDataset()
def test_incomplete_subclass_raises(self):
"""Subclass missing abstract methods raises TypeError."""
class Incomplete(BenchmarkDataset):
pass
with pytest.raises(TypeError):
Incomplete()
def test_complete_subclass_instantiable(self):
"""Complete subclass can be instantiated."""
ds = ConcreteBenchmarkDataset()
assert isinstance(ds, BenchmarkDataset)
class TestBenchmarkDatasetInit:
"""Test BenchmarkDataset initialization."""
def test_default_path_from_class_method(self):
"""Uses get_default_dataset_path when no path provided."""
ds = ConcreteBenchmarkDataset()
assert ds.dataset_path == "/tmp/test_dataset.json"
def test_custom_path_overrides_default(self):
"""Custom path overrides the default."""
ds = ConcreteBenchmarkDataset(dataset_path="/custom/path.json")
assert ds.dataset_path == "/custom/path.json"
def test_not_loaded_initially(self):
"""Dataset is not loaded on init."""
ds = ConcreteBenchmarkDataset()
assert ds._is_loaded is False
assert ds.examples == []
def test_default_seed(self):
"""Default seed is 42."""
ds = ConcreteBenchmarkDataset()
assert ds.seed == 42
def test_custom_num_examples(self):
"""num_examples is stored correctly."""
ds = ConcreteBenchmarkDataset(num_examples=10)
assert ds.num_examples == 10
class TestBenchmarkDatasetLoad:
"""Test load() method."""
def test_load_json_file(self, tmp_path):
"""Loads examples from a JSON file."""
data = [
{"problem": "Q1", "answer": "A1"},
{"problem": "Q2", "answer": "A2"},
]
f = tmp_path / "data.json"
f.write_text(json.dumps(data))
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
examples = ds.load()
assert len(examples) == 2
assert ds._is_loaded is True
def test_load_jsonl_file(self, tmp_path):
"""Loads examples from a JSONL file."""
lines = ['{"problem": "Q1", "answer": "A1"}\n', '{"problem": "Q2"}\n']
f = tmp_path / "data.jsonl"
f.write_text("".join(lines))
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
examples = ds.load()
assert len(examples) == 2
def test_load_csv_file(self, tmp_path):
"""Loads examples from a CSV file."""
f = tmp_path / "data.csv"
f.write_text("problem,answer\nQ1,A1\nQ2,A2\n")
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
examples = ds.load()
assert len(examples) == 2
def test_unsupported_format_raises(self, tmp_path):
"""Unsupported file format raises ValueError."""
f = tmp_path / "data.xml"
f.write_text("<data/>")
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
with pytest.raises(ValueError, match="Unsupported file format"):
ds.load()
def test_load_returns_cached_on_second_call(self, tmp_path):
"""Second call to load() returns cached results."""
f = tmp_path / "data.json"
f.write_text(json.dumps([{"q": "1"}]))
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
first = ds.load()
second = ds.load()
assert first is second
def test_sampling_with_num_examples(self, tmp_path):
"""load() samples when num_examples < total examples."""
data = [{"q": str(i)} for i in range(100)]
f = tmp_path / "data.json"
f.write_text(json.dumps(data))
ds = ConcreteBenchmarkDataset(dataset_path=str(f), num_examples=10)
examples = ds.load()
assert len(examples) == 10
def test_sampling_deterministic_with_seed(self, tmp_path):
"""Same seed produces same sample."""
data = [{"q": str(i)} for i in range(100)]
f = tmp_path / "data.json"
f.write_text(json.dumps(data))
ds1 = ConcreteBenchmarkDataset(
dataset_path=str(f), num_examples=5, seed=42
)
ds2 = ConcreteBenchmarkDataset(
dataset_path=str(f), num_examples=5, seed=42
)
assert ds1.load() == ds2.load()
def test_process_example_error_counted(self, tmp_path):
"""Errors during process_example are counted, not raised."""
data = [{"q": "1"}, {"q": "2"}, {"q": "3"}]
f = tmp_path / "data.json"
f.write_text(json.dumps(data))
class FailingDataset(ConcreteBenchmarkDataset):
def process_example(self, example):
if example["q"] == "2":
raise RuntimeError("bad example")
return example
ds = FailingDataset(dataset_path=str(f))
examples = ds.load()
assert len(examples) == 2 # 3 total - 1 failed
class TestBenchmarkDatasetGetters:
"""Test get_example, get_question, get_answer."""
def test_get_example_valid_index(self, tmp_path):
"""get_example returns the correct example."""
f = tmp_path / "data.json"
f.write_text(json.dumps([{"q": "A"}, {"q": "B"}]))
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
assert ds.get_example(1)["q"] == "B"
def test_get_example_out_of_range(self, tmp_path):
"""get_example raises IndexError for invalid index."""
f = tmp_path / "data.json"
f.write_text(json.dumps([{"q": "A"}]))
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
with pytest.raises(IndexError):
ds.get_example(5)
def test_get_example_negative_index_raises(self, tmp_path):
"""Negative index raises IndexError."""
f = tmp_path / "data.json"
f.write_text(json.dumps([{"q": "A"}]))
ds = ConcreteBenchmarkDataset(dataset_path=str(f))
with pytest.raises(IndexError):
ds.get_example(-1)
def test_get_question_returns_problem_field(self):
"""get_question extracts 'problem' field."""
ds = ConcreteBenchmarkDataset()
assert ds.get_question({"problem": "What is X?"}) == "What is X?"
def test_get_question_missing_field_returns_empty(self):
"""Missing 'problem' field returns empty string."""
ds = ConcreteBenchmarkDataset()
assert ds.get_question({}) == ""
def test_get_answer_prefers_correct_answer(self):
"""get_answer prefers 'correct_answer' over 'answer'."""
ds = ConcreteBenchmarkDataset()
example = {"correct_answer": "CA", "answer": "A"}
assert ds.get_answer(example) == "CA"
def test_get_answer_falls_back_to_answer(self):
"""get_answer falls back to 'answer' field."""
ds = ConcreteBenchmarkDataset()
assert ds.get_answer({"answer": "A"}) == "A"
class TestDatasetRegistry:
"""Test DatasetRegistry registration and retrieval."""
def setup_method(self):
"""Clear registry before each test."""
DatasetRegistry._registry = {}
def test_register_stores_class(self):
"""register() stores the class by its ID."""
DatasetRegistry.register(ConcreteBenchmarkDataset)
assert "test-dataset" in DatasetRegistry._registry
def test_register_no_id_raises(self):
"""register() raises when dataset has no ID."""
class NoIdDataset(ConcreteBenchmarkDataset):
@classmethod
def get_dataset_info(cls):
return {"name": "No ID"}
with pytest.raises(ValueError, match="must have an ID"):
DatasetRegistry.register(NoIdDataset)
def test_get_dataset_class_unknown_raises(self):
"""get_dataset_class raises for unknown ID."""
with pytest.raises(ValueError, match="Unknown dataset"):
DatasetRegistry.get_dataset_class("nonexistent")
def test_create_dataset_returns_instance(self):
"""create_dataset returns a BenchmarkDataset instance."""
DatasetRegistry.register(ConcreteBenchmarkDataset)
ds = DatasetRegistry.create_dataset("test-dataset")
assert isinstance(ds, BenchmarkDataset)
def test_get_available_datasets(self):
"""get_available_datasets returns info for all registered datasets."""
DatasetRegistry.register(ConcreteBenchmarkDataset)
available = DatasetRegistry.get_available_datasets()
assert len(available) == 1
assert available[0]["id"] == "test-dataset"