test_tools.py
5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""Unit tests for tools module."""
import json
import pytest
from hermes_feishu.schemas import SEND_FEISHU_CARD_SCHEMA, SEND_FEISHU_TABLE_SCHEMA
class TestSchemas:
def test_card_schema_has_required_fields(self):
props = SEND_FEISHU_CARD_SCHEMA["parameters"]["properties"]
assert "content" in props
assert "title" in props
assert "chat_id" in props
assert "template" in props
def test_card_schema_content_required(self):
required = SEND_FEISHU_CARD_SCHEMA["parameters"]["required"]
assert "content" in required
def test_card_schema_template_enum(self):
template = SEND_FEISHU_CARD_SCHEMA["parameters"]["properties"]["template"]
assert "enum" in template
assert "blue" in template["enum"]
assert "green" in template["enum"]
assert "red" in template["enum"]
def test_card_schema_description_mentions_table(self):
desc = SEND_FEISHU_CARD_SCHEMA["description"].lower()
assert "table" in desc
assert "feishu" in desc
def test_table_schema_has_required_fields(self):
props = SEND_FEISHU_TABLE_SCHEMA["parameters"]["properties"]
assert "headers" in props
assert "rows" in props
def test_table_schema_required(self):
required = SEND_FEISHU_TABLE_SCHEMA["parameters"]["required"]
assert "headers" in required
assert "rows" in required
def test_table_schema_headers_type(self):
headers = SEND_FEISHU_TABLE_SCHEMA["parameters"]["properties"]["headers"]
assert headers["type"] == "array"
assert headers["items"]["type"] == "string"
def test_table_schema_rows_type(self):
rows = SEND_FEISHU_TABLE_SCHEMA["parameters"]["properties"]["rows"]
assert rows["type"] == "array"
assert rows["items"]["type"] == "array"
class TestToolHandlers:
"""Test tool handlers without actual Feishu API calls."""
def test_card_no_content_returns_error(self):
from hermes_feishu.tools import send_feishu_card
result = json.loads(send_feishu_card({}))
assert "error" in result
def test_card_no_chat_id_returns_error(self):
from hermes_feishu.tools import send_feishu_card
result = json.loads(send_feishu_card({"content": "test"}))
assert "error" in result
def test_card_with_chat_id_attempts_send(self):
from hermes_feishu.tools import send_feishu_card
# With no credentials, should still get a result (error about credentials)
result = json.loads(send_feishu_card(
{"content": "| A | B |\n| --- | --- |\n| 1 | 2 |"},
chat_id="test_chat",
))
# Should get some result (success or error about credentials)
assert "success" in result or "error" in result
def test_table_no_headers_returns_error(self):
from hermes_feishu.tools import send_feishu_table
result = json.loads(send_feishu_table({}))
assert "error" in result
def test_table_no_rows_returns_error(self):
from hermes_feishu.tools import send_feishu_table
result = json.loads(send_feishu_table({"headers": ["A", "B"]}))
assert "error" in result
def test_table_no_chat_id_returns_error(self):
from hermes_feishu.tools import send_feishu_table
result = json.loads(send_feishu_table({
"headers": ["A", "B"],
"rows": [["1", "2"]],
}))
assert "error" in result
def test_table_builds_valid_card_structure(self):
"""Verify the tool builds correct card structure without actually sending."""
from hermes_feishu.tools import send_feishu_table
from unittest.mock import patch
mock_result = json.dumps({"success": True, "message_id": "om_xxx"})
with patch("hermes_feishu.tools.send_card", return_value=mock_result):
result = json.loads(send_feishu_table(
{"headers": ["Name", "Score"], "rows": [["Alice", "95"]]},
chat_id="test_chat",
))
assert result["success"] is True
def test_card_with_table_content(self):
"""Verify card tool handles table content correctly."""
from hermes_feishu.tools import send_feishu_card
from unittest.mock import patch
import hermes_feishu.card_builder as cb
# Verify build_mixed_card is called with table content
content = "| Name | Value |\n| --- | --- |\n| Key | 100 |"
card = cb.build_mixed_card(content)
assert card is not None
assert any(e["tag"] == "table" for e in card["elements"])
class TestPreLlmCallHook:
def test_feishu_platform_returns_context(self):
from hermes_feishu import _on_pre_llm_call
result = _on_pre_llm_call(platform="feishu", is_first_turn=True)
assert result is not None
assert "context" in result
assert "table" in result["context"].lower()
def test_lark_platform_returns_context(self):
from hermes_feishu import _on_pre_llm_call
result = _on_pre_llm_call(platform="lark", is_first_turn=True)
assert result is not None
def test_non_feishu_platform_returns_none(self):
from hermes_feishu import _on_pre_llm_call
result = _on_pre_llm_call(platform="telegram", is_first_turn=True)
assert result is None
def test_not_first_turn_returns_none(self):
from hermes_feishu import _on_pre_llm_call
result = _on_pre_llm_call(platform="feishu", is_first_turn=False)
assert result is None
def test_no_platform_returns_none(self):
from hermes_feishu import _on_pre_llm_call
result = _on_pre_llm_call(platform="", is_first_turn=True)
assert result is None