tenseleyflow/documentlanguagemodel / b1be33a

Browse files

tests: move sway_json helper tests to tests/unit/export/ so the export coverage gate sees them

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
b1be33aad5a06ff95c1219d79202ccc33b8c5f65
Parents
be573f9
Tree
7e3e7af

2 changed files

StatusFile+-
M tests/unit/cli/test_export_sway_json.py 16 164
C tests/unit/export/test_sway_json.py 0 0
tests/unit/cli/test_export_sway_json.pymodified
@@ -1,185 +1,37 @@
1
-"""Sprint 26 X1 — `dlm export --emit-sway-json` test coverage.
1
+"""Sprint 26 X1 — CLI-flag wiring for `dlm export --emit-sway-json`.
2
-
2
+
3
-Two scopes here, both unit-level:
3
+The helper-module unit tests (``write_sway_json`` round-trip + every
4
-
4
+error path) live at ``tests/unit/export/test_sway_json.py`` so the
5
-1. The helper module (``dlm.export.sway_json.write_sway_json``)
5
+``Coverage gate — src/dlm/export = 100%`` job (which runs only
6
-   round-trips a synthetic ``.dlm`` document into a ``sway.yaml`` on
6
+``tests/unit/export``) sees them. This file owns the CLI-surface
7
-   disk. Stubs the dlm-sway dependency via ``sys.modules`` injection
7
+half: the flag is registered, shows up in ``--help``, and carries
8
-   so the test runs without the real ``[sway]`` extra installed.
8
+the sprint-specified text.
9
-
10
-2. The CLI flag (``--emit-sway-json``) is wired into ``dlm export``
11
-   with the right help text, and the typed
12
-   :class:`SwayJsonExportError` surfaces a clear message when
13
-   dlm-sway isn't installed.
14
-
15
-End-to-end against the real ``dlm-sway`` package (running ``sway run``
16
-on the emitted yaml) lives in the sway repo as
17
-``tests/integration/test_dlm_sway_json_export.py`` once both PRs are
18
-mergeable — see the sprint file's coordination notes.
19
 """
9
 """
20
 
10
 
21
 from __future__ import annotations
11
 from __future__ import annotations
22
 
12
 
23
-import sys
13
+import re
24
-import types
25
-from pathlib import Path
26
-
27
-import pytest
28
-
29
-from dlm.export.sway_json import SwayJsonExportError, write_sway_json
30
-
31
-
32
-def _install_fake_dlm_sway(monkeypatch: pytest.MonkeyPatch) -> None:
33
-    """Inject minimal `dlm_sway.integrations.dlm.{autogen,resolver}`
34
-    modules so write_sway_json runs without the real extra installed.
35
-
36
-    The fakes return shapes the real autogen produces so the helper
37
-    can write a syntactically-valid YAML.
38
-    """
39
-    dlm_sway = types.ModuleType("dlm_sway")
40
-    integrations = types.ModuleType("dlm_sway.integrations")
41
-    integrations_dlm = types.ModuleType("dlm_sway.integrations.dlm")
42
-    autogen = types.ModuleType("dlm_sway.integrations.dlm.autogen")
43
-    resolver = types.ModuleType("dlm_sway.integrations.dlm.resolver")
44
-
45
-    class _FakeHandle:
46
-        dlm_id = "01TEST"
47
-
48
-    def _resolve_dlm(_path: Path) -> _FakeHandle:
49
-        return _FakeHandle()
50
-
51
-    def _build_spec_dict(_handle: _FakeHandle, *, dlm_source: str) -> dict[str, object]:
52
-        return {
53
-            "version": 1,
54
-            "models": {
55
-                "base": {"kind": "hf", "base": "smollm2-135m"},
56
-                "ft": {"kind": "hf", "base": "smollm2-135m"},
57
-            },
58
-            "defaults": {"seed": 0},
59
-            "suite": [
60
-                {"name": "dk", "kind": "delta_kl", "prompts": ["x"]},
61
-            ],
62
-            "dlm_source": dlm_source,
63
-        }
64
-
65
-    resolver.resolve_dlm = _resolve_dlm  # type: ignore[attr-defined]
66
-    autogen.build_spec_dict = _build_spec_dict  # type: ignore[attr-defined]
67
-
68
-    monkeypatch.setitem(sys.modules, "dlm_sway", dlm_sway)
69
-    monkeypatch.setitem(sys.modules, "dlm_sway.integrations", integrations)
70
-    monkeypatch.setitem(sys.modules, "dlm_sway.integrations.dlm", integrations_dlm)
71
-    monkeypatch.setitem(sys.modules, "dlm_sway.integrations.dlm.autogen", autogen)
72
-    monkeypatch.setitem(sys.modules, "dlm_sway.integrations.dlm.resolver", resolver)
73
-
74
-
75
-class TestWriteSwayJson:
76
-    def test_writes_yaml_in_export_dir(
77
-        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
78
-    ) -> None:
79
-        """Helper writes ``<export_dir>/sway.yaml`` and returns the path."""
80
-        _install_fake_dlm_sway(monkeypatch)
81
-        dlm_path = tmp_path / "doc.dlm"
82
-        dlm_path.write_text("---\ndlm_id: 01TEST\n---\nbody\n", encoding="utf-8")
83
-        export_dir = tmp_path / "export"
84
-        export_dir.mkdir()
85
-
86
-        out = write_sway_json(dlm_path, export_dir)
87
 
