github.com/simpleiot/simpleiot@v0.18.3/store/hash_test.go (about) 1 package store 2 3 import ( 4 "fmt" 5 "sort" 6 "testing" 7 ) 8 9 func XorSum(a []int) int { 10 var ret int 11 for _, v := range a { 12 ret = ret ^ v 13 } 14 15 return ret 16 } 17 18 func cloneArray[T any](a []T) []T { 19 ret := make([]T, len(a)) 20 copy(ret, a) 21 return ret 22 } 23 24 // We'd like a checksum that is commutative and can be updated incrementally 25 func TestXorChecksum(t *testing.T) { 26 d1 := []int{2342000, 1928323, 29192, 41992, 29439} 27 d2 := cloneArray(d1) 28 sort.Ints(d2) 29 // d1 and d2 slices now have save values, but in different order 30 31 d1Sum := XorSum(d1) 32 d2Sum := XorSum(d2) 33 34 // check that checksum is commutative 35 if d1Sum != d2Sum { 36 t.Fatal("check sum is not commutative") 37 } 38 39 // simulate updating a value by replacing the value in the array 40 // and checksumming the entire array, and also by incrementally 41 // updating the checksum 42 newValue := 101929 43 d3 := cloneArray(d1) 44 45 // replace a value in the array, and calculate the new checksum 46 d3[4] = newValue 47 d3Sum := XorSum(d3) 48 49 // try to incrementally update the checksum by backing out the old 50 // checksum value and adding the new value 51 d3SumInc := d1Sum ^ d1[4] ^ newValue 52 53 if d3Sum != d3SumInc { 54 t.Fatal("Incremental checksum did not equal the complete checksum") 55 } 56 } 57 58 // Test if we can compute XOR checksums in groups, and then XOR the groups 59 func TestXorChecksumGroup(t *testing.T) { 60 d1 := []int{2342000, 1928323, 29192, 41992, 29439} 61 62 d1Sum := XorSum(d1) 63 64 d1SumA := XorSum(d1[:2]) 65 d1SumB := XorSum(d1[2:]) 66 67 d1SumAB := XorSum([]int{d1SumA, d1SumB}) 68 69 if d1Sum != d1SumAB { 70 fmt.Printf("sums: %0x %0x %0x %0x\n", d1Sum, d1SumA, d1SumB, d1SumAB) 71 t.Fatal("Grouped checksum did not work") 72 } 73 74 // it works, pretty neat! 75 } 76 77 func TestUpstreamHash(t *testing.T) { 78 n := 12342342 79 update := 22992343 80 81 n1 := n ^ update 82 83 updateCalc := n ^ n1 84 85 if updateCalc != update { 86 t.Fatal("Hmm, something went wrong") 87 } 88 89 // this is pretty neat as we can simply pass the update value upstream 90 // and apply it to each node. 91 // there is one disadvantage -- if the update travels through two paths, then 92 // the update will cancel out once they merge again 93 }