from __future__ import annotations import json import subprocess import sys from pathlib import Path import pytest from sim.granovetter import cascade, prediction_hit, run_experiments @pytest.mark.parametrize(("thresholds", "final"), [ ([0, 0, 5], 2), ([1, 1], 0), ([0.5], 0), ([0, 0.5], 2), ([0, 1, 2], 3), ([0, 2, 2], 1), ]) def test_small_examples(thresholds, final): assert cascade(thresholds)["final"] == final def test_round_outputs_are_simultaneous_and_one_based(): assert cascade([0, 0.5, 3]) == { "final": 2, "rounds": 2, "series": [1, 2], "stand_round": [1, 2, 0] } @pytest.fixture(scope="module") def summary(): return run_experiments() def test_e1_e2_e3(summary): assert summary["ladder"]["final"] == 100 assert summary["swap"]["final"] == 1 assert summary["swap_k"]["all_equal_k"] is True assert summary["swap_k"]["final"] == list(range(100)) def test_e4_paper_check(summary): assert 12.1 <= summary["expected"]["sigma_c"] <= 12.4 assert 4 <= summary["expected"]["re_below"] <= 8 def stable_json(path: Path): value = json.loads(path.read_text(encoding="utf-8")) value.pop("generated_at", None) value.pop("runtime_s", None) return json.dumps(value, ensure_ascii=False, sort_keys=True, indent=1) + "\n" def test_cli_is_deterministic_except_declared_fields(tmp_path): script = Path(__file__).parents[1] / "sim" / "granovetter.py" first, second = tmp_path / "first", tmp_path / "second" for out in (first, second): subprocess.run([sys.executable, str(script), "--out", str(out)], check=True) assert stable_json(first / "summary.json") == stable_json(second / "summary.json") assert (first / "predictions_check.json").read_bytes() == (second / "predictions_check.json").read_bytes() @pytest.mark.parametrize(("prediction", "yes", "no"), [ ({"kind": "eq", "value": 3}, 3, 2), ({"kind": "bool", "value": True}, True, False), ({"kind": "range", "lo": 2, "hi": 4}, 4, 5), ({"kind": "max", "hi": 4}, 4, 5), ({"kind": "min", "lo": 2}, 2, 1), ({"kind": "in", "values": [2, 4]}, 4, 3), ]) def test_prediction_kinds_positive_and_negative(prediction, yes, no): assert prediction_hit(prediction, yes) is True assert prediction_hit(prediction, no) is False assert prediction_hit(prediction, None) is False