//! Test utilities for Tauri command integration tests. //! //! Provides setup helpers for creating test state with in-memory SQLite database. use std::sync::Arc; use goingson_core::{ProjectId, UserId}; use goingson_db_sqlite::{ init_pool, run_migrations, SqliteAttachmentRepository, SqliteBackupSettingsRepository, SqliteContactRepository, SqliteDailyNoteRepository, SqliteEmailAccountRepository, SqliteEmailRepository, SqliteEventRepository, SqliteMilestoneRepository, SqliteProjectRepository, SqliteSavedViewRepository, SqliteMonthlyReviewRepository, SqliteSearchRepository, SqliteStatsRepository, SqliteSyncAccountRepository, SqliteTaskRepository, SqliteWeeklyReviewRepository, }; use sqlx::SqlitePool; use crate::state::AppState; /// Creates an in-memory test database with all migrations applied. pub async fn setup_test_db() -> SqlitePool { let pool = init_pool(Some(":memory:")) .await .expect("Failed to create in-memory pool"); run_migrations(&pool) .await .expect("Failed to run migrations"); pool } /// Creates a test user and returns their ID. pub async fn create_test_user(pool: &SqlitePool) -> UserId { let user_id = UserId::new(); let now = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); sqlx::query( "INSERT INTO users (id, email, password_hash, display_name, created_at) VALUES (?, ?, ?, ?, ?)" ) .bind(user_id.to_string()) .bind(format!("test-{}@example.com", user_id)) .bind("test-password-hash") .bind("Test User") .bind(&now) .execute(pool) .await .expect("Failed to create test user"); user_id } /// Creates a fully initialized AppState with in-memory database for testing. pub async fn setup_test_state() -> (Arc, UserId) { let pool = setup_test_db().await; let user_id = create_test_user(&pool).await; let state = AppState { pool: pool.clone(), projects: Arc::new(SqliteProjectRepository::new(pool.clone())), tasks: Arc::new(SqliteTaskRepository::new(pool.clone())), events: Arc::new(SqliteEventRepository::new(pool.clone())), emails: Arc::new(SqliteEmailRepository::new(pool.clone())), email_accounts: Arc::new(SqliteEmailAccountRepository::new(pool.clone())), contacts: Arc::new(SqliteContactRepository::new(pool.clone())), daily_notes: Arc::new(SqliteDailyNoteRepository::new(pool.clone())), attachments: Arc::new(SqliteAttachmentRepository::new(pool.clone())), stats: Arc::new(SqliteStatsRepository::new(pool.clone())), search: Arc::new(SqliteSearchRepository::new(pool.clone())), milestones: Arc::new(SqliteMilestoneRepository::new(pool.clone())), saved_views: Arc::new(SqliteSavedViewRepository::new(pool.clone())), weekly_reviews: Arc::new(SqliteWeeklyReviewRepository::new(pool.clone())), monthly_reviews: Arc::new(SqliteMonthlyReviewRepository::new(pool.clone())), backup_settings: Arc::new(SqliteBackupSettingsRepository::new(pool.clone())), sync_accounts: Arc::new(SqliteSyncAccountRepository::new(pool.clone())), sync_client: std::sync::RwLock::new(None), sync_lock: Arc::new(tokio::sync::Mutex::new(())), email_sync_locks: Arc::new(std::sync::Mutex::new(std::collections::HashSet::new())), token_refresh_locks: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())), pending_oauth_flows: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())), data_dir: std::path::PathBuf::from("/tmp/goingson-test"), }; (Arc::new(state), user_id) } /// Creates a test project and returns its ID. pub async fn create_test_project(state: &AppState, user_id: UserId) -> ProjectId { use goingson_core::{NewProject, ProjectStatus, ProjectType}; let new_project = NewProject { name: "Test Project".to_string(), description: "A test project".to_string(), project_type: ProjectType::SideProject, status: ProjectStatus::Active, }; let project = state .projects .create(user_id, new_project) .await .expect("Failed to create test project"); project.id }