github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/ledger/common/bitutils/utils_test.go (about) 1 package bitutils 2 3 import ( 4 crand "crypto/rand" 5 "math/big" 6 "math/bits" 7 "math/rand" 8 "time" 9 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestBitVectorAllocation(t *testing.T) { 17 for bits := 0; bits <= 127; bits++ { 18 numBytes := bits / 8 // integer division with floor 19 if bits%8 > 0 { 20 numBytes += 1 21 } 22 23 vect := MakeBitVector(bits) 24 assert.Equal(t, numBytes, len(vect)) 25 } 26 } 27 28 // Test_PaddedByteSliceLength tests that MinimalByteSliceLength returns the 29 func Test_PaddedByteSliceLength(t *testing.T) { 30 for bits := 0; bits <= 127; bits++ { 31 numBytes := bits / 8 // integer division with floor 32 if bits%8 > 0 { 33 numBytes += 1 34 } 35 36 assert.Equal(t, numBytes, MinimalByteSliceLength(bits)) 37 } 38 } 39 40 func TestBitTools(t *testing.T) { 41 seed := time.Now().UnixNano() 42 t.Logf("rand seed is %d", seed) 43 r := rand.NewSource(seed) 44 45 const maxBits = 131 * 8 // upper bound of indices to test 46 var b big.Int 47 48 t.Run("testing ReadBit", func(t *testing.T) { 49 var max big.Int 50 // set max to 2^maxBits 51 max.SetBit(&max, maxBits, 1) 52 // random big int less that 2^maxBits 53 b.Rand(rand.New(r), &max) 54 maxBitsLen := (maxBits + 7) / 8 // length in bytes needed for maxbits 55 bytes := make([]byte, maxBitsLen) 56 copy(bytes[maxBitsLen-len(b.Bytes()):], b.Bytes()) 57 58 // reverse the endianness (both bits and bytes) 59 for j := 0; j < len(bytes)/2; j++ { 60 bytes[j], bytes[len(bytes)-j-1] = bytes[len(bytes)-j-1], bytes[j] 61 } 62 for j := 0; j < len(bytes); j++ { 63 bytes[j] = bits.Reverse8(bytes[j]) 64 } 65 // test bit reads are equal for all indices 66 for i := 0; i < maxBits; i++ { 67 bit := int(b.Bit(i)) 68 assert.Equal(t, bit, ReadBit(bytes, i)) 69 } 70 }) 71 72 t.Run("testing WriteBit", func(t *testing.T) { 73 b.SetInt64(0) 74 bytes := MakeBitVector(maxBits) 75 _, err := crand.Read(bytes) // fill bytes with random values to verify that writing to each individual bit works 76 require.NoError(t, err) 77 78 // build a random big bit by bit 79 for idx := 0; idx < maxBits; idx++ { 80 bit := rand.Intn(2) 81 // b = 2*b + bit 82 b.Lsh(&b, 1) 83 b.Add(&b, big.NewInt(int64(bit))) 84 WriteBit(bytes, idx, bit) // sets the bit at index `idx` 85 } 86 87 // get the big int from the random slice 88 var randomBig big.Int 89 randomBig.SetBytes(bytes) 90 assert.Equal(t, 0, randomBig.Cmp(&b)) 91 }) 92 93 t.Run("testing ClearBit and SetBit", func(t *testing.T) { 94 b.SetInt64(0) 95 bytes := MakeBitVector(maxBits) 96 _, err := crand.Read(bytes) // fill bytes with random values to verify that writing to each individual bit works 97 require.NoError(t, err) 98 99 // build a random big bit by bit 100 for idx := 0; idx < maxBits; idx++ { 101 bit := rand.Intn(2) 102 // b = 2*b + bit 103 b.Lsh(&b, 1) 104 b.Add(&b, big.NewInt(int64(bit))) 105 // sets the bit at index i 106 if bit == 1 { 107 SetBit(bytes, idx) 108 } else { 109 ClearBit(bytes, idx) 110 } 111 } 112 113 // get the big int from the random slice 114 var randomBig big.Int 115 randomBig.SetBytes(bytes) 116 assert.Equal(t, 0, randomBig.Cmp(&b)) 117 }) 118 }