|
| 1 | +//! db_contracts 单测(内存库;AAA 模式)。 |
| 2 | +
|
| 3 | +use crate::db::Db; |
| 4 | +use crate::db_flashcards::NewFlashcard; |
| 5 | +use crate::types::NewNoteGroup; |
| 6 | +use crate::week_contract::week_start_secs; |
| 7 | + |
| 8 | +/// 内存库。 |
| 9 | +fn mem_db() -> Db { |
| 10 | + Db::open(":memory:").expect("内存库打开") |
| 11 | +} |
| 12 | + |
| 13 | +/// 建组助手(contracts/flashcards 外键前置)。 |
| 14 | +fn make_group(db: &Db, name: &str) -> crate::types::NoteGroup { |
| 15 | + db.create_group(&NewNoteGroup { |
| 16 | + name: name.to_string(), |
| 17 | + terrain: "container".to_string(), |
| 18 | + kind: "standalone".to_string(), |
| 19 | + domain_tag: None, |
| 20 | + source: "manual".to_string(), |
| 21 | + series_key: None, |
| 22 | + route_reason: None, |
| 23 | + }) |
| 24 | + .expect("group") |
| 25 | +} |
| 26 | + |
| 27 | +/// 建卡助手(review_logs 外键前置;新卡 due 不限制)。 |
| 28 | +fn make_card(db: &Db, group_id: i64, front: &str) -> crate::types::Flashcard { |
| 29 | + db.create_card(&NewFlashcard { |
| 30 | + group_id, |
| 31 | + note_id: None, |
| 32 | + fragment_id: None, |
| 33 | + front: front.to_string(), |
| 34 | + back: "验证材料".to_string(), |
| 35 | + kind: "fact".to_string(), |
| 36 | + state_json: "{}".to_string(), |
| 37 | + due_at: 0, |
| 38 | + }) |
| 39 | + .expect("card") |
| 40 | +} |
| 41 | + |
| 42 | +#[test] |
| 43 | +fn upsert_creates_and_overrides_this_week() { |
| 44 | + // Arrange |
| 45 | + let db = mem_db(); |
| 46 | + let group = make_group(&db, "契约组"); |
| 47 | + let ws = week_start_secs(1_767_225_600); |
| 48 | + // Act:首次写入 → 再次写入覆盖(幂等语义) |
| 49 | + let c1 = db |
| 50 | + .upsert_week_contract(group.id, ws, 3, 15) |
| 51 | + .expect("first"); |
| 52 | + let c2 = db |
| 53 | + .upsert_week_contract(group.id, ws, 5, 30) |
| 54 | + .expect("override"); |
| 55 | + // Assert:同周同组仅一份契约,目标值已覆盖 |
| 56 | + let fetched = db.get_week_contract(group.id, ws).expect("get"); |
| 57 | + let fetched = fetched.expect("契约应存在"); |
| 58 | + assert_eq!(fetched.id, c1.id); |
| 59 | + assert_eq!(fetched.target_days, 5); |
| 60 | + assert_eq!(fetched.target_cards, 30); |
| 61 | + assert_ne!(fetched.created_at, c2.created_at); // created_at 刷新 |
| 62 | +} |
| 63 | + |
| 64 | +#[test] |
| 65 | +fn different_weeks_coexist() { |
| 66 | + // Arrange |
| 67 | + let db = mem_db(); |
| 68 | + let group = make_group(&db, "双周组"); |
| 69 | + let wk1 = week_start_secs(1_767_225_600); |
| 70 | + let wk2 = wk1 + 604_800; // 下一周 |
| 71 | + // Act:两周各立一约 |
| 72 | + db.upsert_week_contract(group.id, wk1, 2, 10).expect("wk1"); |
| 73 | + db.upsert_week_contract(group.id, wk2, 4, 20).expect("wk2"); |
| 74 | + // Assert:互不覆盖 |
| 75 | + assert_eq!(db.get_week_contract(group.id, wk1).expect("g1").expect("c1").target_cards, 10); |
| 76 | + assert_eq!(db.get_week_contract(group.id, wk2).expect("g2").expect("c2").target_cards, 20); |
| 77 | +} |
| 78 | + |
| 79 | +#[test] |
| 80 | +fn missing_contract_returns_none() { |
| 81 | + // Arrange:组存在但从未立约 |
| 82 | + let db = mem_db(); |
| 83 | + let group = make_group(&db, "无约组"); |
| 84 | + // Act/Assert:诚实 None(UI 显示设定表单) |
| 85 | + assert!(db.get_week_contract(group.id, week_start_secs(1_767_225_600)).expect("get").is_none()); |
| 86 | +} |
| 87 | + |
| 88 | +#[test] |
| 89 | +fn review_ats_in_week_filters_group_and_range() { |
| 90 | + // Arrange:两组各一卡;本周 3 次复习 + 下周 1 次 |
| 91 | + let db = mem_db(); |
| 92 | + let g1 = make_group(&db, "组一"); |
| 93 | + let g2 = make_group(&db, "组二"); |
| 94 | + let card1 = make_card(&db, g1.id, "卡一"); |
| 95 | + let card2 = make_card(&db, g2.id, "卡二"); |
| 96 | + let ws = week_start_secs(1_767_225_600); |
| 97 | + db.add_review_log(card1.id, "good", ws + 3_600).expect("r1"); // 本周 |
| 98 | + db.add_review_log(card1.id, "good", ws + 86_400).expect("r2"); // 本周 |
| 99 | + db.add_review_log(card2.id, "easy", ws + 43_200).expect("r3"); // 本周·他组 |
| 100 | + db.add_review_log(card1.id, "again", ws + 604_800 + 100).expect("r4"); // 下周 |
| 101 | + // Act |
| 102 | + let ats = db.review_ats_in_week(g1.id, ws).expect("query"); |
| 103 | + // Assert:仅组一本周 2 条(下周归下周、他组不计) |
| 104 | + assert_eq!(ats.len(), 2); |
| 105 | + assert!(ats.contains(&(ws + 3_600))); |
| 106 | + assert!(ats.contains(&(ws + 86_400))); |
| 107 | +} |
| 108 | + |
| 109 | +#[test] |
| 110 | +fn upsert_rejects_unknown_group() { |
| 111 | + // Arrange:不存在的组 id |
| 112 | + let db = mem_db(); |
| 113 | + // Act/Assert:外键约束报错(不静默写孤儿契约) |
| 114 | + assert!(db.upsert_week_contract(9999, 0, 3, 15).is_err()); |
| 115 | +} |
0 commit comments