14
 
88
-        assert out == export_dir / "sway.yaml"
15
+from typer.testing import CliRunner
89
-        assert out.exists()
90
-        # Structural check on the emitted YAML — the test's fake
91
-        # ``build_spec_dict`` returned a delta_kl probe.
92
-        content = out.read_text(encoding="utf-8")
93
-        assert "version: 1" in content
94
-        assert "delta_kl" in content
95
-        assert "dlm_source:" in content
96
 
16
 
97
-    def test_creates_export_dir_if_missing(
17
+from dlm.cli.app import app
98
-        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
99
-    ) -> None:
100
-        """Caller may pass a non-existent export_dir — helper mkdirs."""
101
-        _install_fake_dlm_sway(monkeypatch)
102
-        dlm_path = tmp_path / "doc.dlm"
103
-        dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
104
-        export_dir = tmp_path / "fresh" / "nested" / "export"
105
-        # NOT mkdir'd — helper should create.
106
-
107
-        out = write_sway_json(dlm_path, export_dir)
108
-        assert out.exists()
109
-        assert export_dir.is_dir()
110
-
111
-    def test_dlm_sway_missing_raises_typed_error(
112
-        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
113
-    ) -> None:
114
-        """ImportError on dlm_sway → SwayJsonExportError with install hint."""
115
-        # Wipe any cached dlm_sway modules so the import lookup re-fires.
116
-        for mod in list(sys.modules):
117
-            if mod == "dlm_sway" or mod.startswith("dlm_sway."):
118
-                monkeypatch.delitem(sys.modules, mod, raising=False)
119
-
120
-        # Block the import so the lazy import inside write_sway_json fails.
121
-        import builtins
122
-
123
-        real_import = builtins.__import__
124
-
125
-        def fake_import(name: str, *args: object, **kwargs: object) -> object:
126
-            if name.startswith("dlm_sway"):
127
-                raise ImportError("dlm-sway not installed (test stub)")
128
-            return real_import(name, *args, **kwargs)
129
-
130
-        monkeypatch.setattr(builtins, "__import__", fake_import)
131
-
132
-        dlm_path = tmp_path / "doc.dlm"
133
-        dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
134
-
135
-        with pytest.raises(SwayJsonExportError, match="pip install 'dlm\\[sway\\]'"):
136
-            write_sway_json(dlm_path, tmp_path / "export")
137
-
138
-    def test_autogen_failure_wrapped_in_typed_error(
139
-        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
140
-    ) -> None:
141
-        """A sway-side parse error during build_spec_dict wraps to
142
-        SwayJsonExportError so the dlm CLI sees a familiar exception
143
-        family."""
144
-        # Install a dlm_sway whose build_spec_dict explodes.
145
-        _install_fake_dlm_sway(monkeypatch)
146
-        from dlm_sway.integrations.dlm import (
147
-            autogen as fake_autogen,  # type: ignore[import-not-found]
148
-        )
149
-
150
-        def _raise(*_a: object, **_kw: object) -> dict[str, object]:
151
-            raise RuntimeError("intentional autogen blowup for test")
152
-
153
-        monkeypatch.setattr(fake_autogen, "build_spec_dict", _raise)
154
-
155
-        dlm_path = tmp_path / "doc.dlm"
156
-        dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
157
-        with pytest.raises(SwayJsonExportError, match="intentional autogen blowup"):
158
-            write_sway_json(dlm_path, tmp_path / "export")
159
 
