"""Extended tests for benchmarks/benchmark_functions.py. Covers get_available_benchmarks() and compare_configurations(). """ import tempfile from copy import deepcopy from unittest.mock import patch import pytest from local_deep_research.benchmarks.benchmark_functions import ( compare_configurations, get_available_benchmarks, ) # ── get_available_benchmarks ─────────────────────────────────────── class TestGetAvailableBenchmarks: """Tests for get_available_benchmarks.""" def test_returns_list(self): """Return type is a list.""" result = get_available_benchmarks() assert isinstance(result, list) assert len(result) > 0 def test_has_required_fields(self): """Each benchmark dict has id, name, description, recommended_examples.""" for b in get_available_benchmarks(): assert "id" in b assert "name" in b assert "description" in b assert "recommended_examples" in b assert isinstance(b["recommended_examples"], int) def test_includes_all_types(self): """All three benchmark types are present.""" ids = {b["id"] for b in get_available_benchmarks()} assert "simpleqa" in ids assert "browsecomp" in ids assert "xbench_deepsearch" in ids # ── compare_configurations ───────────────────────────────────────── class TestCompareConfigurations: """Tests for compare_configurations.""" def _mock_benchmark_result(self, config_name="test"): return { "metrics": {"accuracy": 0.85, "average_processing_time": 1.5}, "total_examples": 20, } def test_default_configurations(self): """Default 3 configurations are used when none provided.""" with ( patch( "local_deep_research.benchmarks.benchmark_functions.run_benchmark" ) as mock_run, patch( "local_deep_research.security.file_write_verifier.write_file_verified" ), ): mock_run.return_value = self._mock_benchmark_result() with tempfile.TemporaryDirectory() as tmpdir: result = compare_configurations( num_examples=5, output_dir=tmpdir ) # 3 default configs → 3 calls assert mock_run.call_count == 3 assert result["status"] == "complete" assert result["configurations_tested"] == 3 def test_custom_configurations(self): """Custom configurations list is used.""" custom_configs = [ { "name": "Custom A", "search_tool": "brave", "iterations": 2, "questions_per_iteration": 4, }, { "name": "Custom B", "search_tool": "duckduckgo", "iterations": 1, "questions_per_iteration": 2, }, ] with ( patch( "local_deep_research.benchmarks.benchmark_functions.run_benchmark" ) as mock_run, patch( "local_deep_research.security.file_write_verifier.write_file_verified" ), ): mock_run.return_value = self._mock_benchmark_result() with tempfile.TemporaryDirectory() as tmpdir: result = compare_configurations( configurations=deepcopy(custom_configs), num_examples=5, output_dir=tmpdir, ) assert mock_run.call_count == 2 assert result["configurations_tested"] == 2 def test_pops_name_from_config(self): """config.pop('name') mutates the caller's dicts (documenting the bug).""" configs = [ { "name": "Foo", "search_tool": "searxng", "iterations": 1, "questions_per_iteration": 3, }, ] with ( patch( "local_deep_research.benchmarks.benchmark_functions.run_benchmark" ) as mock_run, patch( "local_deep_research.security.file_write_verifier.write_file_verified" ), ): mock_run.return_value = self._mock_benchmark_result() with tempfile.TemporaryDirectory() as tmpdir: compare_configurations( configurations=configs, num_examples=5, output_dir=tmpdir, ) # The original dict has been mutated: "name" was popped assert "name" not in configs[0] def test_generates_report(self): """Comparison report is written via write_file_verified.""" with ( patch( "local_deep_research.benchmarks.benchmark_functions.run_benchmark" ) as mock_run, patch( "local_deep_research.security.file_write_verifier.write_file_verified" ) as mock_write, ): mock_run.return_value = self._mock_benchmark_result() with tempfile.TemporaryDirectory() as tmpdir: result = compare_configurations( num_examples=5, output_dir=tmpdir ) mock_write.assert_called_once() # Report path is returned assert "report_path" in result def test_handles_benchmark_error(self): """Error in run_benchmark for one config propagates (no swallowing).""" configs = [ { "name": "Good", "search_tool": "searxng", "iterations": 1, "questions_per_iteration": 3, }, { "name": "Bad", "search_tool": "searxng", "iterations": 1, "questions_per_iteration": 3, }, ] call_count = 0 def side_effect(**kwargs): nonlocal call_count call_count += 1 if call_count == 2: raise RuntimeError("benchmark failed") return self._mock_benchmark_result() with ( patch( "local_deep_research.benchmarks.benchmark_functions.run_benchmark", side_effect=side_effect, ), patch( "local_deep_research.security.file_write_verifier.write_file_verified" ), ): with tempfile.TemporaryDirectory() as tmpdir: with pytest.raises(RuntimeError, match="benchmark failed"): compare_configurations( configurations=configs, num_examples=5, output_dir=tmpdir, )