fixes
Some checks failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled

This commit is contained in:
Mikhail Kilin
2026-01-29 01:22:57 +03:00
parent 68a2b7a982
commit 126c7482af
39 changed files with 2861 additions and 74 deletions

241
tests/search.rs Normal file
View File

@@ -0,0 +1,241 @@
// Integration tests for search flow
mod helpers;
use helpers::fake_tdclient::FakeTdClient;
use helpers::test_data::{create_test_chat, TestChatBuilder, TestMessageBuilder};
/// Test: Поиск по чатам фильтрует по названию
#[test]
fn test_search_chats_by_title() {
let mut client = FakeTdClient::new();
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Boss", 456);
let chat3 = create_test_chat("Mom's Work", 789);
client = client.with_chats(vec![chat1, chat2, chat3]);
// Ищем "mom" - должно найти "Mom" и "Mom's Work"
let query = "mom".to_lowercase();
let filtered: Vec<_> = client
.get_chats()
.iter()
.filter(|c| c.title.to_lowercase().contains(&query))
.collect();
assert_eq!(filtered.len(), 2);
assert_eq!(filtered[0].title, "Mom");
assert_eq!(filtered[1].title, "Mom's Work");
}
/// Test: Поиск по чатам фильтрует по @username
#[test]
fn test_search_chats_by_username() {
let mut client = FakeTdClient::new();
let chat1 = TestChatBuilder::new("Alice", 123)
.username("alice")
.build();
let chat2 = TestChatBuilder::new("Bob", 456)
.username("bobby")
.build();
let chat3 = TestChatBuilder::new("Charlie", 789).build(); // Без username
client = client.with_chats(vec![chat1, chat2, chat3]);
// Ищем "bob" - должно найти "Bob" (@bobby)
let query = "bob".to_lowercase();
let filtered: Vec<_> = client
.get_chats()
.iter()
.filter(|c| {
c.title.to_lowercase().contains(&query)
|| c.username
.as_ref()
.map(|u| u.to_lowercase().contains(&query))
.unwrap_or(false)
})
.collect();
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].title, "Bob");
}
/// Test: Пустой поисковый запрос возвращает все чаты
#[test]
fn test_search_empty_query_returns_all() {
let mut client = FakeTdClient::new();
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Boss", 456);
let chat3 = create_test_chat("Friend", 789);
client = client.with_chats(vec![chat1, chat2, chat3]);
// Пустой запрос
let query = "";
let filtered: Vec<_> = client
.get_chats()
.iter()
.filter(|c| c.title.to_lowercase().contains(query))
.collect();
// Все чаты проходят фильтр (пустая строка содержится в любой строке)
assert_eq!(filtered.len(), 3);
}
/// Test: Поиск внутри чата по тексту сообщений
#[test]
fn test_search_messages_in_chat() {
let mut client = FakeTdClient::new();
let msg1 = TestMessageBuilder::new("Hello world", 100).build();
let msg2 = TestMessageBuilder::new("How are you?", 101).build();
let msg3 = TestMessageBuilder::new("Hello again", 102).build();
client = client.with_messages(123, vec![msg1, msg2, msg3]);
// Ищем "hello"
let query = "hello".to_lowercase();
let messages = client.get_messages(123);
let found: Vec<_> = messages
.iter()
.filter(|m| m.content.to_lowercase().contains(&query))
.collect();
assert_eq!(found.len(), 2);
assert_eq!(found[0].content, "Hello world");
assert_eq!(found[1].content, "Hello again");
}
/// Test: Навигация по результатам поиска (n/N)
#[test]
fn test_navigate_search_results() {
let mut client = FakeTdClient::new();
let msg1 = TestMessageBuilder::new("First match", 100).build();
let msg2 = TestMessageBuilder::new("Second match", 101).build();
let msg3 = TestMessageBuilder::new("Third match", 102).build();
client = client.with_messages(123, vec![msg1, msg2, msg3]);
// Ищем "match"
let query = "match".to_lowercase();
let messages = client.get_messages(123);
let results: Vec<_> = messages
.iter()
.enumerate()
.filter(|(_, m)| m.content.to_lowercase().contains(&query))
.collect();
assert_eq!(results.len(), 3);
// Навигация: начинаем с индекса 0
let mut current_index = 0;
// n - следующий результат
current_index = (current_index + 1) % results.len();
assert_eq!(current_index, 1);
assert_eq!(results[current_index].1.content, "Second match");
// n - ещё один
current_index = (current_index + 1) % results.len();
assert_eq!(current_index, 2);
assert_eq!(results[current_index].1.content, "Third match");
// n - wrap around к первому
current_index = (current_index + 1) % results.len();
assert_eq!(current_index, 0);
assert_eq!(results[current_index].1.content, "First match");
// N - предыдущий (wrap to last)
current_index = if current_index == 0 {
results.len() - 1
} else {
current_index - 1
};
assert_eq!(current_index, 2);
assert_eq!(results[current_index].1.content, "Third match");
}
/// Test: Поиск с учётом регистра (case-insensitive)
#[test]
fn test_search_case_insensitive() {
let mut client = FakeTdClient::new();
let msg1 = TestMessageBuilder::new("HELLO", 100).build();
let msg2 = TestMessageBuilder::new("hello", 101).build();
let msg3 = TestMessageBuilder::new("HeLLo", 102).build();
client = client.with_messages(123, vec![msg1, msg2, msg3]);
// Ищем "hello" (lowercase)
let query = "hello".to_lowercase();
let messages = client.get_messages(123);
let found: Vec<_> = messages
.iter()
.filter(|m| m.content.to_lowercase().contains(&query))
.collect();
// Все 3 варианта должны найтись
assert_eq!(found.len(), 3);
}
/// Test: Поиск не находит ничего
#[test]
fn test_search_no_results() {
let mut client = FakeTdClient::new();
let msg1 = TestMessageBuilder::new("Hello", 100).build();
let msg2 = TestMessageBuilder::new("World", 101).build();
client = client.with_messages(123, vec![msg1, msg2]);
// Ищем "xyz" - не должно найтись
let query = "xyz".to_lowercase();
let messages = client.get_messages(123);
let found: Vec<_> = messages
.iter()
.filter(|m| m.content.to_lowercase().contains(&query))
.collect();
assert_eq!(found.len(), 0);
}
/// Test: Отмена поиска (Esc) восстанавливает обычный режим
#[test]
fn test_cancel_search_restores_normal_mode() {
let mut client = FakeTdClient::new();
let chat1 = create_test_chat("Mom", 123);
let chat2 = create_test_chat("Boss", 456);
client = client.with_chats(vec![chat1, chat2]);
// Симулируем: пользователь начал поиск
let mut is_searching = true;
let mut search_query = "mom".to_string();
// Фильтруем
let query = search_query.to_lowercase();
let filtered: Vec<_> = client
.get_chats()
.iter()
.filter(|c| c.title.to_lowercase().contains(&query))
.collect();
assert_eq!(filtered.len(), 1);
// Пользователь нажал Esc
is_searching = false;
search_query.clear();
// После отмены видим все чаты
let all_chats = client.get_chats();
assert_eq!(all_chats.len(), 2);
assert!(!is_searching);
assert_eq!(search_query, "");
}