18
 
160
 
19
 
161
 class TestExportCliFlagWiring:
20
 class TestExportCliFlagWiring:
162
-    """The ``--emit-sway-json`` flag is registered on the CLI with the
163
-    sprint-specified help text. Smoke-level — flag presence + help."""
164
-
165
     def test_flag_present_in_export_help(self) -> None:
21
     def test_flag_present_in_export_help(self) -> None:
166
-        from typer.testing import CliRunner
22
+        """``--emit-sway-json`` flag appears in ``dlm export --help``."""
167
-
168
-        from dlm.cli.app import app
169
-
170
         # Force a wide terminal so typer/Rich don't wrap the long
23
         # Force a wide terminal so typer/Rich don't wrap the long
171
         # ``--emit-sway-json`` flag across lines (CI's runner has a
24
         # ``--emit-sway-json`` flag across lines (CI's runner has a
172
         # narrow default that breaks substring asserts).
25
         # narrow default that breaks substring asserts).
173
         runner = CliRunner(env={"COLUMNS": "200", "TERM": "dumb"})
26
         runner = CliRunner(env={"COLUMNS": "200", "TERM": "dumb"})
174
         result = runner.invoke(app, ["export", "--help"])
27
         result = runner.invoke(app, ["export", "--help"])
175
         assert result.exit_code == 0, result.output
28
         assert result.exit_code == 0, result.output
176
-        # Strip any ANSI escapes so a substring match is robust to
177
-        # color codes inserted at arbitrary positions.
178
-        import re
179
 
29
 
30
+        # Strip ANSI escapes + collapse whitespace so substring asserts
31
+        # are robust to color codes and any wrap that COLUMNS=200 still
32
+        # leaves in place.
180
         plain = re.sub(r"\x1b\[[0-9;]*m", "", result.output)
33
         plain = re.sub(r"\x1b\[[0-9;]*m", "", result.output)
181
-        # Collapse whitespace so wrap-induced line breaks within the
182
-        # flag name still match — belt + braces with the COLUMNS env.
183
         plain = re.sub(r"\s+", " ", plain)
34
         plain = re.sub(r"\s+", " ", plain)
35
+
184
         assert "--emit-sway-json" in plain, plain
36
         assert "--emit-sway-json" in plain, plain
185
         assert "sway.yaml" in plain, plain
37
         assert "sway.yaml" in plain, plain
tests/unit/cli/test_export_sway_json.py → tests/unit/export/test_sway_json.pycopied (65% similarity)
@@ -1,21 +1,14 @@
1
-"""Sprint 26 X1 — `dlm export --emit-sway-json` test coverage.
1
+"""Sprint 26 X1 — `dlm.export.sway_json` helper-module unit tests.
2
 
2
 
3
-Two scopes here, both unit-level:
3
+Exists at this path (rather than under ``tests/unit/cli/``) because
4
+CI's ``Coverage gate — src/dlm/export = 100%`` runs ``pytest tests/unit/export``
5
+exclusively. Without these tests in this dir, ``sway_json.py``'s
6
+coverage shows 0% under the gate even though the CLI-side tests
7
+exercise everything.
4
 
8
 
