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