//! Integration tests for SqliteDailyNoteRepository. mod common; use chrono::NaiveDate; use goingson_core::DailyNoteRepository; use goingson_db_sqlite::SqliteDailyNoteRepository; fn date(y: i32, m: u32, d: u32) -> NaiveDate { NaiveDate::from_ymd_opt(y, m, d).unwrap() } #[tokio::test] async fn upsert_then_get_by_date_roundtrips() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteDailyNoteRepository::new(pool.clone()); let d = date(2026, 3, 15); let created = repo .upsert( user_id, d, "shipped the audit", "less context switching", false, ) .await .unwrap(); assert_eq!(created.note_date, d); assert_eq!(created.went_well, "shipped the audit"); assert_eq!(created.could_improve, "less context switching"); assert!(!created.is_reviewed); assert!(created.reviewed_at.is_none()); let fetched = repo.get_by_date(user_id, d).await.unwrap().unwrap(); assert_eq!(fetched.id, created.id); assert_eq!(fetched.went_well, "shipped the audit"); } #[tokio::test] async fn get_by_date_missing_is_none() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteDailyNoteRepository::new(pool.clone()); assert!( repo.get_by_date(user_id, date(2026, 1, 1)) .await .unwrap() .is_none() ); } #[tokio::test] async fn upsert_conflict_updates_in_place_and_preserves_id_and_created_at() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteDailyNoteRepository::new(pool.clone()); let d = date(2026, 5, 1); let first = repo.upsert(user_id, d, "a", "b", false).await.unwrap(); let second = repo .upsert(user_id, d, "updated", "improved", true) .await .unwrap(); // Same (user, date) folds into an update, not a second row. assert_eq!(second.id, first.id, "id preserved on conflict path"); assert_eq!(second.created_at, first.created_at, "created_at preserved"); assert_eq!(second.went_well, "updated"); assert_eq!(second.could_improve, "improved"); assert!(second.is_reviewed); assert!( second.reviewed_at.is_some(), "reviewed_at set when is_reviewed" ); // Exactly one row exists for this user. let all = repo.list_all(user_id).await.unwrap(); assert_eq!(all.len(), 1); } #[tokio::test] async fn list_all_is_ordered_by_note_date_ascending() { let pool = common::setup_test_db().await; let user_id = common::create_test_user(&pool).await; let repo = SqliteDailyNoteRepository::new(pool.clone()); repo.upsert(user_id, date(2026, 3, 10), "c", "", false) .await .unwrap(); repo.upsert(user_id, date(2026, 3, 1), "a", "", false) .await .unwrap(); repo.upsert(user_id, date(2026, 3, 5), "b", "", false) .await .unwrap(); let all = repo.list_all(user_id).await.unwrap(); let dates: Vec = all.iter().map(|n| n.note_date).collect(); assert_eq!( dates, vec![date(2026, 3, 1), date(2026, 3, 5), date(2026, 3, 10)] ); } #[tokio::test] async fn list_all_is_scoped_per_user() { let pool = common::setup_test_db().await; let user_a = common::create_test_user(&pool).await; let user_b = common::create_test_user(&pool).await; let repo = SqliteDailyNoteRepository::new(pool.clone()); repo.upsert(user_a, date(2026, 2, 1), "a-note", "", false) .await .unwrap(); repo.upsert(user_b, date(2026, 2, 1), "b-note", "", false) .await .unwrap(); let a = repo.list_all(user_a).await.unwrap(); assert_eq!(a.len(), 1); assert_eq!(a[0].went_well, "a-note"); // user_b's identically-dated note does not leak into user_a's listing. assert!( repo.get_by_date(user_a, date(2026, 2, 1)) .await .unwrap() .is_some() ); }