5
-1. The helper module (``dlm.export.sway_json.write_sway_json``)
9
+The CLI-flag-wiring test (``--emit-sway-json`` shows up in
6
-   round-trips a synthetic ``.dlm`` document into a ``sway.yaml`` on
10
+``dlm export --help``) lives at ``tests/unit/cli/test_export_sway_json.py``
7
-   disk. Stubs the dlm-sway dependency via ``sys.modules`` injection
11
+because it touches the CLI surface, not just the helper.
8
-   so the test runs without the real ``[sway]`` extra installed.
9
-
10
-2. The CLI flag (``--emit-sway-json``) is wired into ``dlm export``
11
-   with the right help text, and the typed
12
-   :class:`SwayJsonExportError` surfaces a clear message when
13
-   dlm-sway isn't installed.
14
-
15
-End-to-end against the real ``dlm-sway`` package (running ``sway run``
16
-on the emitted yaml) lives in the sway repo as
17
-``tests/integration/test_dlm_sway_json_export.py`` once both PRs are
18
-mergeable — see the sprint file's coordination notes.
19
 """
12
 """
20
 
13
 
21
 from __future__ import annotations
14
 from __future__ import annotations
@@ -31,10 +24,10 @@ from dlm.export.sway_json import SwayJsonExportError, write_sway_json
31
 
24
 
32
 def _install_fake_dlm_sway(monkeypatch: pytest.MonkeyPatch) -> None:
25
 def _install_fake_dlm_sway(monkeypatch: pytest.MonkeyPatch) -> None:
33
     """Inject minimal `dlm_sway.integrations.dlm.{autogen,resolver}`
26
     """Inject minimal `dlm_sway.integrations.dlm.{autogen,resolver}`
34
-    modules so write_sway_json runs without the real extra installed.
27
+    modules so write_sway_json runs without the real ``[sway]`` extra
35
-
28
+    installed. Mirrors the fakes in ``tests/unit/cli/test_export_sway_json.py``
36
-    The fakes return shapes the real autogen produces so the helper
29
+    so the helper-module surface is exercised independently of the
37
-    can write a syntactically-valid YAML.
30
+    CLI flag wiring test.
38
     """
31
     """
39
     dlm_sway = types.ModuleType("dlm_sway")
32
     dlm_sway = types.ModuleType("dlm_sway")
40
     integrations = types.ModuleType("dlm_sway.integrations")
33
     integrations = types.ModuleType("dlm_sway.integrations")
@@ -72,7 +65,7 @@ def _install_fake_dlm_sway(monkeypatch: pytest.MonkeyPatch) -> None:
72
     monkeypatch.setitem(sys.modules, "dlm_sway.integrations.dlm.resolver", resolver)
65
     monkeypatch.setitem(sys.modules, "dlm_sway.integrations.dlm.resolver", resolver)
73
 
66
 
74
 
67
 
75
-class TestWriteSwayJson:
68
+class TestWriteSwayJsonHelper:
76
     def test_writes_yaml_in_export_dir(
69
     def test_writes_yaml_in_export_dir(
77
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
70
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
78
     ) -> None:
71
     ) -> None:
@@ -87,8 +80,6 @@ class TestWriteSwayJson:
87
 
80
 
88
         assert out == export_dir / "sway.yaml"
81
         assert out == export_dir / "sway.yaml"
89
         assert out.exists()
82
         assert out.exists()
90
-        # Structural check on the emitted YAML — the test's fake
91
-        # ``build_spec_dict`` returned a delta_kl probe.
92
         content = out.read_text(encoding="utf-8")
83
         content = out.read_text(encoding="utf-8")
93
         assert "version: 1" in content
84
         assert "version: 1" in content
94
         assert "delta_kl" in content
85
         assert "delta_kl" in content
@@ -97,12 +88,11 @@ class TestWriteSwayJson:
97
     def test_creates_export_dir_if_missing(
88
     def test_creates_export_dir_if_missing(
98
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
89
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
99
     ) -> None:
90
     ) -> None:
100
-        """Caller may pass a non-existent export_dir — helper mkdirs."""
91
+        """Caller may pass a non-existent export_dir — helper mkdirs it."""
101
         _install_fake_dlm_sway(monkeypatch)
92
         _install_fake_dlm_sway(monkeypatch)
102
         dlm_path = tmp_path / "doc.dlm"
93
         dlm_path = tmp_path / "doc.dlm"
103
         dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
94
         dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
104
         export_dir = tmp_path / "fresh" / "nested" / "export"
95
         export_dir = tmp_path / "fresh" / "nested" / "export"
