Split core and TUI crates
This commit is contained in:
458
crates/tele-tui/tests/helpers/fake_tdclient/operations.rs
Normal file
458
crates/tele-tui/tests/helpers/fake_tdclient/operations.rs
Normal file
@@ -0,0 +1,458 @@
|
||||
use super::{
|
||||
DeletedMessages, EditedMessage, FakeTdClient, ForwardedMessages, SearchQuery, SentMessage,
|
||||
TdUpdate,
|
||||
};
|
||||
use tele_tui::tdlib::types::ReactionInfo;
|
||||
use tele_tui::tdlib::{ChatInfo, MessageInfo, ProfileInfo, ReplyInfo};
|
||||
use tele_tui::types::{ChatId, MessageId, UserId};
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl FakeTdClient {
|
||||
pub async fn load_chats(&self, limit: usize) -> Result<Vec<ChatInfo>, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to load chats".to_string());
|
||||
}
|
||||
|
||||
if self.simulate_delays {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
|
||||
}
|
||||
|
||||
let chats = self
|
||||
.chats
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.take(limit)
|
||||
.cloned()
|
||||
.collect();
|
||||
Ok(chats)
|
||||
}
|
||||
|
||||
pub async fn open_chat(&self, chat_id: ChatId) -> Result<(), String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to open chat".to_string());
|
||||
}
|
||||
|
||||
*self.current_chat_id.lock().unwrap() = Some(chat_id.as_i64());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_chat_history(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
limit: i32,
|
||||
) -> Result<Vec<MessageInfo>, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to load history".to_string());
|
||||
}
|
||||
|
||||
if self.simulate_delays {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
||||
}
|
||||
|
||||
let messages = self
|
||||
.messages
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&chat_id.as_i64())
|
||||
.map(|msgs| msgs.iter().take(limit as usize).cloned().collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
pub async fn load_older_messages(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
from_message_id: MessageId,
|
||||
) -> Result<Vec<MessageInfo>, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to load older messages".to_string());
|
||||
}
|
||||
|
||||
let messages = self.messages.lock().unwrap();
|
||||
let chat_messages = messages.get(&chat_id.as_i64()).ok_or("Chat not found")?;
|
||||
|
||||
if let Some(idx) = chat_messages.iter().position(|m| m.id() == from_message_id) {
|
||||
let older = chat_messages.iter().take(idx).cloned().collect();
|
||||
Ok(older)
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_message(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
text: String,
|
||||
reply_to: Option<MessageId>,
|
||||
reply_info: Option<ReplyInfo>,
|
||||
) -> Result<MessageInfo, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to send message".to_string());
|
||||
}
|
||||
|
||||
if self.simulate_delays {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(200)).await;
|
||||
}
|
||||
|
||||
let message_id = MessageId::new((self.sent_messages.lock().unwrap().len() as i64) + 1000);
|
||||
|
||||
self.sent_messages.lock().unwrap().push(SentMessage {
|
||||
chat_id: chat_id.as_i64(),
|
||||
text: text.clone(),
|
||||
reply_to,
|
||||
reply_info: reply_info.clone(),
|
||||
});
|
||||
|
||||
let message = MessageInfo::new(
|
||||
message_id,
|
||||
"You".to_string(),
|
||||
true,
|
||||
text,
|
||||
vec![],
|
||||
chrono::Utc::now().timestamp() as i32,
|
||||
0,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
reply_info,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
|
||||
self.messages
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(chat_id.as_i64())
|
||||
.or_default()
|
||||
.push(message.clone());
|
||||
|
||||
self.send_update(TdUpdate::NewMessage { chat_id, message: Box::new(message.clone()) });
|
||||
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
pub async fn edit_message(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
message_id: MessageId,
|
||||
new_text: String,
|
||||
) -> Result<MessageInfo, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to edit message".to_string());
|
||||
}
|
||||
|
||||
if self.simulate_delays {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(150)).await;
|
||||
}
|
||||
|
||||
self.edited_messages.lock().unwrap().push(EditedMessage {
|
||||
chat_id: chat_id.as_i64(),
|
||||
message_id,
|
||||
new_text: new_text.clone(),
|
||||
});
|
||||
|
||||
let mut messages = self.messages.lock().unwrap();
|
||||
if let Some(chat_msgs) = messages.get_mut(&chat_id.as_i64()) {
|
||||
if let Some(msg) = chat_msgs.iter_mut().find(|m| m.id() == message_id) {
|
||||
msg.content.text = new_text.clone();
|
||||
msg.metadata.edit_date = msg.metadata.date + 60;
|
||||
|
||||
let updated = msg.clone();
|
||||
drop(messages);
|
||||
|
||||
self.send_update(TdUpdate::MessageContent { chat_id, message_id, new_text });
|
||||
|
||||
return Ok(updated);
|
||||
}
|
||||
}
|
||||
|
||||
Err("Message not found".to_string())
|
||||
}
|
||||
|
||||
pub async fn delete_messages(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
message_ids: Vec<MessageId>,
|
||||
revoke: bool,
|
||||
) -> Result<(), String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to delete messages".to_string());
|
||||
}
|
||||
|
||||
if self.simulate_delays {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
||||
}
|
||||
|
||||
self.deleted_messages.lock().unwrap().push(DeletedMessages {
|
||||
chat_id: chat_id.as_i64(),
|
||||
message_ids: message_ids.clone(),
|
||||
revoke,
|
||||
});
|
||||
|
||||
let mut messages = self.messages.lock().unwrap();
|
||||
if let Some(chat_msgs) = messages.get_mut(&chat_id.as_i64()) {
|
||||
chat_msgs.retain(|m| !message_ids.contains(&m.id()));
|
||||
}
|
||||
drop(messages);
|
||||
|
||||
self.send_update(TdUpdate::DeleteMessages { chat_id, message_ids });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn forward_messages(
|
||||
&self,
|
||||
to_chat_id: ChatId,
|
||||
from_chat_id: ChatId,
|
||||
message_ids: Vec<MessageId>,
|
||||
) -> Result<(), String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to forward messages".to_string());
|
||||
}
|
||||
|
||||
if self.simulate_delays {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(150)).await;
|
||||
}
|
||||
|
||||
self.forwarded_messages
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(ForwardedMessages {
|
||||
from_chat_id: from_chat_id.as_i64(),
|
||||
to_chat_id: to_chat_id.as_i64(),
|
||||
message_ids,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn search_messages(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
query: &str,
|
||||
) -> Result<Vec<MessageInfo>, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to search messages".to_string());
|
||||
}
|
||||
|
||||
let messages = self.messages.lock().unwrap();
|
||||
let results: Vec<_> = messages
|
||||
.get(&chat_id.as_i64())
|
||||
.map(|msgs| {
|
||||
msgs.iter()
|
||||
.filter(|m| m.text().to_lowercase().contains(&query.to_lowercase()))
|
||||
.cloned()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
self.searched_queries.lock().unwrap().push(SearchQuery {
|
||||
chat_id: chat_id.as_i64(),
|
||||
query: query.to_string(),
|
||||
results_count: results.len(),
|
||||
});
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub async fn set_draft_message(&self, chat_id: ChatId, text: String) -> Result<(), String> {
|
||||
if text.is_empty() {
|
||||
self.drafts.lock().unwrap().remove(&chat_id.as_i64());
|
||||
} else {
|
||||
self.drafts
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(chat_id.as_i64(), text.clone());
|
||||
}
|
||||
|
||||
self.send_update(TdUpdate::ChatDraftMessage {
|
||||
chat_id,
|
||||
draft_text: if text.is_empty() { None } else { Some(text) },
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_chat_action(&self, chat_id: ChatId, action: String) {
|
||||
self.chat_actions
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((chat_id.as_i64(), action.clone()));
|
||||
|
||||
if action == "Typing" {
|
||||
*self.typing_chat_id.lock().unwrap() = Some(chat_id.as_i64());
|
||||
} else if action == "Cancel" {
|
||||
*self.typing_chat_id.lock().unwrap() = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_message_available_reactions(
|
||||
&self,
|
||||
_chat_id: ChatId,
|
||||
_message_id: MessageId,
|
||||
) -> Result<Vec<String>, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to get available reactions".to_string());
|
||||
}
|
||||
|
||||
Ok(self.available_reactions.lock().unwrap().clone())
|
||||
}
|
||||
|
||||
pub async fn toggle_reaction(
|
||||
&self,
|
||||
chat_id: ChatId,
|
||||
message_id: MessageId,
|
||||
emoji: String,
|
||||
) -> Result<(), String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to toggle reaction".to_string());
|
||||
}
|
||||
|
||||
let mut messages = self.messages.lock().unwrap();
|
||||
if let Some(chat_msgs) = messages.get_mut(&chat_id.as_i64()) {
|
||||
if let Some(msg) = chat_msgs.iter_mut().find(|m| m.id() == message_id) {
|
||||
let reactions = &mut msg.interactions.reactions;
|
||||
|
||||
if let Some(pos) = reactions
|
||||
.iter()
|
||||
.position(|reaction| reaction.emoji == emoji && reaction.is_chosen)
|
||||
{
|
||||
reactions.remove(pos);
|
||||
} else if let Some(reaction) = reactions
|
||||
.iter_mut()
|
||||
.find(|reaction| reaction.emoji == emoji)
|
||||
{
|
||||
reaction.is_chosen = true;
|
||||
reaction.count += 1;
|
||||
} else {
|
||||
reactions.push(ReactionInfo {
|
||||
emoji: emoji.clone(),
|
||||
count: 1,
|
||||
is_chosen: true,
|
||||
});
|
||||
}
|
||||
|
||||
let updated_reactions = reactions.clone();
|
||||
drop(messages);
|
||||
|
||||
self.send_update(TdUpdate::MessageInteractionInfo {
|
||||
chat_id,
|
||||
message_id,
|
||||
reactions: updated_reactions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn download_file(&self, file_id: i32) -> Result<String, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to download file".to_string());
|
||||
}
|
||||
|
||||
self.downloaded_files
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&file_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("File {} not found", file_id))
|
||||
}
|
||||
|
||||
pub async fn get_profile_info(&self, chat_id: ChatId) -> Result<ProfileInfo, String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to get profile info".to_string());
|
||||
}
|
||||
|
||||
self.profiles
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&chat_id.as_i64())
|
||||
.cloned()
|
||||
.ok_or_else(|| "Profile not found".to_string())
|
||||
}
|
||||
|
||||
pub async fn view_messages(&self, chat_id: ChatId, message_ids: Vec<MessageId>) {
|
||||
self.viewed_messages
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((chat_id.as_i64(), message_ids.iter().map(|id| id.as_i64()).collect()));
|
||||
}
|
||||
|
||||
pub async fn load_folder_chats(&self, _folder_id: i32, _limit: usize) -> Result<(), String> {
|
||||
if self.should_fail() {
|
||||
return Err("Failed to load folder chats".to_string());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_update(&self, update: TdUpdate) {
|
||||
if let Some(tx) = self.update_tx.lock().unwrap().as_ref() {
|
||||
let _ = tx.send(update);
|
||||
}
|
||||
}
|
||||
|
||||
fn should_fail(&self) -> bool {
|
||||
let mut fail = self.fail_next_operation.lock().unwrap();
|
||||
if *fail {
|
||||
*fail = false;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fail_next(&self) {
|
||||
*self.fail_next_operation.lock().unwrap() = true;
|
||||
}
|
||||
|
||||
pub fn simulate_incoming_message(&self, chat_id: ChatId, text: String, sender_name: &str) {
|
||||
let message_id = MessageId::new(9000 + chrono::Utc::now().timestamp());
|
||||
|
||||
let message = MessageInfo::new(
|
||||
message_id,
|
||||
sender_name.to_string(),
|
||||
false,
|
||||
text,
|
||||
vec![],
|
||||
chrono::Utc::now().timestamp() as i32,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
None,
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
|
||||
self.messages
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(chat_id.as_i64())
|
||||
.or_default()
|
||||
.push(message.clone());
|
||||
|
||||
self.send_update(TdUpdate::NewMessage { chat_id, message: Box::new(message) });
|
||||
}
|
||||
|
||||
pub fn simulate_typing(&self, chat_id: ChatId, user_id: UserId) {
|
||||
self.send_update(TdUpdate::ChatAction { chat_id, user_id, action: "Typing".to_string() });
|
||||
}
|
||||
|
||||
pub fn simulate_network_change(&self, state: tele_tui::tdlib::NetworkState) {
|
||||
*self.network_state.lock().unwrap() = state.clone();
|
||||
self.send_update(TdUpdate::ConnectionState { state });
|
||||
}
|
||||
|
||||
pub fn simulate_read_outbox(&self, chat_id: ChatId, last_read_message_id: MessageId) {
|
||||
self.send_update(TdUpdate::ChatReadOutbox {
|
||||
chat_id,
|
||||
last_read_outbox_message_id: last_read_message_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user