prompt-prix / tests /test_export.py
3v324v23's picture
Fix #31, #32, #34, #35, #36: Battery/Compare tab bug fixes
65d9078
"""Tests for prompt_prix.export module."""
import json
import pytest
from pathlib import Path
from unittest.mock import patch
from datetime import datetime
class TestGenerateMarkdownReport:
"""Tests for generate_markdown_report function."""
def test_generate_markdown_report_basic(self, sample_session_state):
"""Test generating a basic markdown report."""
from prompt_prix.export import generate_markdown_report
report = generate_markdown_report(sample_session_state)
# Check header
assert "# LLM Comparison Report" in report
assert "**Generated:**" in report
assert "**Models:**" in report
assert "**Temperature:** 0.7" in report
# Check model sections
assert "## Model: llama-3.2-3b-instruct" in report
assert "## Model: qwen2.5-7b-instruct" in report
# Check conversation content
assert "### User" in report
assert "What is the capital of France?" in report
assert "### Assistant" in report
assert "The capital of France is Paris." in report
def test_generate_markdown_report_with_error(self, sample_session_state):
"""Test markdown report includes model errors."""
from prompt_prix.export import generate_markdown_report
# Add error to one model
sample_session_state.contexts["llama-3.2-3b-instruct"].error = "Connection timeout"
report = generate_markdown_report(sample_session_state)
assert "**Error:** Connection timeout" in report
def test_generate_markdown_report_halted_session(self, halted_session_state):
"""Test markdown report shows halted status."""
from prompt_prix.export import generate_markdown_report
report = generate_markdown_report(halted_session_state)
assert "**Session Halted:**" in report
assert "Connection timeout" in report
def test_generate_markdown_report_includes_system_prompt(self, sample_session_state):
"""Test markdown report includes system prompt."""
from prompt_prix.export import generate_markdown_report
report = generate_markdown_report(sample_session_state)
assert "## System Prompt" in report
assert "You are a helpful assistant." in report
def test_generate_markdown_report_empty_contexts(self):
"""Test markdown report with no messages."""
from prompt_prix.config import SessionState
from prompt_prix.export import generate_markdown_report
state = SessionState(models=["model-a"])
report = generate_markdown_report(state)
assert "# LLM Comparison Report" in report
assert "## Model: model-a" not in report # No context added
class TestGenerateJsonReport:
"""Tests for generate_json_report function."""
def test_generate_json_report_structure(self, sample_session_state):
"""Test JSON report has correct structure."""
from prompt_prix.export import generate_json_report
report_str = generate_json_report(sample_session_state)
report = json.loads(report_str)
assert "generated_at" in report
assert "configuration" in report
assert "halted" in report
assert "halt_reason" in report
assert "conversations" in report
def test_generate_json_report_configuration(self, sample_session_state):
"""Test JSON report configuration section."""
from prompt_prix.export import generate_json_report
report = json.loads(generate_json_report(sample_session_state))
config = report["configuration"]
assert config["models"] == ["llama-3.2-3b-instruct", "qwen2.5-7b-instruct"]
assert config["temperature"] == 0.7
assert config["max_tokens"] == 2048
assert config["timeout_seconds"] == 300
assert config["system_prompt"] == "You are a helpful assistant."
def test_generate_json_report_conversations(self, sample_session_state):
"""Test JSON report conversations section."""
from prompt_prix.export import generate_json_report
report = json.loads(generate_json_report(sample_session_state))
convos = report["conversations"]
assert "llama-3.2-3b-instruct" in convos
assert "qwen2.5-7b-instruct" in convos
llama_convo = convos["llama-3.2-3b-instruct"]
assert len(llama_convo["messages"]) == 2
assert llama_convo["messages"][0]["role"] == "user"
assert llama_convo["messages"][0]["content"] == "What is the capital of France?"
assert llama_convo["error"] is None
def test_generate_json_report_with_error(self, sample_session_state):
"""Test JSON report includes errors."""
from prompt_prix.export import generate_json_report
sample_session_state.contexts["llama-3.2-3b-instruct"].error = "Timeout"
report = json.loads(generate_json_report(sample_session_state))
assert report["conversations"]["llama-3.2-3b-instruct"]["error"] == "Timeout"
def test_generate_json_report_halted(self, halted_session_state):
"""Test JSON report halted status."""
from prompt_prix.export import generate_json_report
report = json.loads(generate_json_report(halted_session_state))
assert report["halted"] is True
assert "Connection timeout" in report["halt_reason"]
def test_generate_json_report_is_valid_json(self, sample_session_state):
"""Test JSON report is valid parseable JSON."""
from prompt_prix.export import generate_json_report
report_str = generate_json_report(sample_session_state)
# Should not raise
parsed = json.loads(report_str)
assert isinstance(parsed, dict)
def test_generate_json_report_excludes_server_metadata(self, sample_session_state):
"""Bug #31: Server metadata should not appear in exported JSON.
The Compare tab displays server info like '*[Server: localhost:1234]*'
for debugging, but this metadata should NOT be stored in the context
or appear in exports.
"""
from prompt_prix.export import generate_json_report
report_str = generate_json_report(sample_session_state)
# Server metadata patterns that should NOT appear
assert "*[Server:" not in report_str
assert "[Server:" not in report_str
assert "localhost:1234" not in report_str
assert "192.168." not in report_str # No IP addresses in responses
class TestSaveReport:
"""Tests for save_report function."""
def test_save_report_writes_file(self, tmp_path, sample_session_state):
"""Test save_report writes content to file."""
from prompt_prix.export import save_report
filepath = tmp_path / "report.md"
content = "# Test Report\n\nThis is a test."
save_report(content, str(filepath))
assert filepath.exists()
assert filepath.read_text(encoding="utf-8") == content
def test_save_report_creates_utf8_file(self, tmp_path):
"""Test save_report creates UTF-8 encoded file."""
from prompt_prix.export import save_report
filepath = tmp_path / "report.md"
content = "# Test Report\n\nUnicode: \u2713 \u2718 \u00e9\u00e8\u00e0"
save_report(content, str(filepath))
# Read back with explicit encoding
result = filepath.read_text(encoding="utf-8")
assert "\u2713" in result
assert "\u00e9" in result
def test_save_report_overwrites_existing(self, tmp_path):
"""Test save_report overwrites existing file."""
from prompt_prix.export import save_report
filepath = tmp_path / "report.md"
filepath.write_text("Old content")
save_report("New content", str(filepath))
assert filepath.read_text() == "New content"
class TestReportTimestamp:
"""Tests for report timestamp handling."""
def test_markdown_report_timestamp_format(self, sample_session_state):
"""Test markdown report has ISO format timestamp."""
from prompt_prix.export import generate_markdown_report
report = generate_markdown_report(sample_session_state)
# Should contain ISO-like timestamp (YYYY-MM-DD)
assert "**Generated:**" in report
# The timestamp should be parseable
def test_json_report_timestamp_format(self, sample_session_state):
"""Test JSON report has ISO format timestamp."""
from prompt_prix.export import generate_json_report
report = json.loads(generate_json_report(sample_session_state))
# Should be ISO format
timestamp = report["generated_at"]
# Verify it's parseable as ISO format
datetime.fromisoformat(timestamp)