@@ -36,6 +36,18 @@ def _make_message(outgoing: bool = False, age_seconds: int = 0, from_bot: bool =
3636 return msg
3737
3838
39+ def _sys_msg_side_effect (* args , ** kwargs ):
40+ """Side-effect для get_system_message: возвращает разные строки по ключу."""
41+ key = args [1 ] if len (args ) > 1 else kwargs .get ("key" , "" )
42+ mapping = {
43+ "status_disconnected" : "Connect first" ,
44+ "poke_result" : "Checked {checked} chats — generating {drafts} drafts." ,
45+ "poke_result_none" : "Checked {checked} chats — no drafts needed." ,
46+ "draft_typing" : "{emoji} is typing..." ,
47+ }
48+ return mapping .get (key , key )
49+
50+
3951class TestOnPoke :
4052 """Тесты для on_poke()."""
4153
@@ -48,7 +60,7 @@ async def test_not_connected_shows_message(self):
4860 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
4961 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
5062 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
51- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Connect first" ):
63+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ):
5264 mock_pc .is_active = MagicMock (return_value = False )
5365
5466 await on_poke (update , context )
@@ -57,7 +69,7 @@ async def test_not_connected_shows_message(self):
5769
5870 @pytest .mark .asyncio
5971 async def test_unanswered_incoming_generates_draft (self ):
60- """Входящее сообщение без черновика → генерация."""
72+ """Входящее сообщение без черновика → генерация + результат с drafts=1 ."""
6173 user_id = 123
6274 chat_id = 456
6375 update = _make_update (user_id = user_id )
@@ -68,7 +80,7 @@ async def test_unanswered_incoming_generates_draft(self):
6880 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
6981 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
7082 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
71- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
83+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
7284 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : {}}), \
7385 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = False ), \
7486 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
@@ -83,10 +95,15 @@ async def test_unanswered_incoming_generates_draft(self):
8395 await on_poke (update , context )
8496
8597 mock_gen .assert_called_once_with (user_id , chat_id , {"settings" : {}}, {}, None )
98+ # result only
99+ update .message .reply_text .assert_called_once ()
100+ result_call = update .message .reply_text .call_args_list [- 1 ]
101+ assert "1 chats" in result_call .args [0 ]
102+ assert "1 drafts" in result_call .args [0 ]
86103
87104 @pytest .mark .asyncio
88105 async def test_incoming_with_existing_draft_skipped (self ):
89- """Входящее с существующим черновиком → пропуск."""
106+ """Входящее с существующим черновиком → пропуск, drafts=0 ."""
90107 user_id = 123
91108 chat_id = 456
92109 update = _make_update (user_id = user_id )
@@ -95,7 +112,7 @@ async def test_incoming_with_existing_draft_skipped(self):
95112 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
96113 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
97114 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
98- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
115+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
99116 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : {}}), \
100117 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = False ), \
101118 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
@@ -107,11 +124,15 @@ async def test_incoming_with_existing_draft_skipped(self):
107124 await on_poke (update , context )
108125
109126 mock_gen .assert_not_called ()
127+ # result_none only
128+ update .message .reply_text .assert_called_once ()
129+ result_call = update .message .reply_text .call_args_list [- 1 ]
130+ assert "no drafts needed" in result_call .args [0 ]
110131 _bot_drafts .pop ((user_id , chat_id ), None )
111132
112133 @pytest .mark .asyncio
113134 async def test_outgoing_fresh_skipped (self ):
114- """Исходящее свежее (< 12ч) → пропуск."""
135+ """Исходящее свежее (< 12ч) → пропуск, drafts=0 ."""
115136 user_id = 123
116137 chat_id = 456
117138 update = _make_update (user_id = user_id )
@@ -122,7 +143,7 @@ async def test_outgoing_fresh_skipped(self):
122143 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
123144 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
124145 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
125- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
146+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
126147 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : {}}), \
127148 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = False ), \
128149 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
@@ -136,10 +157,15 @@ async def test_outgoing_fresh_skipped(self):
136157 await on_poke (update , context )
137158
138159 mock_gen .assert_not_called ()
160+ # result_none only (checked=1, drafts=0)
161+ update .message .reply_text .assert_called_once ()
162+ result_call = update .message .reply_text .call_args_list [- 1 ]
163+ assert "1 chats" in result_call .args [0 ]
164+ assert "no drafts needed" in result_call .args [0 ]
139165
140166 @pytest .mark .asyncio
141167 async def test_outgoing_old_generates_followup (self ):
142- """Исходящее старое (> 12ч) → follow-up генерация."""
168+ """Исходящее старое (> 12ч) → follow-up генерация, drafts=1 ."""
143169 user_id = 123
144170 chat_id = 456
145171 update = _make_update (user_id = user_id )
@@ -150,7 +176,7 @@ async def test_outgoing_old_generates_followup(self):
150176 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
151177 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
152178 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
153- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
179+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
154180 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : {}}), \
155181 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = False ), \
156182 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
@@ -165,6 +191,10 @@ async def test_outgoing_old_generates_followup(self):
165191 await on_poke (update , context )
166192
167193 mock_gen .assert_called_once ()
194+ # result only
195+ update .message .reply_text .assert_called_once ()
196+ result_call = update .message .reply_text .call_args_list [- 1 ]
197+ assert "1 drafts" in result_call .args [0 ]
168198
169199 @pytest .mark .asyncio
170200 async def test_ignored_chat_skipped (self ):
@@ -179,7 +209,7 @@ async def test_ignored_chat_skipped(self):
179209 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
180210 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
181211 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
182- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
212+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
183213 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : settings }), \
184214 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = False ), \
185215 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
@@ -203,7 +233,7 @@ async def test_bot_message_skipped(self):
203233 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
204234 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
205235 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
206- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
236+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
207237 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : {}}), \
208238 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = False ), \
209239 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
@@ -231,7 +261,7 @@ async def test_user_typing_skipped(self):
231261 with patch ("handlers.poke_handler.pyrogram_client" ) as mock_pc , \
232262 patch ("handlers.poke_handler.ensure_effective_user" , new_callable = AsyncMock ), \
233263 patch ("handlers.poke_handler.update_last_msg_at" , new_callable = AsyncMock ), \
234- patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , return_value = "Scanning" ), \
264+ patch ("handlers.poke_handler.get_system_message" , new_callable = AsyncMock , side_effect = _sys_msg_side_effect ), \
235265 patch ("handlers.poke_handler.get_user" , new_callable = AsyncMock , return_value = {"settings" : {}}), \
236266 patch ("handlers.poke_handler._is_user_typing" , new_callable = AsyncMock , return_value = True ) as mock_typing , \
237267 patch ("handlers.poke_handler._generate_reply_for_chat" , new_callable = AsyncMock ) as mock_gen :
0 commit comments