"""Tests for transcript parser."""
import json
from datetime import datetime, timezone
from pathlib import Path
import pytest
from ccsession.parsers.transcript import (
TranscriptParser,
TokenUsage,
ContextBudget,
DEFAULT_CONTEXT_LIMIT,
)
def test_token_usage_total():
"""Test TokenUsage.total calculation."""
usage = TokenUsage(
input_tokens=1000,
output_tokens=500,
cache_creation_input_tokens=2000,
cache_read_input_tokens=3000,
)
assert usage.total == 6500
def test_token_usage_defaults():
"""Test TokenUsage defaults to zero."""
usage = TokenUsage()
assert usage.total == 0
def test_context_budget_status():
"""Test ContextBudget status thresholds."""
# Sufficient
budget = ContextBudget(50000, 106000, 32.0, 156000, "sufficient")
assert budget.status == "sufficient"
assert budget.percentage_used < 60
# Low
budget_low = ContextBudget(100000, 56000, 64.1, 156000, "low")
assert budget_low.status == "low"
# Critical
budget_critical = ContextBudget(130000, 26000, 83.3, 156000, "critical")
assert budget_critical.status == "critical"
def test_transcript_parser_get_latest_usage(sample_transcript_path):
"""Test getting latest token usage from transcript."""
parser = TranscriptParser(transcript_path=sample_transcript_path)
usage = parser.get_latest_usage()
# Last message has: input=3500, output=100, cache_read=5000
assert usage.input_tokens == 3500
assert usage.output_tokens == 100
assert usage.cache_read_input_tokens == 5000
assert usage.total == 8600
def test_transcript_parser_get_context_budget(sample_transcript_path):
"""Test context budget calculation."""
parser = TranscriptParser(transcript_path=sample_transcript_path)
budget = parser.get_context_budget(context_limit=20000)
assert budget.tokens_used == 8600
assert budget.tokens_remaining == 11400
assert budget.context_limit == 20000
assert 40 < budget.percentage_used < 45
def test_transcript_parser_get_session_start_time(sample_transcript_path):
"""Test extracting session start time."""
parser = TranscriptParser(transcript_path=sample_transcript_path)
start_time = parser.get_session_start_time()
assert start_time is not None
assert start_time.year == 2025
assert start_time.month == 12
assert start_time.day == 3
def test_transcript_parser_get_files_modified(sample_transcript_path):
"""Test extracting modified files from transcript."""
parser = TranscriptParser(transcript_path=sample_transcript_path)
files = parser.get_files_modified()
assert "/tmp/test.py" in files["created"]
assert "/tmp/test.py" in files["edited"]
assert len(files["deleted"]) == 0
def test_transcript_parser_get_agents_spawned(sample_transcript_path):
"""Test extracting spawned agents from transcript."""
parser = TranscriptParser(transcript_path=sample_transcript_path)
agents = parser.get_agents_spawned()
assert "Explore" in agents
def test_transcript_parser_get_tool_calls(sample_transcript_path):
"""Test extracting tool calls from transcript."""
parser = TranscriptParser(transcript_path=sample_transcript_path)
tool_calls = parser.get_tool_calls()
tool_names = [tc["name"] for tc in tool_calls]
assert "Write" in tool_names
assert "Edit" in tool_names
assert "Task" in tool_names
assert "Bash" in tool_names
def test_transcript_parser_no_transcript():
"""Test behavior when no transcript is found."""
parser = TranscriptParser(transcript_path="/nonexistent/file.jsonl")
usage = parser.get_latest_usage()
assert usage.total == 0
def test_transcript_parser_empty_file(tmp_path):
"""Test handling of empty transcript file."""
empty_transcript = tmp_path / "empty.jsonl"
empty_transcript.touch()
parser = TranscriptParser(transcript_path=empty_transcript)
usage = parser.get_latest_usage()
assert usage.total == 0
def test_transcript_parser_invalid_json(tmp_path):
"""Test handling of invalid JSON in transcript."""
bad_transcript = tmp_path / "bad.jsonl"
bad_transcript.write_text("not valid json\n{also bad}")
parser = TranscriptParser(transcript_path=bad_transcript)
usage = parser.get_latest_usage()
assert usage.total == 0