61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
"""Tests for the Phase 1.3 QueryDecomposer component."""
|
|
|
|
import json
|
|
from typing import List
|
|
|
|
import pytest
|
|
|
|
from app.services.query_decomposer import QueryDecomposer
|
|
|
|
|
|
class MockLLMClient:
|
|
"""Simple mock LLM client with a fixed response."""
|
|
|
|
def __init__(self, response: str):
|
|
self._response = response
|
|
self.last_prompt = None
|
|
|
|
def complete(self, prompt: str, temperature: float = 0.7) -> str:
|
|
self.last_prompt = prompt
|
|
return self._response
|
|
|
|
|
|
def test_decompose_valid_json():
|
|
llm = MockLLMClient('["alpha", "beta", "gamma"]')
|
|
decomposer = QueryDecomposer(llm)
|
|
result: List[str] = decomposer.decompose("What are keywords for X?")
|
|
assert result == ["alpha", "beta", "gamma"]
|
|
# Ensure the prompt was constructed with the given question
|
|
assert llm.last_prompt == "Given question: 'What are keywords for X?', extract key search keywords as JSON array"
|
|
|
|
|
|
def test_decompose_empty_question_returns_empty():
|
|
llm = MockLLMClient('["should_not_be_used"]')
|
|
decomposer = QueryDecomposer(llm)
|
|
result = decomposer.decompose("")
|
|
assert result == []
|
|
# LLM should not be called for empty input
|
|
assert llm.last_prompt is None
|
|
|
|
|
|
def test_decompose_invalid_json_returns_empty():
|
|
llm = MockLLMClient("not-json")
|
|
decomposer = QueryDecomposer(llm)
|
|
result = decomposer.decompose("Question?")
|
|
assert result == []
|
|
|
|
|
|
def test_decompose_non_list_json_returns_empty():
|
|
llm = MockLLMClient("{\"a\": 1}")
|
|
decomposer = QueryDecomposer(llm)
|
|
result = decomposer.decompose("Question?")
|
|
assert result == []
|
|
|
|
|
|
def test_decompose_mixed_types_coerced_to_strings():
|
|
llm = MockLLMClient('["a", 2, null]')
|
|
decomposer = QueryDecomposer(llm)
|
|
result = decomposer.decompose("Question?")
|
|
# Non-string items should be coerced to strings
|
|
assert result == ["a", "2", "None"]
|