test_display_emoji.py
1 """Tests for get_tool_emoji in agent/display.py — skin + registry integration.""" 2 3 from unittest.mock import patch as mock_patch, MagicMock 4 5 from agent.display import get_tool_emoji 6 7 8 class TestGetToolEmoji: 9 """Verify the skin → registry → fallback resolution chain.""" 10 11 def test_returns_registry_emoji_when_no_skin(self): 12 """Registry-registered emoji is used when no skin is active.""" 13 mock_registry = MagicMock() 14 mock_registry.get_emoji.return_value = "🎨" 15 with mock_patch("agent.display._get_skin", return_value=None), \ 16 mock_patch("agent.display.registry", mock_registry, create=True): 17 # Need to patch the import inside get_tool_emoji 18 pass 19 # Direct test: patch the lazy import path 20 with mock_patch("agent.display._get_skin", return_value=None): 21 # get_tool_emoji will try to import registry — mock that 22 mock_reg = MagicMock() 23 mock_reg.get_emoji.return_value = "📖" 24 with mock_patch.dict("sys.modules", {}): 25 import sys 26 # Patch tools.registry module 27 mock_module = MagicMock() 28 mock_module.registry = mock_reg 29 with mock_patch.dict(sys.modules, {"tools.registry": mock_module}): 30 result = get_tool_emoji("read_file") 31 assert result == "📖" 32 33 def test_skin_override_takes_precedence(self): 34 """Skin tool_emojis override registry defaults.""" 35 skin = MagicMock() 36 skin.tool_emojis = {"terminal": "⚔"} 37 with mock_patch("agent.display._get_skin", return_value=skin): 38 result = get_tool_emoji("terminal") 39 assert result == "⚔" 40 41 def test_skin_empty_dict_falls_through(self): 42 """Empty skin tool_emojis falls through to registry.""" 43 skin = MagicMock() 44 skin.tool_emojis = {} 45 mock_reg = MagicMock() 46 mock_reg.get_emoji.return_value = "💻" 47 import sys 48 mock_module = MagicMock() 49 mock_module.registry = mock_reg 50 with mock_patch("agent.display._get_skin", return_value=skin), \ 51 mock_patch.dict(sys.modules, {"tools.registry": mock_module}): 52 result = get_tool_emoji("terminal") 53 assert result == "💻" 54 55 def test_fallback_default(self): 56 """When neither skin nor registry has an emoji, use the default.""" 57 skin = MagicMock() 58 skin.tool_emojis = {} 59 mock_reg = MagicMock() 60 mock_reg.get_emoji.return_value = "" 61 import sys 62 mock_module = MagicMock() 63 mock_module.registry = mock_reg 64 with mock_patch("agent.display._get_skin", return_value=skin), \ 65 mock_patch.dict(sys.modules, {"tools.registry": mock_module}): 66 result = get_tool_emoji("unknown_tool") 67 assert result == "⚡" 68 69 def test_custom_default(self): 70 """Custom default is returned when nothing matches.""" 71 with mock_patch("agent.display._get_skin", return_value=None): 72 mock_reg = MagicMock() 73 mock_reg.get_emoji.return_value = "" 74 import sys 75 mock_module = MagicMock() 76 mock_module.registry = mock_reg 77 with mock_patch.dict(sys.modules, {"tools.registry": mock_module}): 78 result = get_tool_emoji("x", default="⚙️") 79 assert result == "⚙️" 80 81 def test_skin_override_only_for_matching_tool(self): 82 """Skin override for one tool doesn't affect others.""" 83 skin = MagicMock() 84 skin.tool_emojis = {"terminal": "⚔"} 85 mock_reg = MagicMock() 86 mock_reg.get_emoji.return_value = "🔍" 87 import sys 88 mock_module = MagicMock() 89 mock_module.registry = mock_reg 90 with mock_patch("agent.display._get_skin", return_value=skin), \ 91 mock_patch.dict(sys.modules, {"tools.registry": mock_module}): 92 assert get_tool_emoji("terminal") == "⚔" # skin override 93 assert get_tool_emoji("web_search") == "🔍" # registry fallback 94 95 96 class TestSkinConfigToolEmojis: 97 """Verify SkinConfig handles tool_emojis field correctly.""" 98 99 def test_skin_config_has_tool_emojis_field(self): 100 from hermes_cli.skin_engine import SkinConfig 101 skin = SkinConfig(name="test") 102 assert skin.tool_emojis == {} 103 104 def test_skin_config_accepts_tool_emojis(self): 105 from hermes_cli.skin_engine import SkinConfig 106 emojis = {"terminal": "⚔", "web_search": "🔮"} 107 skin = SkinConfig(name="test", tool_emojis=emojis) 108 assert skin.tool_emojis == emojis 109 110 def test_build_skin_config_includes_tool_emojis(self): 111 from hermes_cli.skin_engine import _build_skin_config 112 data = { 113 "name": "custom", 114 "tool_emojis": {"terminal": "🗡️", "patch": "⚒️"}, 115 } 116 skin = _build_skin_config(data) 117 assert skin.tool_emojis == {"terminal": "🗡️", "patch": "⚒️"} 118 119 def test_build_skin_config_empty_tool_emojis_default(self): 120 from hermes_cli.skin_engine import _build_skin_config 121 data = {"name": "minimal"} 122 skin = _build_skin_config(data) 123 assert skin.tool_emojis == {}