"""Tests for diagnose/_llm_client.py — thinking-tag stripping and content extraction."""
from __future__ import annotations
import pytest
def _resp(content: str | None) -> dict:
if content is None:
return {"choices": []}
return {"choices": [{"message": {"content": content}}]}
class TestExtractContent:
def test_returns_plain_content(self):
from app.services.diagnose._llm_client import extract_content
assert extract_content(_resp("hello world")) == "hello world"
def test_returns_none_on_empty_choices(self):
from app.services.diagnose._llm_client import extract_content
assert extract_content({"choices": []}) is None
def test_returns_none_on_empty_content(self):
from app.services.diagnose._llm_client import extract_content
assert extract_content(_resp("")) is None
def test_strips_single_think_block(self):
from app.services.diagnose._llm_client import extract_content
raw = "Let me reason about this…\nThe answer is 42."
assert extract_content(_resp(raw)) == "The answer is 42."
def test_strips_multi_line_think_block(self):
from app.services.diagnose._llm_client import extract_content
raw = "\nStep 1: consider X\nStep 2: consider Y\n\n\nFinal answer here."
result = extract_content(_resp(raw))
assert result == "Final answer here."
assert "" not in result
def test_strips_multiple_think_blocks(self):
from app.services.diagnose._llm_client import extract_content
raw = "first actual second content"
result = extract_content(_resp(raw))
assert "" not in result
assert "actual" in result
assert "content" in result
def test_strips_case_insensitive(self):
from app.services.diagnose._llm_client import extract_content
raw = "hidden visible"
result = extract_content(_resp(raw))
assert result == "visible"
def test_returns_none_when_only_thinking_remains(self):
from app.services.diagnose._llm_client import extract_content
raw = "only thinking, no output"
assert extract_content(_resp(raw)) is None
def test_content_without_thinking_unchanged(self):
from app.services.diagnose._llm_client import extract_content
raw = "Redis OOM at 03:00 — key eviction triggered by batch job."
assert extract_content(_resp(raw)) == raw
class TestStripJsonFences:
def test_strips_json_fence(self):
from app.services.diagnose._llm_client import strip_json_fences
raw = "```json\n[{\"a\": 1}]\n```"
assert strip_json_fences(raw) == '[{"a": 1}]'
def test_strips_plain_fence(self):
from app.services.diagnose._llm_client import strip_json_fences
raw = "```\nhello\n```"
assert "```" not in strip_json_fences(raw)
class TestExtractFirstJsonArray:
def test_extracts_array_from_mixed_text(self):
from app.services.diagnose._llm_client import extract_first_json_array
raw = 'Here is the result:\n[{"id": 1}, {"id": 2}]\nThat is all.'
result = extract_first_json_array(raw)
import json
parsed = json.loads(result)
assert len(parsed) == 2
def test_returns_original_when_no_array(self):
from app.services.diagnose._llm_client import extract_first_json_array
raw = "no array here"
assert extract_first_json_array(raw) == raw