"""petctl parsing — the pseudo-commands the server can relay to drive the pet's body instead of a shell.""" import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from bolt_pet import pet_actions def test_non_pet_commands_are_left_alone(): assert pet_actions.parse("ls -la") is None assert pet_actions.parse("systemctl restart nginx") is None assert pet_actions.parse("") is None # "petstore" must not be mistaken for the "pet" prefix assert pet_actions.parse("petstore --list") is None def test_move_to_an_anchor(): assert pet_actions.parse("petctl move top-left") == {"action": "move", "anchor": "top-left"} assert pet_actions.parse("petctl move bottom_right") == {"action": "move", "anchor": "bottom-right"} def test_move_to_coordinates(): assert pet_actions.parse("petctl move 300 120") == {"action": "move", "x": 300, "y": 120} def test_move_rejects_nonsense_targets(): with pytest.raises(pet_actions.ActionError): pet_actions.parse("petctl move sideways") with pytest.raises(pet_actions.ActionError): pet_actions.parse("petctl move") def test_emotes(): assert pet_actions.parse("petctl emote wave") == {"action": "emote", "emote": "wave"} with pytest.raises(pet_actions.ActionError): pet_actions.parse("petctl emote moonwalk") def test_say_keeps_the_whole_sentence(): assert pet_actions.parse('petctl say "build is green"') == { "action": "say", "text": "build is green" } assert pet_actions.parse("petctl say build is green")["text"] == "build is green" def test_wander_and_nap_toggles(): assert pet_actions.parse("petctl wander off") == {"action": "wander", "enabled": False} assert pet_actions.parse("petctl nap on") == {"action": "nap", "enabled": True} with pytest.raises(pet_actions.ActionError): pet_actions.parse("petctl wander maybe") def test_alternate_prefixes_and_verbs(): assert pet_actions.parse("bolt-pet goto center")["anchor"] == "center" assert pet_actions.parse("pet do hop")["emote"] == "hop" def test_unknown_verb_is_an_error_not_a_shell_command(): with pytest.raises(pet_actions.ActionError): pet_actions.parse("petctl explode") def test_describe_is_reported_back_to_the_server(): assert "top-left" in pet_actions.describe({"action": "move", "anchor": "top-left"}) assert "wave" in pet_actions.describe({"action": "emote", "emote": "wave"}) assert pet_actions.describe({"action": "help"}) == pet_actions.HELP def test_voice_reset_parses_with_or_without_the_word_reset(): assert pet_actions.parse("petctl voice reset") == {"action": "voice", "voice": "default"} assert pet_actions.parse("petctl voice default") == {"action": "voice", "voice": "default"} assert pet_actions.parse("petctl voice") == {"action": "voice", "voice": "default"} def test_petctl_cannot_be_used_to_pick_a_voice(): """Choosing a voice is the server's job (speak_as) — it has the voice library. petctl only ever undoes one, so an attempt to set a voice here is pointed back at the marker that works.""" with pytest.raises(pet_actions.ActionError, match="speak_as"): pet_actions.parse("petctl voice Terence")