tenseleyflow/sway / e6b3366

Browse files

tests/style_fingerprint: extended fingerprint fallback + extended=on SKIP path

Authored by espadonne
SHA
e6b3366727692b12136f806a92b3ab3cc67289af
Parents
6f6fd81
Tree
6ef44e0

1 changed file

StatusFile+-
A tests/unit/test_style_fingerprint_extended.py 106 0
tests/unit/test_style_fingerprint_extended.pyadded
@@ -0,0 +1,106 @@
1
+"""Tests for the extended (9-dim) style fingerprint.
2
+
3
+The extended path requires the ``style`` extra (spaCy + textstat).
4
+We don't gate the test on the extra being installed — instead we test
5
+that:
6
+
7
+1. ``extended=False`` always returns 6 dims (backward-compat with the
8
+   v1 fingerprint contract).
9
+2. ``extended=True`` returns 9 dims **when** ``_has_style_extra()`` is
10
+   true; the test patches the extra-detection to simulate both states.
11
+3. The probe's ``extended="on"`` SKIPs cleanly when the extra is
12
+   missing rather than crashing.
13
+"""
14
+
15
+from __future__ import annotations
16
+
17
+from unittest.mock import patch
18
+
19
+import numpy as np
20
+
21
+from dlm_sway.backends.dummy import DummyDifferentialBackend, DummyResponses
22
+from dlm_sway.core.result import Verdict
23
+from dlm_sway.probes.base import RunContext, build_probe
24
+from dlm_sway.probes.style_fingerprint import (
25
+    FINGERPRINT_SCHEMA_VERSION,
26
+    fingerprint,
27
+)
28
+
29
+
30
+def _backend_with_generations(prompts: list[str]) -> DummyDifferentialBackend:
31
+    base = {p: f"base {p} response with several words and a period." for p in prompts}
32
+    ft = {p: f"ft {p} response, longer, with extra punctuation, more words." for p in prompts}
33
+    return DummyDifferentialBackend(
34
+        base=DummyResponses(generations=base),
35
+        ft=DummyResponses(generations=ft),
36
+    )
37
+
38
+
39
+class TestFingerprintFunction:
40
+    def test_default_is_6_dim(self) -> None:
41
+        fp = fingerprint("Hello there. This is a test sentence. Another one follows.")
42
+        assert fp.shape == (6,)
43
+
44
+    def test_empty_text_returns_zeros_at_requested_dim(self) -> None:
45
+        assert fingerprint("", extended=False).shape == (6,)
46
+        assert fingerprint("", extended=True).shape == (9,)
47
+
48
+    def test_extended_falls_back_when_extra_missing(self) -> None:
49
+        with patch("dlm_sway.probes.style_fingerprint._extended_fingerprint", return_value=None):
50
+            fp = fingerprint("Some text. Another sentence.", extended=True)
51
+            assert fp.shape == (6,)
52
+
53
+
54
+class TestProbeExtendedOnRequiresExtra:
55
+    def test_extended_on_skips_without_extra(self) -> None:
56
+        prompts = ["p1"]
57
+        backend = _backend_with_generations(prompts)
58
+        probe, spec = build_probe(
59
+            {
60
+                "name": "sf",
61
+                "kind": "style_fingerprint",
62
+                "prompts": prompts,
63
+                "doc_reference": "The reference document. Has some sentences. Three of them.",
64
+                "extended": "on",
65
+            }
66
+        )
67
+        ctx = RunContext(backend=backend)
68
+        with patch("dlm_sway.probes.style_fingerprint._has_style_extra", return_value=False):
69
+            result = probe.run(spec, ctx)
70
+        assert result.verdict == Verdict.SKIP
71
+        assert "style" in result.message.lower()
72
+
73
+
74
+class TestProbeExtendedAuto:
75
+    def test_auto_off_when_extra_missing(self) -> None:
76
+        prompts = ["p1"]
77
+        backend = _backend_with_generations(prompts)
78
+        probe, spec = build_probe(
79
+            {
80
+                "name": "sf",
81
+                "kind": "style_fingerprint",
82
+                "prompts": prompts,
83
+                "doc_reference": "The reference document. Has some sentences.",
84
+                "extended": "auto",
85
+            }
86
+        )
87
+        ctx = RunContext(backend=backend)
88
+        with patch("dlm_sway.probes.style_fingerprint._has_style_extra", return_value=False):
89
+            result = probe.run(spec, ctx)
90
+        assert result.evidence.get("extended") is False
91
+        assert len(result.evidence["base_fp"]) == 6
92
+        assert result.evidence["schema_version"] == FINGERPRINT_SCHEMA_VERSION
93
+
94
+
95
+class TestExtendedProducesNineDimWhenSimulated:
96
+    def test_extended_path_returns_9_dim(self) -> None:
97
+        """Patch ``_extended_fingerprint`` to return a 9-vector and confirm
98
+        ``fingerprint(..., extended=True)`` passes it through unchanged."""
99
+        nine = np.arange(9, dtype=np.float64) / 9.0
100
+        with patch(
101
+            "dlm_sway.probes.style_fingerprint._extended_fingerprint",
102
+            return_value=nine,
103
+        ):
104
+            fp = fingerprint("Some text. Another sentence.", extended=True)
105
+            assert fp.shape == (9,)
106
+            np.testing.assert_array_equal(fp, nine)