ForcePilot/backend/test/unit/channels/test_wechat_selector.py

189 lines
7.7 KiB
Python
Raw Normal View History

from __future__ import annotations
from unittest.mock import patch
import pytest
from yuxi.channels.adapters.wechat.selector import (
SelectorCard,
SelectorItem,
SelectorOption,
WeChatSelectorAdapter,
)
class TestSelectorDataClasses:
def test_selector_option_creation(self):
opt = SelectorOption(id="1", text="选项一", is_default=True)
assert opt.id == "1"
assert opt.text == "选项一"
assert opt.is_default is True
def test_selector_option_defaults(self):
opt = SelectorOption(id="2", text="选项二")
assert opt.is_default is False
def test_selector_item_creation(self):
options = [SelectorOption(id="a", text="A"), SelectorOption(id="b", text="B")]
item = SelectorItem(question_key="q1", title="问题1", options=options, type="multi")
assert item.question_key == "q1"
assert item.title == "问题1"
assert len(item.options) == 2
assert item.type == "multi"
assert item.disable is False
def test_selector_card_creation(self):
card = SelectorCard(task_id="task1", title="请选择", description="desc")
assert card.task_id == "task1"
assert card.title == "请选择"
assert card.description == "desc"
assert card.created_at == 0.0
assert card.expires_at == 0.0
def test_selector_card_defaults(self):
card = SelectorCard(task_id="t1")
assert card.title == "请选择"
assert card.description == ""
assert card.items is None
class TestWeChatSelectorAdapter:
def setup_method(self):
self.adapter = WeChatSelectorAdapter(default_ttl_hours=24)
def test_build_selector(self):
items = [SelectorItem(question_key="q1", title="Q1")]
card = WeChatSelectorAdapter.build_selector("task-1", "标题", items, "描述", ttl_hours=1)
assert card.task_id == "task-1"
assert card.title == "标题"
assert card.description == "描述"
assert card.expires_at > card.created_at
def test_build_instance_option(self):
opt = WeChatSelectorAdapter.build_instance_option("1", "选项")
assert isinstance(opt, SelectorOption)
assert opt.id == "1"
assert opt.text == "选项"
def test_build_instance_item(self):
options = [SelectorOption(id="x", text="X")]
item = WeChatSelectorAdapter.build_instance_item("k1", "标题", options, "single")
assert isinstance(item, SelectorItem)
assert item.question_key == "k1"
assert item.type == "single"
def test_create_and_get_selector(self):
card = WeChatSelectorAdapter.build_selector("task-1", "标题", [])
self.adapter.create_selector(card)
retrieved = self.adapter.get_selector("task-1")
assert retrieved is not None
assert retrieved.task_id == "task-1"
def test_get_nonexistent_selector(self):
assert self.adapter.get_selector("nonexistent") is None
def test_is_expired_nonexistent(self):
assert self.adapter.is_expired("nonexistent") is True
@patch("time.time")
def test_is_expired_expired_card(self, mock_time):
mock_time.return_value = 1000000.0
card = WeChatSelectorAdapter.build_selector("task-1", "标题", [], ttl_hours=1)
self.adapter.create_selector(card)
mock_time.return_value = 1000000.0 + 3601.0
assert self.adapter.is_expired("task-1") is True
assert self.adapter.get_selector("task-1") is None
@patch("time.time")
def test_get_selector_expired_returns_none(self, mock_time):
mock_time.return_value = 100.0
card = WeChatSelectorAdapter.build_selector("task-e", "标题", [], ttl_hours=0)
self.adapter.create_selector(card)
mock_time.return_value = 101.0
assert self.adapter.get_selector("task-e") is None
def test_resolve_selections_single(self):
options = [SelectorOption(id="a", text="A"), SelectorOption(id="b", text="B")]
items = [SelectorItem(question_key="q1", title="Q1", options=options, type="single")]
card = WeChatSelectorAdapter.build_selector("task-r", "标题", items)
self.adapter.create_selector(card)
result = self.adapter.resolve_selections("task-r", {"q1": ["a", "b"]})
assert result is not None
assert result["answers"]["q1"] == "a"
def test_resolve_selections_multi(self):
options = [SelectorOption(id="a", text="A"), SelectorOption(id="b", text="B")]
items = [SelectorItem(question_key="q1", title="Q1", options=options, type="multi")]
card = WeChatSelectorAdapter.build_selector("task-r", "标题", items)
self.adapter.create_selector(card)
result = self.adapter.resolve_selections("task-r", {"q1": ["a", "b"]})
assert result is not None
assert result["answers"]["q1"] == ["a", "b"]
def test_resolve_selections_filters_invalid_ids(self):
options = [SelectorOption(id="a", text="A")]
items = [SelectorItem(question_key="q1", title="Q1", options=options)]
card = WeChatSelectorAdapter.build_selector("task-r", "标题", items)
self.adapter.create_selector(card)
result = self.adapter.resolve_selections("task-r", {"q1": ["invalid", "a"]})
assert result is not None
assert result["answers"]["q1"] == "a"
def test_resolve_selections_missing_key(self):
options = [SelectorOption(id="a", text="A")]
items = [SelectorItem(question_key="q1", title="Q1", options=options)]
card = WeChatSelectorAdapter.build_selector("task-r", "标题", items)
self.adapter.create_selector(card)
result = self.adapter.resolve_selections("task-r", {"other": ["a"]})
assert result is not None
assert "q1" not in result["answers"]
def test_resolve_selections_no_items(self):
card = SelectorCard(task_id="task-r", items=None)
self.adapter.create_selector(card)
result = self.adapter.resolve_selections("task-r", {"q1": ["a"]})
assert result is None
def test_render_taskcard_payload(self):
options = [SelectorOption(id="a", text="A")]
items = [SelectorItem(question_key="q1", title="Q1", options=options)]
card = WeChatSelectorAdapter.build_selector("task-card", "选择", items)
payload = self.adapter.render_taskcard_payload("user1", "agent1", card)
assert payload["touser"] == "user1"
assert payload["agentid"] == "agent1"
assert payload["msgtype"] == "template_card"
assert payload["template_card"]["card_type"] == "button_interaction"
assert payload["template_card"]["main_title"]["title"] == "选择"
assert len(payload["template_card"]["select_list"]) == 1
assert payload["template_card"]["submit_button"]["text"] == "确认"
@patch("time.time")
def test_list_active_selectors(self, mock_time):
mock_time.return_value = 1000.0
items = [SelectorItem(question_key="q1", title="Q1")]
card = WeChatSelectorAdapter.build_selector("task-1", "Card1", items, ttl_hours=24)
self.adapter.create_selector(card)
mock_time.return_value = 1010.0
active = self.adapter.list_active_selectors()
assert len(active) == 1
assert active[0]["task_id"] == "task-1"
assert active[0]["title"] == "Card1"
@patch("time.time")
def test_list_active_selectors_excludes_expired(self, mock_time):
mock_time.return_value = 1000.0
items = [SelectorItem(question_key="q1", title="Q1")]
card = WeChatSelectorAdapter.build_selector("task-1", "Card1", items, ttl_hours=0)
self.adapter.create_selector(card)
mock_time.return_value = 2000.0
active = self.adapter.list_active_selectors()
assert len(active) == 0