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  }