Files
rond-with-you/internal/fog/diff_test.go
T
tamakyi 30c502ce7b 备份与迷雾的差异分析、合并执行,附属数据改挂坐标键
备份(.rondbackup)与迷雾(.fwss)各加一层「先看差异再动手」:

- 迷雾:上传先出差异页,说清叠加能补多少、整体替换会丢多少,并在真实底图上
  用绿/灰/红标出会新增 / 不变 / 会丢的区域
- 备份:与当前数据集按 UUID 逐条比对(rond 每次导出都会重排 Z_PK,编号认不出人),
  新增合入、冲突逐条选、仅站内有逐条勾选删除,全在一个事务里执行;
  合入的行写回 entity_raw,保证再传同一份备份时差异归零
- 地点按坐标对齐:站点的「补全地址」会把地点改名,拿名称当键会让一整个地点的
  到访全变成假冲突
- 附属数据(备注/结论/访客票/图片)从 dataset_id+src_pk 换成坐标键,换数据集不再失联;
  访客票没有 dataset_id,回填按活跃数据集认领
- 修正 contentHash 拿 Z_PK 当指纹的隐患,以及两处「src_pk 跨快照稳定」的错误注释

导出格式(.rondbackup / .fwss)保持原样,往返测试通过。
2026-09-19 16:04:00 +08:00

89 lines
2.9 KiB
Go

package fog
import "testing"
// blk 造一个块,cells 是块内的 (列, 行) 坐标。
func blk(gx, gy int, cells ...[2]int) Block {
bm := make([]byte, bitmapSize)
for _, c := range cells {
bm[c[1]*8+c[0]/8] |= 0x80 >> (c[0] % 8)
}
return Block{GX: gx, GY: gy, Bitmap: bm}
}
func TestDiffEmptyBase(t *testing.T) {
d := DiffBlocks(nil, []Block{blk(10, 20, [2]int{0, 0}, [2]int{1, 0})})
if d.CurBlocks != 0 || d.CurCells != 0 {
t.Fatalf("空库不该有现有数据: %+v", d)
}
if d.GainBlocks != 1 || d.GainCells != 2 || d.IncCells != 2 {
t.Fatalf("空库叠加应为全部新增: %+v", d)
}
if d.LostBlocks != 0 || d.LostCells != 0 || !d.Changed() {
t.Fatalf("空库不该有丢失: %+v", d)
}
}
func TestDiffIdentical(t *testing.T) {
cur := []Block{blk(10, 20, [2]int{0, 0}, [2]int{1, 0}), blk(11, 20, [2]int{5, 5})}
d := DiffBlocks(cur, cur)
if d.GainCells != 0 || d.Changed() {
t.Fatalf("同一份快照再叠一次不该有任何新增: %+v", d)
}
if d.LostBlocks != 0 || d.LostCells != 0 {
t.Fatalf("同一份快照不该有可丢的部分: %+v", d)
}
if d.OverlapBlocks != 2 || d.SameBlocks != 2 {
t.Fatalf("两个块都应算作「重叠且无变化」: %+v", d)
}
}
func TestDiffOverlapGain(t *testing.T) {
d := DiffBlocks(
[]Block{blk(10, 20, [2]int{0, 0})},
[]Block{blk(10, 20, [2]int{0, 0}, [2]int{3, 4})})
if d.GainBlocks != 0 || d.GainCells != 1 {
t.Fatalf("重叠块应只补亮多出的那一格: %+v", d)
}
if d.OverlapBlocks != 1 || d.SameBlocks != 0 {
t.Fatalf("重叠但补亮了,不该记为无变化: %+v", d)
}
if d.LostBlocks != 0 {
t.Fatalf("同一个块不该被判为会丢失: %+v", d)
}
}
func TestDiffDisjoint(t *testing.T) {
d := DiffBlocks(
[]Block{blk(10, 20, [2]int{0, 0})},
[]Block{blk(30, 40, [2]int{1, 1})})
if d.GainBlocks != 1 || d.GainCells != 1 {
t.Fatalf("另一块应是新增: %+v", d)
}
if d.LostBlocks != 1 || d.LostCells != 1 {
t.Fatalf("库里那块在快照里没有,整体替换会丢掉: %+v", d)
}
}
// 面积按块中心纬度做 cos 修正,越靠近两极越小;总量关系也要自洽。
func TestDiffAreas(t *testing.T) {
equator := DiffBlocks(nil, []Block{blk(100, WorldCells/BlockCells/2, [2]int{1, 1})})
high := DiffBlocks(nil, []Block{blk(100, 20000, [2]int{1, 1})})
if high.GainAreaKm2() <= 0 {
t.Fatalf("高纬单格面积应为正: %v", high.GainAreaKm2())
}
if !(equator.GainAreaKm2() > high.GainAreaKm2()) {
t.Fatalf("赤道单格应大于高纬: %v vs %v", equator.GainAreaKm2(), high.GainAreaKm2())
}
m := DiffBlocks(
[]Block{blk(10, 20, [2]int{0, 0})},
[]Block{blk(10, 20, [2]int{0, 0}, [2]int{9, 9})})
if diff := m.MergeAreaKm2() - (m.CurAreaKm2() + m.GainAreaKm2()); diff > 1e-12 || diff < -1e-12 {
t.Fatalf("叠加后总量应等于现有加新增: %v", diff)
}
if m.CoverAreaKm2() != m.IncAreaKm2() {
t.Fatalf("整体替换后总量应等于快照本身: %v vs %v", m.CoverAreaKm2(), m.IncAreaKm2())
}
}