from imagine_buddy.protocol import ReplySegment, parse_reply def test_plain_text_becomes_narrator_segment(): p = parse_reply("The wood holds its breath.") assert p.segments == (ReplySegment("narrator", "The wood holds its breath."),) assert p.controls == () def test_multiple_voice_segments(): p = parse_reply('[voice:narrator] A bridge appears. [voice:Rexy] "Who goes there?"') assert p.segments == ( ReplySegment("narrator", "A bridge appears."), ReplySegment("Rexy", '"Who goes there?"'), ) def test_control_tags_extracted_and_stripped(): raw = ('[voice:narrator] A new friend! ' '[cast:add name=Rexy role="bridge guardian" temperament=gruff] ' '[beat:advance][fateroll]') p = parse_reply(raw) assert p.segments == (ReplySegment("narrator", "A new friend!"),) assert {"type": "cast:add", "name": "Rexy", "role": "bridge guardian", "temperament": "gruff"} in p.controls assert {"type": "beat:advance"} in p.controls assert {"type": "fateroll"} in p.controls def test_text_before_first_voice_tag_is_narrator(): p = parse_reply('Once upon a time. [voice:Knight] Onward!') assert p.segments[0] == ReplySegment("narrator", "Once upon a time.") assert p.segments[1] == ReplySegment("Knight", "Onward!") def test_empty_segments_are_dropped(): p = parse_reply("[voice:narrator] [voice:Rexy] Rawr!") assert p.segments == (ReplySegment("Rexy", "Rawr!"),) def test_unknown_bracket_tags_left_in_text(): p = parse_reply("[voice:narrator] He waves [enthusiastically].") assert p.segments == (ReplySegment("narrator", "He waves [enthusiastically]."),) def test_attr_values_are_whitespace_stripped(): p = parse_reply('[cast:add name=" Rexy " role=dino temperament=gruff]') assert p.controls[0]["name"] == "Rexy" def test_hallucinated_type_attr_cannot_overwrite_control_type(): p = parse_reply("[cast:add type=evil name=X]") assert p.controls[0]["type"] == "cast:add" assert p.controls[0]["name"] == "X"