"""Tests for the validation harness (dee.core.benchmark) — the receipts engine. Predictions are injected, so we can assert the exact correlation / precision behaviour without ESM. These pin the numbers we'd publish as our benchmark. """ import numpy as np import pytest import pandas as pd from dee.core.benchmark import ( DatasetResult, evaluate_dataset, predict_additive, spearman, summarize, top_decile_precision, ) def _fake_scores_df(): # position 0-indexed: pos 0 A->C = 1.0, pos 4 D->E = 0.5 return pd.DataFrame([ {"position": 0, "wt_aa": "A", "mut_aa": "C", "delta_ll": 1.0}, {"position": 4, "wt_aa": "D", "mut_aa": "E", "delta_ll": 0.5}, {"position": 4, "wt_aa": "D", "mut_aa": "G", "delta_ll": -0.3}, ]) def test_predict_additive_single_and_multi_site(): df = _fake_scores_df() preds = predict_additive(df, ["A1C", "A1C:D5E", "A1C,D5E"]) assert preds[0] == pytest.approx(1.0) assert preds[1] == pytest.approx(1.5) # colon-separated multi-site sums assert preds[2] == pytest.approx(1.5) # comma-separated too def test_predict_additive_nan_for_unscorable_label(): df = _fake_scores_df() preds = predict_additive(df, ["Z9Q", "A1C:Z9Q", "not-a-label"]) assert all(np.isnan(p) for p in preds) def test_spearman_perfect_and_anti(): a = list(range(20)) assert spearman(a, a) == pytest.approx(1.0) assert spearman(a, list(reversed(a))) == pytest.approx(-1.0) def test_spearman_monotonic_nonlinear_is_one(): a = list(range(1, 11)) b = [x ** 3 for x in a] # monotonic → rank corr = 1 even if nonlinear assert spearman(a, b) == pytest.approx(1.0) def test_spearman_handles_ties(): a = [1, 1, 2, 2, 3, 3] b = [1, 1, 2, 2, 3, 3] assert spearman(a, b) == pytest.approx(1.0) def test_spearman_none_when_degenerate(): assert spearman([1, 2], [3, 4]) is None # < 3 points assert spearman([5, 5, 5, 5], [1, 2, 3, 4]) is None # no variance in a def test_top_decile_precision_perfect_alignment(): rng = np.random.default_rng(0) measured = rng.normal(size=100) predicted = measured.copy() # perfect ranking # top 10% predicted are exactly the top 10% measured, all within top 25%. assert top_decile_precision(predicted, measured) == pytest.approx(1.0) def test_top_decile_precision_anti_alignment_is_low(): measured = np.linspace(0, 1, 100) predicted = -measured # worst possible ranking assert top_decile_precision(predicted, measured) == pytest.approx(0.0) def test_top_decile_precision_none_when_too_small(): assert top_decile_precision([1, 2, 3], [3, 2, 1]) is None def test_evaluate_dataset_and_summarize(): rng = np.random.default_rng(1) m1 = rng.normal(size=60) p1 = m1 + rng.normal(scale=0.3, size=60) # good but noisy predictor m2 = rng.normal(size=40) p2 = -m2 # a hard/anti assay r1 = evaluate_dataset("assayA", "P1", p1, m1, source="doi:1") r2 = evaluate_dataset("assayB", "P2", p2, m2, source="doi:2") assert r1.spearman > 0.6 assert r2.spearman < 0 s = summarize([r1, r2]) assert s["n_datasets"] == 2 assert s["n_variants"] == 100 assert s["median_spearman"] is not None # as_dict rounds + is JSON-safe d = r1.as_dict() assert set(d) == {"name", "protein", "n", "spearman", "top_decile_precision", "source"} def test_summarize_empty(): s = summarize([]) assert s == {"n_datasets": 0, "n_variants": 0, "median_spearman": None, "median_top_decile_precision": None} def test_benchmarks_route_public_and_shaped(): from dee import server app = server.create_app() app.config.update(TESTING=True) body = app.test_client().get("/api/benchmarks").get_json() # no auth — public assert body["ok"] is True assert "summary" in body and "datasets" in body assert set(body["summary"]) == {"n_datasets", "n_variants", "median_spearman", "median_top_decile_precision"} # n_datasets/datasets length must agree, whatever the current bundled state is # (empty before the first real run, or real numbers once /api/admin/run- # benchmarks has populated it — this route never fabricates either way). assert body["summary"]["n_datasets"] == len(body["datasets"]) def test_benchmarks_route_honest_empty_when_file_absent(monkeypatch, tmp_path): from dee import server monkeypatch.setattr(server, "__file__", str(tmp_path / "server.py")) app = server.create_app() app.config.update(TESTING=True) body = app.test_client().get("/api/benchmarks").get_json() assert body["ok"] is True assert body["summary"]["n_datasets"] == 0 assert body["datasets"] == [] assert body["generated_at"] is None