from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
from yuxi.channels.adapters.whatsapp.reactions.ack_reaction import AckReactionManager
from yuxi.channels.adapters.whatsapp.reactions.reaction_level import ReactionLevel, ReactionLevelController
from yuxi.channels.adapters.whatsapp.markdown import markdown_to_whatsapp, text_sanitizer
from yuxi.channels.adapters.whatsapp.structured_context import (
ContextSource,
ContextType,
StructuredContextEntry,
UntrustedStructuredContext,
)
class TestReactionLevel:
def test_enum_values(self):
assert ReactionLevel.OFF == "off"
assert ReactionLevel.MINIMAL == "minimal"
assert ReactionLevel.FULL == "full"
class TestReactionLevelController:
def test_default_constructor(self):
ctrl = ReactionLevelController({})
assert ctrl.level == ReactionLevel.MINIMAL
def test_off_level(self):
ctrl = ReactionLevelController({"reactionLevel": "off"})
assert ctrl.level == ReactionLevel.OFF
assert ctrl.can_send_reaction() is False
assert ctrl.can_send_reaction(is_ack=True) is False
def test_minimal_level(self):
ctrl = ReactionLevelController({"reactionLevel": "minimal"})
assert ctrl.level == ReactionLevel.MINIMAL
assert ctrl.can_send_reaction() is False
assert ctrl.can_send_reaction(is_ack=True) is True
def test_full_level(self):
ctrl = ReactionLevelController({"reactionLevel": "full"})
assert ctrl.level == ReactionLevel.FULL
assert ctrl.can_send_reaction() is True
assert ctrl.can_send_reaction(is_ack=True) is True
def test_invalid_level_defaults(self):
ctrl = ReactionLevelController({"reactionLevel": "invalid"})
assert ctrl.level == ReactionLevel.MINIMAL
def test_agent_reactions_disabled(self):
ctrl = ReactionLevelController({"reactionLevel": "full", "agentReactionsEnabled": False})
assert ctrl.agent_reactions_enabled is False
assert ctrl.can_agent_react() is False
def test_agent_reactions_off_level(self):
ctrl = ReactionLevelController({"reactionLevel": "off", "agentReactionsEnabled": True})
assert ctrl.can_agent_react() is False
def test_agent_reactions_enabled(self):
ctrl = ReactionLevelController({"reactionLevel": "full", "agentReactionsEnabled": True})
assert ctrl.can_agent_react() is True
def test_agent_reaction_guidance(self):
ctrl = ReactionLevelController({"agentReactionGuidance": "Use emoji"})
assert ctrl.get_agent_guidance() == "Use emoji"
def test_agent_reaction_guidance_empty(self):
ctrl = ReactionLevelController({})
assert ctrl.agent_reaction_guidance == ""
def test_agent_reaction_guidance_none(self):
ctrl = ReactionLevelController({})
assert ctrl.get_agent_guidance() is None
def test_properties_readonly(self):
ctrl = ReactionLevelController({"reactionLevel": "full"})
assert ctrl.level == ReactionLevel.FULL
assert ctrl.agent_reactions_enabled is True
class TestAckReactionManager:
def test_default_constructor(self):
mgr = AckReactionManager({})
assert mgr.emoji == "\u2705"
assert mgr.should_ack_direct() is True
assert mgr.should_ack_group() is True
def test_custom_emoji(self):
mgr = AckReactionManager({"ackReaction": {"emoji": "👍"}})
assert mgr.emoji == "👍"
def test_direct_disabled(self):
mgr = AckReactionManager({"ackReaction": {"direct": False}})
assert mgr.should_ack_direct() is False
def test_group_off(self):
mgr = AckReactionManager({"ackReaction": {"group": "off"}})
assert mgr.should_ack_group() is False
def test_group_mentions_only(self):
mgr = AckReactionManager({"ackReaction": {"group": "mentions"}})
assert mgr.should_ack_group() is True
assert mgr.should_ack_group_mentions_only() is True
def test_can_ack_direct(self):
mgr = AckReactionManager({"ackReaction": {"cooldown": 0}})
assert mgr.can_ack("chat1", is_group=False) is True
def test_can_ack_group_full(self):
mgr = AckReactionManager({"ackReaction": {"group": "full", "cooldown": 0}})
assert mgr.can_ack("chat1", is_group=True) is True
def test_can_ack_group_mentions_only_mentioned(self):
mgr = AckReactionManager({"ackReaction": {"group": "mentions", "cooldown": 0}})
assert mgr.can_ack("chat1", is_group=True, is_mentioned=True) is True
def test_can_ack_group_mentions_only_not_mentioned(self):
mgr = AckReactionManager({"ackReaction": {"group": "mentions", "cooldown": 0}})
assert mgr.can_ack("chat1", is_group=True, is_mentioned=False) is False
def test_can_ack_group_off(self):
mgr = AckReactionManager({"ackReaction": {"group": "off"}})
assert mgr.can_ack("chat1", is_group=True) is False
def test_can_ack_direct_disabled(self):
mgr = AckReactionManager({"ackReaction": {"direct": False, "cooldown": 0}})
assert mgr.can_ack("chat1", is_group=False) is False
def test_cooldown_prevents_ack(self):
mgr = AckReactionManager({"ackReaction": {"cooldown": 60}})
assert mgr.can_ack("chat1", is_group=False) is True
mgr.record_ack("chat1")
assert mgr.can_ack("chat1", is_group=False) is False
def test_different_chats_independent_cooldown(self):
mgr = AckReactionManager({"ackReaction": {"cooldown": 60}})
assert mgr.can_ack("chat1", is_group=False) is True
mgr.record_ack("chat1")
assert mgr.can_ack("chat2", is_group=False) is True
def test_record_ack(self):
mgr = AckReactionManager({})
mgr.record_ack("chat1")
class TestTextSanitizer:
def test_empty_string(self):
assert text_sanitizer("") == ""
def test_none_like(self):
assert text_sanitizer("") == ""
def test_nbsp_replacement(self):
assert text_sanitizer("hello world") == "hello world"
def test_allows_b_tag(self):
assert text_sanitizer("bold") == "bold"
def test_allows_i_tag(self):
assert text_sanitizer("italic") == "italic"
def test_allows_strong_tag(self):
assert text_sanitizer("bold") == "bold"
def test_allows_em_tag(self):
assert text_sanitizer("em") == "em"
def test_allows_u_tag(self):
assert text_sanitizer("underline") == "underline"
def test_allows_s_tag(self):
assert text_sanitizer("strikethrough") == "strikethrough"
def test_allows_code_tag(self):
assert text_sanitizer("code") == "code"
def test_allows_pre_tag(self):
assert text_sanitizer("
pre") == "
pre" def test_allows_a_tag(self): assert text_sanitizer('link') == 'link' def test_strips_script_tag(self): result = text_sanitizer("") assert "" not in result def test_strips_unknown_tags(self): assert text_sanitizer("