@@ -8,7 +8,14 @@ import pytest |
| 8 | 8 | |
| 9 | 9 | from dlm_sway.core.errors import SpecValidationError |
| 10 | 10 | from dlm_sway.core.result import ProbeResult, Verdict |
| 11 | | -from dlm_sway.probes.base import Probe, ProbeSpec, RunContext, build_probe, registry |
| 11 | +from dlm_sway.probes.base import ( |
| 12 | + Probe, |
| 13 | + ProbeSpec, |
| 14 | + RunContext, |
| 15 | + build_probe, |
| 16 | + registry, |
| 17 | + validate_all_probes, |
| 18 | +) |
| 12 | 19 | |
| 13 | 20 | |
| 14 | 21 | class _DummySpec(ProbeSpec): |
@@ -67,3 +74,35 @@ class TestBuildProbe: |
| 67 | 74 | with pytest.raises(SpecValidationError) as exc_info: |
| 68 | 75 | build_probe({"name": "t", "kind": "__test_dummy", "bogus": "y"}) |
| 69 | 76 | assert "bogus" in str(exc_info.value).lower() |
| 77 | + |
| 78 | + |
| 79 | +class TestValidateAllProbes: |
| 80 | + """B7: collect every probe-entry error in a single message.""" |
| 81 | + |
| 82 | + def test_clean_suite_passes(self) -> None: |
| 83 | + validate_all_probes( |
| 84 | + [ |
| 85 | + {"name": "p1", "kind": "__test_dummy"}, |
| 86 | + {"name": "p2", "kind": "__test_dummy", "payload": "y"}, |
| 87 | + ] |
| 88 | + ) |
| 89 | + |
| 90 | + def test_collects_multiple_errors(self) -> None: |
| 91 | + with pytest.raises(SpecValidationError) as exc_info: |
| 92 | + validate_all_probes( |
| 93 | + [ |
| 94 | + {"name": "good", "kind": "__test_dummy"}, |
| 95 | + {"name": "typo1", "kind": "no_such_kind"}, |
| 96 | + {"name": "typo2", "kind": "another_typo"}, |
| 97 | + ] |
| 98 | + ) |
| 99 | + msg = str(exc_info.value) |
| 100 | + # Both typos surface in one message — the user fixes everything in one pass. |
| 101 | + assert "typo1" in msg |
| 102 | + assert "typo2" in msg |
| 103 | + assert "no_such_kind" in msg |
| 104 | + assert "another_typo" in msg |
| 105 | + |
| 106 | + def test_unnamed_entry_uses_index_label(self) -> None: |
| 107 | + with pytest.raises(SpecValidationError, match="entry #0"): |
| 108 | + validate_all_probes([{"kind": "no_such_kind"}]) |