105
-        # NOT mkdir'd — helper should create.
106
 
96
 
107
         out = write_sway_json(dlm_path, export_dir)
97
         out = write_sway_json(dlm_path, export_dir)
108
         assert out.exists()
98
         assert out.exists()
@@ -112,12 +102,10 @@ class TestWriteSwayJson:
112
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
102
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
113
     ) -> None:
103
     ) -> None:
114
         """ImportError on dlm_sway → SwayJsonExportError with install hint."""
104
         """ImportError on dlm_sway → SwayJsonExportError with install hint."""
115
-        # Wipe any cached dlm_sway modules so the import lookup re-fires.
116
         for mod in list(sys.modules):
105
         for mod in list(sys.modules):
117
             if mod == "dlm_sway" or mod.startswith("dlm_sway."):
106
             if mod == "dlm_sway" or mod.startswith("dlm_sway."):
118
                 monkeypatch.delitem(sys.modules, mod, raising=False)
107
                 monkeypatch.delitem(sys.modules, mod, raising=False)
119
 
108
 
120
-        # Block the import so the lazy import inside write_sway_json fails.
121
         import builtins
109
         import builtins
122
 
110
 
123
         real_import = builtins.__import__
111
         real_import = builtins.__import__
@@ -138,10 +126,9 @@ class TestWriteSwayJson:
138
     def test_autogen_failure_wrapped_in_typed_error(
126
     def test_autogen_failure_wrapped_in_typed_error(
139
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
127
         self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
140
     ) -> None:
128
     ) -> None:
141
-        """A sway-side parse error during build_spec_dict wraps to
129
+        """A sway-side error during build_spec_dict wraps to
142
         SwayJsonExportError so the dlm CLI sees a familiar exception
130
         SwayJsonExportError so the dlm CLI sees a familiar exception
143
         family."""
131
         family."""
144
-        # Install a dlm_sway whose build_spec_dict explodes.
145
         _install_fake_dlm_sway(monkeypatch)
132
         _install_fake_dlm_sway(monkeypatch)
146
         from dlm_sway.integrations.dlm import (
133
         from dlm_sway.integrations.dlm import (
147
             autogen as fake_autogen,  # type: ignore[import-not-found]
134
             autogen as fake_autogen,  # type: ignore[import-not-found]
@@ -156,30 +143,3 @@ class TestWriteSwayJson:
156
         dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
143
         dlm_path.write_text("---\ndlm_id: 01\n---\n", encoding="utf-8")
157
         with pytest.raises(SwayJsonExportError, match="intentional autogen blowup"):
144
         with pytest.raises(SwayJsonExportError, match="intentional autogen blowup"):
158
             write_sway_json(dlm_path, tmp_path / "export")
145
             write_sway_json(dlm_path, tmp_path / "export")
159
-
160
-
161
-class TestExportCliFlagWiring:
162
-    """The ``--emit-sway-json`` flag is registered on the CLI with the
163
-    sprint-specified help text. Smoke-level — flag presence + help."""
164
-
165
-    def test_flag_present_in_export_help(self) -> None:
166
-        from typer.testing import CliRunner
167
-
168
-        from dlm.cli.app import app
169
-
170
-        # Force a wide terminal so typer/Rich don't wrap the long
171
-        # ``--emit-sway-json`` flag across lines (CI's runner has a
172
-        # narrow default that breaks substring asserts).
173
-        runner = CliRunner(env={"COLUMNS": "200", "TERM": "dumb"})
174
-        result = runner.invoke(app, ["export", "--help"])
175
-        assert result.exit_code == 0, result.output
176
-        # Strip any ANSI escapes so a substring match is robust to
177
-        # color codes inserted at arbitrary positions.
178
-        import re
179
-
180
-        plain = re.sub(r"\x1b\[[0-9;]*m", "", result.output)
181
-        # Collapse whitespace so wrap-induced line breaks within the
182
-        # flag name still match — belt + braces with the COLUMNS env.
183
-        plain = re.sub(r"\s+", " ", plain)
184
-        assert "--emit-sway-json" in plain, plain
185
-        assert "sway.yaml" in plain, plain