import json import pytest from chat.llm.mock import MockLLMClient from chat.services.turn_parse import ( ParsedTurn, TurnSegment, parse_turn, ) @pytest.mark.asyncio async def test_parse_turn_three_segment_happy_path(): canned = json.dumps( { "segments": [ {"kind": "action", "text": "walks over"}, {"kind": "dialogue", "text": "Hey."}, {"kind": "ooc", "text": "player note"}, ] } ) mock = MockLLMClient(canned=[canned]) result = await parse_turn( mock, model="m", prose='*walks over* "Hey." ((player note))', ) assert isinstance(result, ParsedTurn) assert len(result.segments) == 3 kinds = [s.kind for s in result.segments] assert kinds == ["action", "dialogue", "ooc"] texts = [s.text for s in result.segments] assert texts == ["walks over", "Hey.", "player note"] assert all(isinstance(s, TurnSegment) for s in result.segments) @pytest.mark.asyncio async def test_parse_turn_pure_dialogue_single_segment(): canned = json.dumps( { "segments": [ {"kind": "dialogue", "text": "Hello there"}, ] } ) mock = MockLLMClient(canned=[canned]) result = await parse_turn( mock, model="m", prose='"Hello there"', ) assert isinstance(result, ParsedTurn) assert len(result.segments) == 1 assert result.segments[0].kind == "dialogue" assert result.segments[0].text == "Hello there" @pytest.mark.asyncio async def test_parse_turn_empty_prose_short_circuits_without_classifier_call(): # No canned responses provided — if classify() is invoked it will raise # IndexError on the empty list. The short-circuit must prevent that. mock = MockLLMClient(canned=[]) result = await parse_turn(mock, model="m", prose="") assert isinstance(result, ParsedTurn) assert result.segments == [] # Whitespace-only prose must also short-circuit. result_ws = await parse_turn(mock, model="m", prose=" \n\t ") assert isinstance(result_ws, ParsedTurn) assert result_ws.segments == [] @pytest.mark.asyncio async def test_parse_turn_raises_when_classifier_fails_twice(): mock = MockLLMClient(canned=["nope", "still nope", "nope3"]) with pytest.raises(RuntimeError): await parse_turn( mock, model="m", prose='*shrugs* "whatever"', )