Files
learningcircuit--local-deep…/tests/benchmarks/test_metrics_calculation_extended.py
T
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

430 lines
14 KiB
Python

"""Extended tests for benchmarks/metrics/calculation.py - covering edge cases
in calculate_metrics and calculate_combined_score."""
import json
import tempfile
import pytest
class TestCalculateMetricsEdgeCases:
"""Tests for calculate_metrics edge cases."""
def test_nonexistent_file_returns_error(self):
"""Non-existent file should return error dict."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
result = calculate_metrics("/nonexistent/path/results.jsonl")
assert "error" in result
def test_empty_file_returns_error(self):
"""Empty file should return error about no results."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write("")
f.flush()
result = calculate_metrics(f.name)
assert result["error"] == "No results found"
def test_malformed_json_lines_returns_error(self):
"""File with malformed JSON should return error."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write("not valid json\n")
f.flush()
result = calculate_metrics(f.name)
assert "error" in result
def test_file_with_only_whitespace_lines(self):
"""File with only whitespace lines should return no results error."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write("\n\n\n")
f.flush()
result = calculate_metrics(f.name)
assert result["error"] == "No results found"
def test_all_correct_results(self):
"""All correct results should give accuracy of 1.0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
for i in range(5):
f.write(
json.dumps({"is_correct": True, "processing_time": 1.0})
+ "\n"
)
f.flush()
result = calculate_metrics(f.name)
assert result["accuracy"] == 1.0
assert result["correct"] == 5
assert result["graded_examples"] == 5
def test_all_incorrect_results(self):
"""All incorrect results should give accuracy of 0.0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
for i in range(3):
f.write(json.dumps({"is_correct": False}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert result["accuracy"] == 0.0
assert result["correct"] == 0
def test_mixed_graded_and_ungraded(self):
"""Mixed graded and ungraded results should only use graded for accuracy."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"is_correct": True}) + "\n")
f.write(json.dumps({"is_correct": False}) + "\n")
f.write(json.dumps({"answer": "no grading"}) + "\n") # Ungraded
f.flush()
result = calculate_metrics(f.name)
assert result["total_examples"] == 3
assert result["graded_examples"] == 2
assert result["accuracy"] == 0.5
def test_results_with_errors(self):
"""Results with errors should be counted in error_rate."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"is_correct": True}) + "\n")
f.write(json.dumps({"error": "timeout"}) + "\n")
f.write(json.dumps({"error": "API error"}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert result["error_count"] == 2
assert result["error_rate"] == pytest.approx(2 / 3)
def test_processing_time_calculation(self):
"""Average processing time should be calculated correctly."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(
json.dumps({"processing_time": 10.0, "is_correct": True}) + "\n"
)
f.write(
json.dumps({"processing_time": 20.0, "is_correct": True}) + "\n"
)
f.write(
json.dumps({"processing_time": 30.0, "is_correct": True}) + "\n"
)
f.flush()
result = calculate_metrics(f.name)
assert result["average_processing_time"] == pytest.approx(20.0)
def test_confidence_parsing(self):
"""Confidence values should be parsed and averaged."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"confidence": "80", "is_correct": True}) + "\n")
f.write(json.dumps({"confidence": "60", "is_correct": True}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert result["average_confidence"] == 70.0
def test_invalid_confidence_values_skipped(self):
"""Invalid confidence values should be skipped."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(
json.dumps({"confidence": "not_a_number", "is_correct": True})
+ "\n"
)
f.write(json.dumps({"confidence": "90", "is_correct": True}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert result["average_confidence"] == 90.0
def test_per_category_metrics(self):
"""Per-category metrics should be calculated correctly."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"is_correct": True, "category": "math"}) + "\n")
f.write(
json.dumps({"is_correct": False, "category": "math"}) + "\n"
)
f.write(
json.dumps({"is_correct": True, "category": "science"}) + "\n"
)
f.flush()
result = calculate_metrics(f.name)
assert "categories" in result
assert result["categories"]["math"]["accuracy"] == 0.5
assert result["categories"]["math"]["total"] == 2
assert result["categories"]["science"]["accuracy"] == 1.0
def test_no_processing_times(self):
"""Results without processing_time should give avg_time of 0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"is_correct": True}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert result["average_processing_time"] == 0
def test_no_graded_results_accuracy_zero(self):
"""Results with no is_correct field should give accuracy 0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"answer": "something"}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert result["accuracy"] == 0
assert result["graded_examples"] == 0
def test_timestamp_included(self):
"""Result should include a timestamp."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_metrics,
)
with tempfile.NamedTemporaryFile(
mode="w", suffix=".jsonl", delete=False
) as f:
f.write(json.dumps({"is_correct": True}) + "\n")
f.flush()
result = calculate_metrics(f.name)
assert "timestamp" in result
assert isinstance(result["timestamp"], str)
class TestCalculateCombinedScoreEdgeCases:
"""Tests for calculate_combined_score edge cases."""
def test_default_weights(self):
"""Default weights should be quality=0.6, speed=0.3, resource=0.1."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_combined_score,
)
metrics = {
"quality": {"quality_score": 1.0},
"speed": {"speed_score": 1.0},
"resource": {"resource_score": 1.0},
}
score = calculate_combined_score(metrics)
assert score == pytest.approx(1.0)
def test_zero_weights_returns_zero(self):
"""All zero weights should return 0.0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_combined_score,
)
metrics = {"quality": {"quality_score": 1.0}}
weights = {"quality": 0.0, "speed": 0.0, "resource": 0.0}
score = calculate_combined_score(metrics, weights)
assert score == 0.0
def test_missing_metric_categories(self):
"""Missing metric categories should be skipped."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_combined_score,
)
metrics = {
"quality": {"quality_score": 0.8},
# No speed or resource
}
score = calculate_combined_score(metrics)
# Only quality contributes: 0.8 * (0.6/1.0) = 0.48
assert score == pytest.approx(0.8 * 0.6)
def test_custom_weights(self):
"""Custom weights should be used instead of defaults."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_combined_score,
)
metrics = {
"quality": {"quality_score": 1.0},
"speed": {"speed_score": 0.5},
}
weights = {"quality": 1.0, "speed": 1.0}
score = calculate_combined_score(metrics, weights)
# Normalized: quality=0.5, speed=0.5
# Score: 1.0*0.5 + 0.5*0.5 = 0.75
assert score == pytest.approx(0.75)
def test_empty_metrics(self):
"""Empty metrics should return 0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_combined_score,
)
score = calculate_combined_score({})
assert score == 0.0
def test_missing_score_keys_in_metrics(self):
"""Missing score keys within metric dicts should default to 0."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_combined_score,
)
metrics = {
"quality": {}, # No quality_score key
"speed": {"speed_score": 0.8},
}
score = calculate_combined_score(metrics)
# quality_score defaults to 0.0, speed_score=0.8
assert score == pytest.approx(0.0 * 0.6 + 0.8 * 0.3)
class TestCalculateResourceMetrics:
"""Tests for calculate_resource_metrics."""
def test_basic_resource_calculation(self):
"""Basic resource metrics with default config."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_resource_metrics,
)
config = {
"iterations": 2,
"questions_per_iteration": 2,
"max_results": 50,
}
result = calculate_resource_metrics(config)
assert "resource_score" in result
assert "estimated_complexity" in result
assert 0 <= result["resource_score"] <= 1
def test_higher_config_means_more_resources(self):
"""Higher config values should give lower resource score (more resources used)."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_resource_metrics,
)
low_config = {
"iterations": 1,
"questions_per_iteration": 1,
"max_results": 10,
}
high_config = {
"iterations": 10,
"questions_per_iteration": 10,
"max_results": 100,
}
low_result = calculate_resource_metrics(low_config)
high_result = calculate_resource_metrics(high_config)
assert low_result["resource_score"] > high_result["resource_score"]
assert (
low_result["estimated_complexity"]
< high_result["estimated_complexity"]
)
def test_default_values_used_when_missing(self):
"""Default values should be used when config keys are missing."""
from local_deep_research.benchmarks.metrics.calculation import (
calculate_resource_metrics,
)
result = calculate_resource_metrics({}) # Empty config
assert "resource_score" in result
assert result["estimated_complexity"] > 0