//! 搜索功能专项测试 use rust_user_api::{ models::{ user::User, search::UserSearchParams, pagination::PaginationParams, }, storage::{database::DatabaseUserStore, memory::MemoryUserStore, UserStore}, utils::errors::ApiError, }; use uuid::Uuid; use chrono::Utc; /// 创建测试用户 fn create_test_user(username: &str, email: &str) -> User { User { id: Uuid::new_v4(), username: username.to_string(), email: email.to_string(), password_hash: "hashed_password".to_string(), created_at: Utc::now(), updated_at: Utc::now(), } } /// 创建多个测试用户用于搜索 async fn create_search_test_users(store: &dyn UserStore) -> Vec { let users = vec![ create_test_user("admin_user", "admin@company.com"), create_test_user("john_doe", "john@example.com"), create_test_user("jane_smith", "jane@company.com"), create_test_user("admin_root", "root@admin.com"), create_test_user("test_user", "test@example.com"), create_test_user("manager_bob", "bob@company.com"), ]; let mut created_users = Vec::new(); for user in users { let created = store.create_user(user).await.unwrap(); created_users.push(created); // 添加小延迟确保创建时间不同 tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; } created_users } /// 测试内存存储的通用搜索功能 #[tokio::test] async fn test_memory_store_general_search() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 搜索包含"admin"的用户 let search_params = UserSearchParams { q: Some("admin".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 2, "应该找到2个包含admin的用户"); assert_eq!(results.len(), 2, "结果应该包含2个用户"); // 验证搜索结果 for user in &results { assert!( user.username.contains("admin") || user.email.contains("admin"), "搜索结果应该包含admin关键词" ); } } /// 测试数据库存储的通用搜索功能 #[tokio::test] async fn test_database_store_general_search() { let database_url = "sqlite::memory:"; let store = DatabaseUserStore::from_url(database_url).await.unwrap(); let _users = create_search_test_users(&store).await; // 搜索包含"company"的用户 let search_params = UserSearchParams { q: Some("company".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 3, "应该找到3个包含company的用户"); assert_eq!(results.len(), 3, "结果应该包含3个用户"); // 验证搜索结果 for user in &results { assert!( user.username.contains("company") || user.email.contains("company"), "搜索结果应该包含company关键词" ); } } /// 测试用户名过滤 #[tokio::test] async fn test_username_filter() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 按用户名过滤 let search_params = UserSearchParams { username: Some("admin".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 2, "应该找到2个用户名包含admin的用户"); for user in &results { assert!( user.username.to_lowercase().contains("admin"), "用户名应该包含admin" ); } } /// 测试邮箱过滤 #[tokio::test] async fn test_email_filter() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 按邮箱域名过滤 let search_params = UserSearchParams { email: Some("example.com".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 2, "应该找到2个example.com域名的用户"); for user in &results { assert!( user.email.contains("example.com"), "邮箱应该包含example.com" ); } } /// 测试排序功能 #[tokio::test] async fn test_search_sorting() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 按用户名升序排序 let search_params = UserSearchParams { sort_by: Some("username".to_string()), sort_order: Some("asc".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, _) = store.search_users(&search_params, &pagination_params).await.unwrap(); // 验证排序 for i in 0..results.len() - 1 { assert!( results[i].username <= results[i + 1].username, "结果应该按用户名升序排列" ); } // 测试降序排序 let search_params = UserSearchParams { sort_by: Some("username".to_string()), sort_order: Some("desc".to_string()), ..Default::default() }; let (results, _) = store.search_users(&search_params, &pagination_params).await.unwrap(); // 验证降序排序 for i in 0..results.len() - 1 { assert!( results[i].username >= results[i + 1].username, "结果应该按用户名降序排列" ); } } /// 测试搜索参数验证 #[tokio::test] async fn test_search_params_validation() { let search_params = UserSearchParams { sort_by: Some("invalid_field".to_string()), sort_order: Some("asc".to_string()), ..Default::default() }; assert!(!search_params.is_valid_sort_field(), "无效的排序字段应该被拒绝"); let search_params = UserSearchParams { sort_by: Some("username".to_string()), sort_order: Some("invalid_order".to_string()), ..Default::default() }; assert!(!search_params.is_valid_sort_order(), "无效的排序方向应该被拒绝"); // 测试有效参数 let search_params = UserSearchParams { sort_by: Some("username".to_string()), sort_order: Some("asc".to_string()), ..Default::default() }; assert!(search_params.is_valid_sort_field(), "有效的排序字段应该被接受"); assert!(search_params.is_valid_sort_order(), "有效的排序方向应该被接受"); } /// 测试搜索分页功能 #[tokio::test] async fn test_search_with_pagination() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 搜索所有用户,第一页 let search_params = UserSearchParams::default(); let pagination_params = PaginationParams { page: Some(1), limit: Some(3), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 6, "总共应该有6个用户"); assert_eq!(results.len(), 3, "第一页应该有3个用户"); // 第二页 let pagination_params = PaginationParams { page: Some(2), limit: Some(3), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 6, "总数应该保持一致"); assert_eq!(results.len(), 3, "第二页应该有3个用户"); // 第三页(超出范围) let pagination_params = PaginationParams { page: Some(3), limit: Some(3), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 6, "总数应该保持一致"); assert_eq!(results.len(), 0, "第三页应该没有用户"); } /// 测试复合搜索条件 #[tokio::test] async fn test_complex_search() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 搜索用户名包含"admin"且邮箱包含"company"的用户 let search_params = UserSearchParams { username: Some("admin".to_string()), email: Some("company".to_string()), sort_by: Some("username".to_string()), sort_order: Some("asc".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 1, "应该找到1个同时满足条件的用户"); assert_eq!(results.len(), 1, "结果应该包含1个用户"); let user = &results[0]; assert!(user.username.contains("admin"), "用户名应该包含admin"); assert!(user.email.contains("company"), "邮箱应该包含company"); } /// 测试空搜索结果 #[tokio::test] async fn test_empty_search_results() { let store = MemoryUserStore::new(); let _users = create_search_test_users(&store).await; // 搜索不存在的关键词 let search_params = UserSearchParams { q: Some("nonexistent".to_string()), ..Default::default() }; let pagination_params = PaginationParams { page: Some(1), limit: Some(10), }; let (results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap(); assert_eq!(total_count, 0, "应该没有找到任何用户"); assert_eq!(results.len(), 0, "结果应该为空"); } /// 测试搜索参数默认值 #[tokio::test] async fn test_search_params_defaults() { let search_params = UserSearchParams::default(); assert_eq!(search_params.get_sort_by(), "created_at", "默认排序字段应该是created_at"); assert_eq!(search_params.get_sort_order(), "desc", "默认排序方向应该是desc"); assert!(!search_params.has_filters(), "默认参数不应该有过滤条件"); } /// 测试搜索参数的has_filters方法 #[tokio::test] async fn test_search_params_has_filters() { let search_params = UserSearchParams { q: Some("test".to_string()), ..Default::default() }; assert!(search_params.has_filters(), "有搜索关键词时应该返回true"); let search_params = UserSearchParams { username: Some("test".to_string()), ..Default::default() }; assert!(search_params.has_filters(), "有用户名过滤时应该返回true"); let search_params = UserSearchParams { email: Some("test".to_string()), ..Default::default() }; assert!(search_params.has_filters(), "有邮箱过滤时应该返回true"); let search_params = UserSearchParams::default(); assert!(!search_params.has_filters(), "默认参数应该返回false"); }