"""tests/unit/test_validate.py — 块验证纯决策函数的单元测试。"""

import pytest

from core.evolution.validate import classify_quadrants, compute_accuracy, pair_block


class TestPairBlock:
    """pair_block 逐题比对基线与候选的翻转统计测试。"""

    def test_basic_flips(self) -> None:
        """基本翻转：一题从错到对(w)、一题从对到错(l)、一题不变。"""
        baseline = {"q1": False, "q2": True, "q3": True}
        candidate = {"q1": True, "q2": False, "q3": True}
        result = pair_block(baseline, candidate, ["q1", "q2", "q3"])
        assert result.w == 1
        assert result.l == 1
        assert result.observed == {
            "q1": (False, True),
            "q2": (True, False),
            "q3": (True, True),
        }

    def test_empty(self) -> None:
        """空输入应返回零翻转。"""
        result = pair_block({}, {}, [])
        assert result.w == 0 and result.l == 0

    def test_all_wins(self) -> None:
        """全部从错到对的极端情况。"""
        baseline = {"q1": False, "q2": False}
        candidate = {"q1": True, "q2": True}
        result = pair_block(baseline, candidate, ["q1", "q2"])
        assert result.w == 2
        assert result.l == 0

    def test_all_losses(self) -> None:
        """全部从对到错的极端情况。"""
        baseline = {"q1": True, "q2": True}
        candidate = {"q1": False, "q2": False}
        result = pair_block(baseline, candidate, ["q1", "q2"])
        assert result.w == 0
        assert result.l == 2

    def test_subset_of_questions(self) -> None:
        """只对 question_ids 中指定的子集进行比对。"""
        baseline = {"q1": False, "q2": True, "q3": True}
        candidate = {"q1": True, "q2": False, "q3": True}
        result = pair_block(baseline, candidate, ["q1"])
        assert result.w == 1
        assert result.l == 0
        assert "q2" not in result.observed


class TestClassifyQuadrants:
    """classify_quadrants 四象限分类测试。"""

    def test_all_four(self) -> None:
        """四个象限各有一题。"""
        observed = {
            "q1": (False, True),
            "q2": (True, False),
            "q3": (False, False),
            "q4": (True, True),
        }
        qc = classify_quadrants(observed)
        assert qc.improvements == ["q1"]
        assert qc.regressions == ["q2"]
        assert qc.persistent_fails == ["q3"]
        assert qc.stable_successes == ["q4"]

    def test_sorted_within_quadrant(self) -> None:
        """同象限内题目 ID 应按字典序排列。"""
        observed = {"z": (False, True), "a": (False, True)}
        qc = classify_quadrants(observed)
        assert qc.improvements == ["a", "z"]

    def test_empty_observed(self) -> None:
        """空输入应返回全空象限。"""
        qc = classify_quadrants({})
        assert qc.improvements == []
        assert qc.regressions == []
        assert qc.persistent_fails == []
        assert qc.stable_successes == []


class TestComputeAccuracy:
    """compute_accuracy 准确率计算测试。"""

    def test_basic(self) -> None:
        """一对一错，准确率 0.5。"""
        assert compute_accuracy({"q1": True, "q2": False}, ["q1", "q2"]) == 0.5

    def test_all_correct(self) -> None:
        """全部正确，准确率 1.0。"""
        assert compute_accuracy({"q1": True, "q2": True}, ["q1", "q2"]) == 1.0

    def test_all_wrong(self) -> None:
        """全部错误，准确率 0.0。"""
        assert compute_accuracy({"q1": False, "q2": False}, ["q1", "q2"]) == 0.0

    def test_empty_raises(self) -> None:
        """空题目列表应抛出 ZeroDivisionError。"""
        with pytest.raises(ZeroDivisionError):
            compute_accuracy({}, [])
