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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! # teremock - Production-grade Mock Bot for Teloxide Integration Testing
//!
//! A high-performance mock bot for integration testing teloxide bots with an actual fake server.
//!
//! ## Key Features
//!
//! - **Persistent Server Architecture**: Server starts once and is reused across all dispatches
//! - **Stack Overflow Prevention**: Uses tokio task spawn per dispatch to prevent stack buildup
//! - **Black-Box Testing**: No dialogue state manipulation - tests interact only through the bot interface
//! - **Rich Response Inspection**: Comprehensive access to all bot API responses
//!
//! ## Quick Start
//!
//! ```no_run
//! use teloxide::{
//! dispatching::{UpdateFilterExt, UpdateHandler},
//! prelude::*,
//! };
//!
//! type HandlerResult = Result<(), Box<dyn std::error::Error + Send + Sync>>;
//!
//! async fn hello_world(bot: Bot, message: Message) -> HandlerResult {
//! bot.send_message(message.chat.id, "Hello World!").await?;
//! Ok(())
//! }
//!
//! fn handler_tree() -> UpdateHandler<Box<dyn std::error::Error + Send + Sync + 'static>> {
//! dptree::entry().branch(Update::filter_message().endpoint(hello_world))
//! }
//!
//! #[cfg(test)]
//! mod tests {
//! use super::*;
//! use teremock::{MockBot, MockMessageText};
//!
//! #[tokio::test]
//! async fn test_hello_world() {
//! let mut bot = MockBot::new(MockMessageText::new().text("Hi!"), handler_tree()).await;
//! bot.dispatch().await;
//! let message = bot.get_responses().sent_messages.last().unwrap();
//! assert_eq!(message.text(), Some("Hello World!"));
//! }
//! }
//! ```
//!
//! ## Architecture
//!
//! teremock is designed for production-grade integration testing with:
//!
//! 1. **Persistent Server**: Unlike the original teloxide_tests where each dispatch creates a new
//! server, teremock keeps the server alive across all dispatches. This provides 15-30x faster
//! test execution (2s vs 30-60s for 50+ dispatches).
//!
//! 2. **Tokio Task Isolation**: Each dispatch runs in a separate tokio task with a fresh 2MB stack.
//! This prevents stack overflow issues that occur when handler trees are cloned across many
//! sequential dispatches.
//!
//! 3. **Black-Box Testing Philosophy**: Tests should interact only through the bot interface
//! (messages, callbacks, commands). There's no dialogue state manipulation API - state changes
//! happen naturally through the handler tree.
//!
//! ## Supported Endpoints
//!
//! - /AnswerCallbackQuery
//! - /DeleteMessage
//! - /DeleteMessages
//! - /EditMessageText
//! - /EditMessageReplyMarkup
//! - /EditMessageCaption
//! - /GetFile
//! - /SendMessage
//! - /SendDocument
//! - /SendPhoto
//! - /SendVideo
//! - /SendAudio
//! - /SendVoice
//! - /SendVideoNote
//! - /SendAnimation
//! - /SendLocation
//! - /SendVenue
//! - /SendContact
//! - /SendDice
//! - /SendPoll
//! - /SendSticker
//! - /SendChatAction
//! - /SendMediaGroup
//! - /SendInvoice
//! - /PinChatMessage
//! - /UnpinChatMessage
//! - /UnpinAllChatMessages
//! - /ForwardMessage
//! - /CopyMessage
//! - /BanChatMember
//! - /UnbanChatMember
//! - /RestrictChatMember
//! - /SetMessageReaction
//! - /SetMyCommands
//! - /GetMe
//!
//! ## Migration from teloxide_tests
//!
//! The main API differences:
//!
//! ```ignore
//! // OLD (teloxide_tests):
//! let mut bot = MockBot::new(MockMessageText::new().text("Hi!"), handler_tree());
//! bot.dispatch().await;
//!
//! // NEW (teremock):
//! let mut bot = MockBot::new(MockMessageText::new().text("Hi!"), handler_tree()).await;
//! bot.dispatch().await;
//! // Note: `new()` is now async because it starts the server immediately
//! ```
//!
//! Key differences:
//! - `new()` is now async (starts the server immediately)
//! - No `set_state()` / `get_state()` methods (black-box testing)
//! - Server persists across dispatches (much faster)
//! - Works with default 2MB stack (no custom thread builder needed)
//! - No global lock needed (server is persistent per MockBot instance)
// Clippy suppressions - these are intentional design choices:
// - new_without_default: 36 Mock* builders have new() but Default adds no value for builder pattern
// - too_many_arguments: Macro-generated constructors for Telegram API types
// - enum_variant_names: InputMedia* variants mirror Telegram API naming
pub
pub
pub use *;
pub use ;
pub use Responses;
use ;
use teremock_macros as proc_macros;
/// Error type alias commonly used with handler trees
pub type HandlerError = ;
// Conversion traits for ergonomic ID field setters
// These traits allow mock builders to accept both primitive types and teloxide wrapper types
/// Trait for types that can be converted to [`ChatId`].
///
/// This trait is automatically implemented for:
/// - `i64` - raw chat ID value
/// - `i32` - raw chat ID value (for bare integer literals)
/// - `ChatId` - directly pass a ChatId
/// - `UserId` - for private chats where chat ID equals user ID
/// Trait for types that can be converted to [`UserId`].
///
/// This trait is automatically implemented for:
/// - `u64` - raw user ID value
/// - `i64` - raw user ID value (useful when working with chat IDs)
/// - `i32` - raw user ID value (for bare integer literals)
/// - `UserId` - directly pass a UserId
/// Trait for types that can be converted to [`MessageId`].
///
/// This trait is automatically implemented for:
/// - `i32` - raw message ID value
/// - `MessageId` - directly pass a MessageId