package rond import "testing" func TestBuildMergePlanPicks(t *testing.T) { vd := VisitDiff{ Added: []Visit{{SrcPK: 900, Arrival: tp("2026-09-09 10:00")}}, Removed: []StoredVisit{{SrcPK: 5, UUID: uuidA}}, Changed: []VisitConflict{ {Backup: Visit{SrcPK: 901, Arrival: tp("2026-09-01 12:00")}, DB: StoredVisit{SrcPK: 1, UUID: uuidA}}, {Backup: Visit{SrcPK: 902, Arrival: tp("2026-09-02 12:00")}, DB: StoredVisit{SrcPK: 2, UUID: uuidB}}, }, } pd := PlaceDiff{Added: []Location{{SrcPK: 3, Name: "新地点"}}} ad := ActivityDiff{Added: []Activity{{SrcPK: 8, Name: "散步"}}} p := BuildMergePlan(vd, pd, ad, Choices{ AddVisits: true, AddPlaces: true, AddActs: false, VisitClash: map[string]string{uuidA: PickBackup, uuidB: PickDB}, }) if len(p.AddVisits) != 1 || p.AddVisits[0].SrcPK != 900 { t.Fatalf("新增到访应合入一条: %+v", p.AddVisits) } if len(p.UpdVisits) != 1 || p.UpdVisits[0].UUID != uuidA { t.Fatalf("只有选了「用实机」的那条才该更新: %+v", p.UpdVisits) } if len(p.AddPlaces) != 1 { t.Fatalf("勾了「并进来」就该带上新增地点: %d", len(p.AddPlaces)) } // 即使没单独勾活动,合入到访时也要把它可能挂着的「库里还没有的活动」带上, // 否则那条到访的 activity_id 无从映射,只能整条丢掉。 if len(p.AddActs) != 1 || p.AddActs[0].Name != "散步" { t.Fatalf("合入到访应连带它需要的活动: %+v", p.AddActs) } // 「仅站内有」永远不进计划:删除是单独的事,绝不顺手做 if len(p.UpdPlaces)+len(p.UpdActs) != 0 { t.Fatal("不该有地点/活动更新") } } // 没提交的键、或提交了怪值,一律当成「保留站内」——不误伤。 func TestBuildMergePlanDefaultsToKeepDB(t *testing.T) { vd := VisitDiff{Changed: []VisitConflict{ {Backup: Visit{SrcPK: 901}, DB: StoredVisit{SrcPK: 1, UUID: uuidA}}, }} p := BuildMergePlan(vd, PlaceDiff{}, ActivityDiff{}, Choices{VisitClash: map[string]string{uuidA: "wat"}}) if len(p.UpdVisits) != 0 { t.Fatalf("怪值不该被当成「用实机」: %+v", p.UpdVisits) } if !p.Empty() { t.Fatal("什么都没选,计划应当是空的") } } // 冲突选了「跳过」也不动。 func TestBuildMergePlanSkip(t *testing.T) { vd := VisitDiff{Changed: []VisitConflict{ {Backup: Visit{SrcPK: 901}, DB: StoredVisit{SrcPK: 1, UUID: uuidA}}, }} p := BuildMergePlan(vd, PlaceDiff{}, ActivityDiff{}, Choices{VisitClash: map[string]string{uuidA: PickSkip}}) if !p.Empty() { t.Fatalf("跳过就不该产生改动: %+v", p) } } // 活动改了名也要能用 UUID 当键对得上。 func TestActivityKeyPrefersUUID(t *testing.T) { if got := ActivityKey(StoredActivity{SrcPK: 1, Name: "上班", UUID: uuidC}); got != uuidC { t.Fatalf("有 UUID 就用 UUID,实际 %q", got) } if got := ActivityKey(StoredActivity{SrcPK: 1, Name: "上班"}); got != "n:上班" { t.Fatalf("没有 UUID 退回名称,实际 %q", got) } }