Skip to main content

max / goingson

4.0 KB · 133 lines History Blame Raw
1 //! Integration tests for SqliteDailyNoteRepository.
2
3 mod common;
4
5 use chrono::NaiveDate;
6 use goingson_core::DailyNoteRepository;
7 use goingson_db_sqlite::SqliteDailyNoteRepository;
8
9 fn date(y: i32, m: u32, d: u32) -> NaiveDate {
10 NaiveDate::from_ymd_opt(y, m, d).unwrap()
11 }
12
13 #[tokio::test]
14 async fn upsert_then_get_by_date_roundtrips() {
15 let pool = common::setup_test_db().await;
16 let user_id = common::create_test_user(&pool).await;
17 let repo = SqliteDailyNoteRepository::new(pool.clone());
18 let d = date(2026, 3, 15);
19
20 let created = repo
21 .upsert(
22 user_id,
23 d,
24 "shipped the audit",
25 "less context switching",
26 false,
27 )
28 .await
29 .unwrap();
30 assert_eq!(created.note_date, d);
31 assert_eq!(created.went_well, "shipped the audit");
32 assert_eq!(created.could_improve, "less context switching");
33 assert!(!created.is_reviewed);
34 assert!(created.reviewed_at.is_none());
35
36 let fetched = repo.get_by_date(user_id, d).await.unwrap().unwrap();
37 assert_eq!(fetched.id, created.id);
38 assert_eq!(fetched.went_well, "shipped the audit");
39 }
40
41 #[tokio::test]
42 async fn get_by_date_missing_is_none() {
43 let pool = common::setup_test_db().await;
44 let user_id = common::create_test_user(&pool).await;
45 let repo = SqliteDailyNoteRepository::new(pool.clone());
46
47 assert!(
48 repo.get_by_date(user_id, date(2026, 1, 1))
49 .await
50 .unwrap()
51 .is_none()
52 );
53 }
54
55 #[tokio::test]
56 async fn upsert_conflict_updates_in_place_and_preserves_id_and_created_at() {
57 let pool = common::setup_test_db().await;
58 let user_id = common::create_test_user(&pool).await;
59 let repo = SqliteDailyNoteRepository::new(pool.clone());
60 let d = date(2026, 5, 1);
61
62 let first = repo.upsert(user_id, d, "a", "b", false).await.unwrap();
63 let second = repo
64 .upsert(user_id, d, "updated", "improved", true)
65 .await
66 .unwrap();
67
68 // Same (user, date) folds into an update, not a second row.
69 assert_eq!(second.id, first.id, "id preserved on conflict path");
70 assert_eq!(second.created_at, first.created_at, "created_at preserved");
71 assert_eq!(second.went_well, "updated");
72 assert_eq!(second.could_improve, "improved");
73 assert!(second.is_reviewed);
74 assert!(
75 second.reviewed_at.is_some(),
76 "reviewed_at set when is_reviewed"
77 );
78
79 // Exactly one row exists for this user.
80 let all = repo.list_all(user_id).await.unwrap();
81 assert_eq!(all.len(), 1);
82 }
83
84 #[tokio::test]
85 async fn list_all_is_ordered_by_note_date_ascending() {
86 let pool = common::setup_test_db().await;
87 let user_id = common::create_test_user(&pool).await;
88 let repo = SqliteDailyNoteRepository::new(pool.clone());
89
90 repo.upsert(user_id, date(2026, 3, 10), "c", "", false)
91 .await
92 .unwrap();
93 repo.upsert(user_id, date(2026, 3, 1), "a", "", false)
94 .await
95 .unwrap();
96 repo.upsert(user_id, date(2026, 3, 5), "b", "", false)
97 .await
98 .unwrap();
99
100 let all = repo.list_all(user_id).await.unwrap();
101 let dates: Vec<NaiveDate> = all.iter().map(|n| n.note_date).collect();
102 assert_eq!(
103 dates,
104 vec![date(2026, 3, 1), date(2026, 3, 5), date(2026, 3, 10)]
105 );
106 }
107
108 #[tokio::test]
109 async fn list_all_is_scoped_per_user() {
110 let pool = common::setup_test_db().await;
111 let user_a = common::create_test_user(&pool).await;
112 let user_b = common::create_test_user(&pool).await;
113 let repo = SqliteDailyNoteRepository::new(pool.clone());
114
115 repo.upsert(user_a, date(2026, 2, 1), "a-note", "", false)
116 .await
117 .unwrap();
118 repo.upsert(user_b, date(2026, 2, 1), "b-note", "", false)
119 .await
120 .unwrap();
121
122 let a = repo.list_all(user_a).await.unwrap();
123 assert_eq!(a.len(), 1);
124 assert_eq!(a[0].went_well, "a-note");
125 // user_b's identically-dated note does not leak into user_a's listing.
126 assert!(
127 repo.get_by_date(user_a, date(2026, 2, 1))
128 .await
129 .unwrap()
130 .is_some()
131 );
132 }
133