Viewing files at commit ef78687eef1aCommit detailsView latest

Browse files
tests/test_subject_kinds.py 97 lines · 3.9 KB · python
1
"""Subject-kind plugin layer: schema, capability gaps, and the parity proof.
2
3
The load-bearing assertion is parity_report == [] for git and oak: the
4
plugin JSONs are a parallel read of config/command_semantics.json, and an
5
empty report proves the extraction is measurement-identical, so existing
6
lanes' behavior cannot have changed.
7
"""
8
9
from __future__ import annotations
10
11
import sys
12
import unittest
13
from pathlib import Path
14
15
ROOT = Path(__file__).resolve().parents[1]
16
sys.path.insert(0, str(ROOT / "scripts"))
17
18
from oakbench.subject_kinds import (
19
    SCHEMA_VERSION,
20
    available_kinds,
21
    command_for,
22
    load_subject_kind,
23
    parity_report,
24
)
25
26
27
class ParityProofTest(unittest.TestCase):
28
    """The row_parity proof for the config layer (empty = identical)."""
29
30
    def test_git_plugin_is_measurement_identical_to_command_semantics(self) -> None:
31
        self.assertEqual(parity_report("git", ROOT / "config" / "command_semantics.json"), [])
32
33
    def test_oak_plugin_is_measurement_identical_to_command_semantics(self) -> None:
34
        self.assertEqual(parity_report("oak", ROOT / "config" / "command_semantics.json"), [])
35
36
    def test_jj_is_honestly_absent_from_command_semantics(self) -> None:
37
        report = parity_report("jj", ROOT / "config" / "command_semantics.json")
38
        self.assertEqual(len(report), 1)
39
        self.assertIn("kind_not_in_command_semantics:jj", report[0])
40
41
42
class SchemaTest(unittest.TestCase):
43
    def test_all_shipped_plugins_load_and_validate(self) -> None:
44
        kinds = available_kinds()
45
        self.assertEqual(kinds, ["git", "jj", "oak"])
46
        for kind in kinds:
47
            plugin = load_subject_kind(kind)
48
            self.assertEqual(plugin.kind, kind)
49
            self.assertEqual(plugin.schema_version, SCHEMA_VERSION)
50
            self.assertIsInstance(plugin.workspace_model, str)
51
            self.assertIn("stage_required", plugin.snapshot_call_semantics)
52
            self.assertIn("calls_per_snapshot", plugin.snapshot_call_semantics)
53
54
    def test_workspace_models_match_declarations(self) -> None:
55
        self.assertEqual(load_subject_kind("git").workspace_model, "working_copy")
56
        self.assertEqual(load_subject_kind("oak").workspace_model, "virtual_branch")
57
        self.assertEqual(load_subject_kind("jj").workspace_model, "working_copy_autosnapshot")
58
59
    def test_remote_env_vars_match_harness(self) -> None:
60
        self.assertEqual(load_subject_kind("git").remote_env_var, "GIT_BENCH_REMOTE")
61
        self.assertEqual(load_subject_kind("oak").remote_env_var, "OAK_BENCH_REMOTE")
62
        self.assertIsNone(load_subject_kind("jj").remote_env_var)
63
64
65
class CapabilityGapTest(unittest.TestCase):
66
    def test_jj_status_has_argv(self) -> None:
67
        self.assertEqual(command_for("jj", "status"), ["st"])
68
69
    def test_jj_absent_operation_is_capability_gap(self) -> None:
70
        self.assertIsNone(command_for("jj", "rebase.interactive"))
71
72
    def test_jj_explicit_null_is_capability_gap(self) -> None:
73
        plugin = load_subject_kind("jj")
74
        self.assertIsNone(plugin.command_for("stage"))
75
        self.assertIsNone(plugin.command_for("branch_create"))
76
        self.assertEqual(plugin.skip_reason("stage"), "capability_gap:jj:stage")
77
78
    def test_track_selection(self) -> None:
79
        self.assertEqual(command_for("git", "status", track="core-equivalent"), ["status", "--porcelain=v1"])
80
        self.assertIsNone(command_for("jj", "status", track="core-equivalent"))
81
82
    def test_oak_stage_gap_matches_command_semantics(self) -> None:
83
        self.assertIsNone(command_for("oak", "stage"))
84
85
86
class UnknownKindTest(unittest.TestCase):
87
    def test_unknown_kind_raises_clear_error(self) -> None:
88
        with self.assertRaises(ValueError) as ctx:
89
            load_subject_kind("sapling")
90
        message = str(ctx.exception)
91
        self.assertIn("sapling", message)
92
        self.assertIn("available", message)
93
        self.assertIn("git", message)
94
95
96
if __name__ == "__main__":
97
    unittest.main()