""" Tests for benchmarks/comparison/evaluator.py covering missing lines. Covers: - Lines 539-543: Duration conversion (hours, minutes) in _create_metric_comparison_chart - Lines 599-652: Spider chart RadarAxes creation (polygon frame, unit_poly_verts) - Lines 723-736: Spider chart exception fallback - Lines 783-784: Pareto chart dominated point detection - _calculate_average_metrics with speed/resource/quality metrics """ from pathlib import Path from unittest.mock import patch MODULE = "local_deep_research.benchmarks.comparison.evaluator" # --------------------------------------------------------------------------- # _calculate_average_metrics # --------------------------------------------------------------------------- class TestCalculateAverageMetrics: def test_averages_quality_metrics(self): from local_deep_research.benchmarks.comparison.evaluator import ( _calculate_average_metrics, ) results = [ { "success": True, "quality_metrics": {"accuracy": 0.8, "completeness": 0.6}, "speed_metrics": {}, "resource_metrics": {}, }, { "success": True, "quality_metrics": {"accuracy": 0.9, "completeness": 0.7}, "speed_metrics": {}, "resource_metrics": {}, }, ] avg = _calculate_average_metrics(results) assert abs(avg["quality_metrics"]["accuracy"] - 0.85) < 0.01 assert abs(avg["quality_metrics"]["completeness"] - 0.65) < 0.01 def test_averages_speed_metrics(self): from local_deep_research.benchmarks.comparison.evaluator import ( _calculate_average_metrics, ) results = [ { "success": True, "quality_metrics": {}, "speed_metrics": {"total_duration": 120}, "resource_metrics": {}, }, { "success": True, "quality_metrics": {}, "speed_metrics": {"total_duration": 180}, "resource_metrics": {}, }, ] avg = _calculate_average_metrics(results) assert avg["speed_metrics"]["total_duration"] == 150.0 def test_averages_resource_metrics(self): from local_deep_research.benchmarks.comparison.evaluator import ( _calculate_average_metrics, ) results = [ { "success": True, "quality_metrics": {}, "speed_metrics": {}, "resource_metrics": {"token_count": 1000}, }, { "success": True, "quality_metrics": {}, "speed_metrics": {}, "resource_metrics": {"token_count": 2000}, }, ] avg = _calculate_average_metrics(results) assert avg["resource_metrics"]["token_count"] == 1500.0 def test_skips_none_values(self): from local_deep_research.benchmarks.comparison.evaluator import ( _calculate_average_metrics, ) results = [ { "success": True, "quality_metrics": {"accuracy": 0.9}, "speed_metrics": {}, "resource_metrics": {}, }, { "success": True, "quality_metrics": {}, "speed_metrics": {}, "resource_metrics": {}, }, ] avg = _calculate_average_metrics(results) assert avg["quality_metrics"]["accuracy"] == 0.9 # --------------------------------------------------------------------------- # _create_metric_comparison_chart: duration conversion (lines 538-543) # --------------------------------------------------------------------------- class TestMetricComparisonDurationConversion: def test_duration_hours_conversion(self, tmp_path): """Duration > 3600 is converted to hours.""" from local_deep_research.benchmarks.comparison.evaluator import ( _create_metric_comparison_chart, ) results = [ { "config_name": "Config A", "avg_metrics": { "speed_metrics": {"total_duration": 7200}, }, }, { "config_name": "Config B", "avg_metrics": { "speed_metrics": {"total_duration": 3601}, }, }, ] output = str(tmp_path / "chart.png") _create_metric_comparison_chart( results, ["Config A", "Config B"], ["total_duration"], "speed_metrics", "Duration Test", output, ) assert Path(output).exists() def test_duration_minutes_conversion(self, tmp_path): """Duration > 60 but < 3600 is converted to minutes.""" from local_deep_research.benchmarks.comparison.evaluator import ( _create_metric_comparison_chart, ) results = [ { "config_name": "Config A", "avg_metrics": { "speed_metrics": {"total_duration": 120}, }, }, ] output = str(tmp_path / "chart.png") _create_metric_comparison_chart( results, ["Config A"], ["total_duration"], "speed_metrics", "Duration Test", output, ) assert Path(output).exists() def test_duration_seconds_no_conversion(self, tmp_path): """Duration <= 60 stays in seconds.""" from local_deep_research.benchmarks.comparison.evaluator import ( _create_metric_comparison_chart, ) results = [ { "config_name": "Config A", "avg_metrics": { "speed_metrics": {"total_duration": 30}, }, }, ] output = str(tmp_path / "chart.png") _create_metric_comparison_chart( results, ["Config A"], ["total_duration"], "speed_metrics", "Duration Test", output, ) assert Path(output).exists() # --------------------------------------------------------------------------- # _create_spider_chart: exception fallback (lines 723-736) # --------------------------------------------------------------------------- class TestSpiderChartExceptionFallback: def test_spider_chart_exception_creates_fallback_text(self, tmp_path): """When spider chart creation fails, a text-based fallback is saved.""" from local_deep_research.benchmarks.comparison.evaluator import ( _create_spider_chart, ) results = [ { "config_name": "A", "avg_metrics": {"quality_metrics": {}}, } ] output = str(tmp_path / "spider.png") with patch( f"{MODULE}.np.linspace", side_effect=RuntimeError("radar fail"), ): _create_spider_chart(results, ["A"], output) assert Path(output).exists() # --------------------------------------------------------------------------- # _create_pareto_chart: dominated point detection (lines 783-784) # --------------------------------------------------------------------------- class TestParetoChartDominatedPoints: def test_pareto_with_dominated_points(self, tmp_path): """Points dominated by others are not on the Pareto frontier.""" from local_deep_research.benchmarks.comparison.evaluator import ( _create_pareto_chart, ) results = [ { "config_name": "Fast Low Quality", "avg_metrics": { "quality_metrics": {"overall_quality": 0.3}, "speed_metrics": {"total_duration": 10}, }, }, { "config_name": "Best", "avg_metrics": { "quality_metrics": {"overall_quality": 0.9}, "speed_metrics": {"total_duration": 5}, }, }, { "config_name": "Dominated", "avg_metrics": { "quality_metrics": {"overall_quality": 0.5}, "speed_metrics": {"total_duration": 20}, }, }, ] output = str(tmp_path / "pareto.png") _create_pareto_chart(results, output) assert Path(output).exists() def test_pareto_all_equal(self, tmp_path): """When all points are equal, all are on the frontier.""" from local_deep_research.benchmarks.comparison.evaluator import ( _create_pareto_chart, ) results = [ { "config_name": f"Config {i}", "avg_metrics": { "quality_metrics": {"overall_quality": 0.5}, "speed_metrics": {"total_duration": 10}, }, } for i in range(3) ] output = str(tmp_path / "pareto_equal.png") _create_pareto_chart(results, output) assert Path(output).exists()