Viewing files at commit 369435870869Commit detailsView latest

Browse files
tests/test_calibration.py 94 lines · 3.7 KB · python
1
"""Tests for the token-estimate calibration classifier."""
2
3
from __future__ import annotations
4
5
import sys
6
from pathlib import Path
7
8
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
9
10
import unittest
11
12
import token_calibration
13
14
15
class CompositionTest(unittest.TestCase):
16
    def test_classes_partition_the_text(self) -> None:
17
        text = "commit 4f2a9c8be1d34f7a line 42, words here!\n"
18
        counts = token_calibration.classify_chars(text)
19
        self.assertEqual(sum(counts.values()), len(text))
20
21
    def test_hex_runs_detected(self) -> None:
22
        counts = token_calibration.classify_chars("deadbeefcafe1234")
23
        self.assertEqual(counts["hex_run"], 16)
24
25
26
class BiasDirectionTest(unittest.TestCase):
27
    """Pins the HEURISTIC path: optional enhancers (tiktoken, ADR-0001) must
28
    not flip test behavior depending on what happens to be installed, so
29
    exact_tokens is forced off. Direction claims under a real tokenizer are
30
    asserted separately in TokenizerBiasDirectionTest."""
31
32
    def factor(self, sample_name: str) -> float:
33
        text = token_calibration.SELF_TEST_SAMPLES[sample_name]
34
        original = token_calibration.exact_tokens
35
        token_calibration.exact_tokens = lambda _text: (None, None)
36
        try:
37
            result = token_calibration.analyze_text(sample_name, text)
38
        finally:
39
            token_calibration.exact_tokens = original
40
        return result["calibration_factor_vs_char_div_4"]
41
42
    def test_hash_heavy_underestimated_by_char_div_4(self) -> None:
43
        # factor > 1 means char/4 UNDERESTIMATES; hash-heavy log output is the
44
        # worst case and the reason cross-subject token deltas need calibration.
45
        self.assertGreater(self.factor("hash_heavy_log"), 1.3)
46
47
    def test_prose_close_to_char_div_4(self) -> None:
48
        self.assertLess(self.factor("prose_readme"), 1.0)
49
        self.assertGreater(self.factor("prose_readme"), 0.8)
50
51
    def test_diff_between_the_two(self) -> None:
52
        self.assertGreater(self.factor("git_diff_like"), 1.0)
53
        self.assertLess(self.factor("git_diff_like"), self.factor("hash_heavy_log"))
54
55
56
class TokenizerBiasDirectionTest(unittest.TestCase):
57
    """Direction-only claims when a real tokenizer is present; skipped
58
    otherwise. Bounds are loose on purpose — exact values are calibration
59
    output, not test fixtures."""
60
61
    def setUp(self) -> None:
62
        exact, _ = token_calibration.exact_tokens("probe")
63
        if exact is None:
64
            self.skipTest("tiktoken not installed")
65
66
    def factor(self, sample_name: str) -> float:
67
        text = token_calibration.SELF_TEST_SAMPLES[sample_name]
68
        return token_calibration.analyze_text(sample_name, text)["calibration_factor_vs_char_div_4"]
69
70
    def test_hash_heavy_still_underestimated(self) -> None:
71
        self.assertGreater(self.factor("hash_heavy_log"), 1.0)
72
73
    def test_prose_not_underestimated(self) -> None:
74
        self.assertLess(self.factor("prose_readme"), 1.0)
75
76
    def test_ordering_preserved(self) -> None:
77
        self.assertLess(self.factor("prose_readme"), self.factor("git_diff_like"))
78
        self.assertLess(self.factor("git_diff_like"), self.factor("hash_heavy_log"))
79
80
81
class AggregateTest(unittest.TestCase):
82
    def test_aggregate_reports_method_honestly(self) -> None:
83
        results = [
84
            token_calibration.analyze_text(name, text)
85
            for name, text in token_calibration.SELF_TEST_SAMPLES.items()
86
        ]
87
        aggregate = token_calibration.aggregate(results, label="self-test")
88
        self.assertEqual(aggregate["samples"], 3)
89
        self.assertIn(aggregate["method"], {"exact_tokenizer", "mixed", "composition_heuristic"})
90
        self.assertIsNotNone(aggregate["calibration_factor_vs_char_div_4"])
91
92
93
if __name__ == "__main__":
94
    unittest.main()