fix: stop masking runtime failures
This commit is contained in:
@@ -7,7 +7,7 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from nanobot.utils.gitstore import GitStore
|
||||
from nanobot.utils.gitstore import GitStore, GitStoreError
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -63,11 +63,13 @@ class TestLineAges:
|
||||
assert len(ages) == 2
|
||||
assert all(a.age_days == 30 for a in ages)
|
||||
|
||||
def test_annotate_failure_returns_empty(self, tmp_path):
|
||||
"""If annotate fails, line_ages should return [] gracefully."""
|
||||
git = GitStore(tmp_path, tracked_files=["MEMORY.md"])
|
||||
# Don't init — annotate will fail
|
||||
assert git.line_ages("MEMORY.md") == []
|
||||
def test_annotate_failure_is_explicit(self, git, tmp_path):
|
||||
(tmp_path / "MEMORY.md").write_text("important\n", encoding="utf-8")
|
||||
git.auto_commit("initial")
|
||||
|
||||
with patch("dulwich.porcelain.annotate", side_effect=OSError("broken repo")):
|
||||
with pytest.raises(GitStoreError, match="annotation failed"):
|
||||
git.line_ages("MEMORY.md")
|
||||
|
||||
def test_partial_edit_only_updates_changed_lines(self, git, tmp_path):
|
||||
"""Only modified lines should reflect the new commit's timestamp."""
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
from pathlib import Path
|
||||
from zoneinfo import ZoneInfoNotFoundError
|
||||
|
||||
import pytest
|
||||
import tiktoken
|
||||
|
||||
from nanobot.utils import helpers
|
||||
from nanobot.utils.helpers import _write_text_atomic, split_message, truncate_text_to_tokens
|
||||
from nanobot.utils.helpers import (
|
||||
_write_text_atomic,
|
||||
current_time_str,
|
||||
split_message,
|
||||
truncate_text_to_tokens,
|
||||
)
|
||||
|
||||
|
||||
def test_split_message_no_code_blocks_unchanged():
|
||||
@@ -43,6 +50,11 @@ def test_truncate_text_to_tokens_non_positive_budget_returns_text():
|
||||
assert truncate_text_to_tokens(text, 0) == text
|
||||
|
||||
|
||||
def test_current_time_str_rejects_unknown_timezone():
|
||||
with pytest.raises(ZoneInfoNotFoundError):
|
||||
current_time_str("Not/AZone")
|
||||
|
||||
|
||||
def test_write_text_atomic_fsyncs_file_and_parent_directory(
|
||||
tmp_path: Path, monkeypatch
|
||||
) -> None:
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import json
|
||||
|
||||
from nanobot.utils import helpers
|
||||
from nanobot.utils.helpers import estimate_prompt_tokens, estimate_prompt_tokens_chain
|
||||
from nanobot.utils.helpers import (
|
||||
estimate_message_tokens,
|
||||
estimate_prompt_tokens,
|
||||
estimate_prompt_tokens_chain,
|
||||
truncate_text_to_tokens,
|
||||
)
|
||||
|
||||
|
||||
class _NoCounterProvider:
|
||||
@@ -35,6 +40,57 @@ def test_estimate_prompt_tokens_chain_falls_back_when_provider_counter_fails() -
|
||||
assert source == "tiktoken"
|
||||
|
||||
|
||||
def test_estimate_prompt_tokens_uses_conservative_fallback_when_tiktoken_fails(
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
monkeypatch.setattr(
|
||||
helpers,
|
||||
"_get_token_encoding",
|
||||
lambda: (_ for _ in ()).throw(RuntimeError("encoding unavailable")),
|
||||
)
|
||||
|
||||
content = "你" * 1_000
|
||||
messages = [{"role": "user", "content": content}]
|
||||
tokens = estimate_prompt_tokens(messages)
|
||||
chain_tokens, source = estimate_prompt_tokens_chain(
|
||||
_NoCounterProvider(),
|
||||
"test-model",
|
||||
messages,
|
||||
)
|
||||
|
||||
actual_tokens = len(helpers.tiktoken.get_encoding("cl100k_base").encode(content)) + 4
|
||||
assert tokens == len(content.encode("utf-8")) + 4
|
||||
assert tokens >= actual_tokens
|
||||
assert chain_tokens == tokens
|
||||
assert source == "heuristic"
|
||||
|
||||
|
||||
def test_estimate_message_tokens_uses_utf8_byte_fallback(monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
helpers,
|
||||
"_get_token_encoding",
|
||||
lambda: (_ for _ in ()).throw(RuntimeError("encoding unavailable")),
|
||||
)
|
||||
content = "🙂你" * 100
|
||||
|
||||
assert estimate_message_tokens({"role": "user", "content": content}) == (
|
||||
len(content.encode("utf-8")) + 4
|
||||
)
|
||||
|
||||
|
||||
def test_truncate_text_to_tokens_uses_utf8_byte_budget_fallback(monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
helpers,
|
||||
"_get_token_encoding",
|
||||
lambda: (_ for _ in ()).throw(RuntimeError("encoding unavailable")),
|
||||
)
|
||||
|
||||
result = truncate_text_to_tokens("🙂你" * 100, 40)
|
||||
|
||||
assert result.endswith("\n... (truncated)")
|
||||
assert len(result.encode("utf-8")) <= 40
|
||||
|
||||
|
||||
def test_estimate_prompt_tokens_caches_tools_encoding(monkeypatch) -> None:
|
||||
helpers._get_token_encoding.cache_clear()
|
||||
helpers._TOOLS_TOKEN_CACHE.clear()
|
||||
|
||||
Reference in New Issue
Block a user