"""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