Coverage for tests / unit / ai / test_token_budget.py: 100%
37 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Tests for token budget estimation and truncation utilities."""
3from __future__ import annotations
5import pytest
6from assertpy import assert_that
8from lintro.ai.token_budget import estimate_tokens, truncate_to_budget
10# -- estimate_tokens ---------------------------------------------------------
13def test_empty_string_returns_zero() -> None:
14 """An empty string produces 0 tokens."""
15 assert_that(estimate_tokens("")).is_equal_to(0)
18def test_short_string_returns_at_least_one() -> None:
19 """A non-empty string shorter than 4 chars still returns 1."""
20 assert_that(estimate_tokens("hi")).is_equal_to(1)
23def test_four_chars_equals_one_token() -> None:
24 """4 characters maps to exactly 1 token."""
25 assert_that(estimate_tokens("abcd")).is_equal_to(1)
28def test_eight_chars_equals_two_tokens() -> None:
29 """8 characters maps to 2 tokens."""
30 assert_that(estimate_tokens("abcdefgh")).is_equal_to(2)
33# -- truncate_to_budget ------------------------------------------------------
36def test_no_truncation_when_under_budget() -> None:
37 """Text under the budget is returned as-is with truncated=False."""
38 text = "hello"
39 result, truncated = truncate_to_budget(text, max_tokens=100)
40 assert_that(result).is_equal_to(text)
41 assert_that(truncated).is_false()
44def test_truncation_sets_flag() -> None:
45 """Text over budget returns truncated=True."""
46 text = "a" * 100
47 result, truncated = truncate_to_budget(text, max_tokens=5)
48 assert_that(truncated).is_true()
49 assert_that(len(result)).is_less_than(len(text))
52def test_truncation_cuts_at_newline() -> None:
53 """Truncation prefers cutting at a newline boundary."""
54 text = "line1\nline2\nline3\nline4\nline5\n"
55 result, truncated = truncate_to_budget(text, max_tokens=3)
56 # max_tokens=3 -> max_chars=12 -> cuts at newline boundary
57 assert_that(truncated).is_true()
58 assert_that(result).contains("\n")
59 # Result should not contain later lines
60 assert_that(result).does_not_contain("line3")
61 assert_that(result).does_not_contain("line4")
64def test_empty_string_no_truncation() -> None:
65 """An empty string is never truncated."""
66 result, truncated = truncate_to_budget("", max_tokens=10)
67 assert_that(result).is_equal_to("")
68 assert_that(truncated).is_false()
71@pytest.mark.parametrize("max_tokens", [0, -1, -5])
72def test_truncate_raises_on_non_positive_max_tokens(max_tokens: int) -> None:
73 """truncate_to_budget raises ValueError for non-positive max_tokens."""
74 with pytest.raises(ValueError, match="max_tokens must be positive"):
75 truncate_to_budget("some text", max_tokens=max_tokens)