@@ -123,6 +123,38 @@ class TestDoctorJson: |
| 123 | 123 | assert "httpx" in payload["extras"]["api"] |
| 124 | 124 | assert "tenacity" in payload["extras"]["api"] |
| 125 | 125 | |
| 126 | + def test_json_schema_is_snapshot_stable(self) -> None: |
| 127 | + """Stronger-test #11 — pin ``sway doctor --json``'s *shape* |
| 128 | + (top-level keys + extras bucket keys + their contents as sets of |
| 129 | + module names). Values (``sway_version``, ``python``, ``platform``, |
| 130 | + installed vs missing) vary by host and are masked so the snapshot |
| 131 | + catches structural drift without being environment-sensitive.""" |
| 132 | + result = CliRunner().invoke(app, ["doctor", "--json"]) |
| 133 | + assert result.exit_code == 0 |
| 134 | + payload = json.loads(result.stdout) |
| 135 | + |
| 136 | + assert set(payload) == {"sway_version", "python", "platform", "extras"} |
| 137 | + # Every extra bucket's keys are stable; values (module versions) |
| 138 | + # are not. Snapshot the sorted module-name set per bucket. |
| 139 | + extras = payload["extras"] |
| 140 | + assert isinstance(extras, dict) |
| 141 | + extras_shape = {bucket: sorted(extras[bucket]) for bucket in sorted(extras)} |
| 142 | + assert extras_shape == { |
| 143 | + "api": ["httpx", "tenacity"], |
| 144 | + "dlm": ["dlm"], |
| 145 | + "hf": ["peft", "torch", "transformers"], |
| 146 | + "mlx": ["mlx", "mlx_lm"], |
| 147 | + "pytest": ["pytest"], |
| 148 | + "semsim": ["sentence_transformers", "sklearn"], |
| 149 | + "style": ["nlpaug", "spacy", "textstat"], |
| 150 | + "viz": ["matplotlib", "plotly"], |
| 151 | + } |
| 152 | + # Value type is str-or-None on every module entry. |
| 153 | + for bucket_name, bucket in extras.items(): |
| 154 | + for mod_name, version in bucket.items(): |
| 155 | + assert isinstance(mod_name, str), bucket_name |
| 156 | + assert version is None or isinstance(version, str), (bucket_name, mod_name) |
| 157 | + |
| 126 | 158 | |
| 127 | 159 | class TestListProbes: |
| 128 | 160 | """D6: ``sway list-probes`` prints the registered kinds.""" |