github.com/okex/exchain@v1.8.0/libs/tendermint/crypto/multisig/bitarray/compact_bit_array_test.go (about) 1 package bitarray 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math" 7 "math/rand" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 tmrand "github.com/okex/exchain/libs/tendermint/libs/rand" 14 ) 15 16 func randCompactBitArray(bits int) (*CompactBitArray, []byte) { 17 numBytes := (bits + 7) / 8 18 src := tmrand.Bytes((bits + 7) / 8) 19 bA := NewCompactBitArray(bits) 20 21 for i := 0; i < numBytes-1; i++ { 22 for j := uint8(0); j < 8; j++ { 23 bA.SetIndex(i*8+int(j), src[i]&(uint8(1)<<(8-j)) > 0) 24 } 25 } 26 // Set remaining bits 27 for i := uint8(0); i < 8-bA.ExtraBitsStored; i++ { 28 bA.SetIndex(numBytes*8+int(i), src[numBytes-1]&(uint8(1)<<(8-i)) > 0) 29 } 30 return bA, src 31 } 32 33 func TestNewBitArrayNeverCrashesOnNegatives(t *testing.T) { 34 bitList := []int{-127, -128, -1 << 31} 35 for _, bits := range bitList { 36 bA := NewCompactBitArray(bits) 37 require.Nil(t, bA) 38 } 39 } 40 41 func TestJSONMarshalUnmarshal(t *testing.T) { 42 43 bA1 := NewCompactBitArray(0) 44 bA2 := NewCompactBitArray(1) 45 46 bA3 := NewCompactBitArray(1) 47 bA3.SetIndex(0, true) 48 49 bA4 := NewCompactBitArray(5) 50 bA4.SetIndex(0, true) 51 bA4.SetIndex(1, true) 52 53 bA5 := NewCompactBitArray(9) 54 bA5.SetIndex(0, true) 55 bA5.SetIndex(1, true) 56 bA5.SetIndex(8, true) 57 58 bA6 := NewCompactBitArray(16) 59 bA6.SetIndex(0, true) 60 bA6.SetIndex(1, true) 61 bA6.SetIndex(8, false) 62 bA6.SetIndex(15, true) 63 64 testCases := []struct { 65 bA *CompactBitArray 66 marshalledBA string 67 }{ 68 {nil, `null`}, 69 {bA1, `null`}, 70 {bA2, `"_"`}, 71 {bA3, `"x"`}, 72 {bA4, `"xx___"`}, 73 {bA5, `"xx______x"`}, 74 {bA6, `"xx_____________x"`}, 75 } 76 77 for _, tc := range testCases { 78 tc := tc 79 t.Run(tc.bA.String(), func(t *testing.T) { 80 bz, err := json.Marshal(tc.bA) 81 require.NoError(t, err) 82 83 assert.Equal(t, tc.marshalledBA, string(bz)) 84 85 var unmarshalledBA *CompactBitArray 86 err = json.Unmarshal(bz, &unmarshalledBA) 87 require.NoError(t, err) 88 89 if tc.bA == nil { 90 require.Nil(t, unmarshalledBA) 91 } else { 92 require.NotNil(t, unmarshalledBA) 93 assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) 94 if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) { 95 assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) 96 } 97 } 98 }) 99 } 100 } 101 102 func TestCompactMarshalUnmarshal(t *testing.T) { 103 bA1 := NewCompactBitArray(0) 104 bA2 := NewCompactBitArray(1) 105 106 bA3 := NewCompactBitArray(1) 107 bA3.SetIndex(0, true) 108 109 bA4 := NewCompactBitArray(5) 110 bA4.SetIndex(0, true) 111 bA4.SetIndex(1, true) 112 113 bA5 := NewCompactBitArray(9) 114 bA5.SetIndex(0, true) 115 bA5.SetIndex(1, true) 116 bA5.SetIndex(8, true) 117 118 bA6 := NewCompactBitArray(16) 119 bA6.SetIndex(0, true) 120 bA6.SetIndex(1, true) 121 bA6.SetIndex(8, false) 122 bA6.SetIndex(15, true) 123 124 testCases := []struct { 125 bA *CompactBitArray 126 marshalledBA []byte 127 }{ 128 {nil, []byte("null")}, 129 {bA1, []byte("null")}, 130 {bA2, []byte{byte(1), byte(0)}}, 131 {bA3, []byte{byte(1), byte(128)}}, 132 {bA4, []byte{byte(5), byte(192)}}, 133 {bA5, []byte{byte(9), byte(192), byte(128)}}, 134 {bA6, []byte{byte(16), byte(192), byte(1)}}, 135 } 136 137 for _, tc := range testCases { 138 tc := tc 139 t.Run(tc.bA.String(), func(t *testing.T) { 140 bz := tc.bA.CompactMarshal() 141 142 assert.Equal(t, tc.marshalledBA, bz) 143 144 unmarshalledBA, err := CompactUnmarshal(bz) 145 require.NoError(t, err) 146 if tc.bA == nil { 147 require.Nil(t, unmarshalledBA) 148 } else { 149 require.NotNil(t, unmarshalledBA) 150 assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) 151 if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) { 152 assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) 153 } 154 } 155 }) 156 } 157 } 158 159 func TestCompactBitArrayNumOfTrueBitsBefore(t *testing.T) { 160 testCases := []struct { 161 marshalledBA string 162 bAIndex []int 163 trueValueIndex []int 164 }{ 165 {`"_____"`, []int{0, 1, 2, 3, 4}, []int{0, 0, 0, 0, 0}}, 166 {`"x"`, []int{0}, []int{0}}, 167 {`"_x"`, []int{1}, []int{0}}, 168 {`"x___xxxx"`, []int{0, 4, 5, 6, 7}, []int{0, 1, 2, 3, 4}}, 169 {`"__x_xx_x__x_x___"`, []int{2, 4, 5, 7, 10, 12}, []int{0, 1, 2, 3, 4, 5}}, 170 {`"______________xx"`, []int{14, 15}, []int{0, 1}}, 171 } 172 for tcIndex, tc := range testCases { 173 tc := tc 174 tcIndex := tcIndex 175 t.Run(tc.marshalledBA, func(t *testing.T) { 176 var bA *CompactBitArray 177 err := json.Unmarshal([]byte(tc.marshalledBA), &bA) 178 require.NoError(t, err) 179 180 for i := 0; i < len(tc.bAIndex); i++ { 181 182 require.Equal(t, tc.trueValueIndex[i], bA.NumTrueBitsBefore(tc.bAIndex[i]), "tc %d, i %d", tcIndex, i) 183 } 184 }) 185 } 186 } 187 188 func TestCompactBitArrayGetSetIndex(t *testing.T) { 189 r := rand.New(rand.NewSource(100)) 190 numTests := 10 191 numBitsPerArr := 100 192 for i := 0; i < numTests; i++ { 193 bits := r.Intn(1000) 194 bA, _ := randCompactBitArray(bits) 195 196 for j := 0; j < numBitsPerArr; j++ { 197 copy := bA.Copy() 198 index := r.Intn(bits) 199 val := (r.Int63() % 2) == 0 200 bA.SetIndex(index, val) 201 require.Equal(t, val, bA.GetIndex(index), "bA.SetIndex(%d, %v) failed on bit array: %s", index, val, copy) 202 } 203 } 204 } 205 206 func TestNewCompactBitArrayCrashWithLimits(t *testing.T) { 207 if testing.Short() { 208 t.Skip("This test can be expensive in memory") 209 } 210 tests := []struct { 211 in int 212 mustPass bool 213 }{ 214 {int(^uint(0) >> 30), false}, 215 {int(^uint(0) >> 1), false}, 216 {int(^uint(0) >> 2), false}, 217 {int(math.MaxInt32), true}, 218 {int(math.MaxInt32) + 1, true}, 219 {int(math.MaxInt32) + 2, true}, 220 {int(math.MaxInt32) - 7, true}, 221 {int(math.MaxInt32) + 24, true}, 222 {int(math.MaxInt32) * 9, false}, // results in >=maxint after (bits+7)/8 223 {1, true}, 224 {0, false}, 225 } 226 227 for _, tt := range tests { 228 tt := tt 229 t.Run(fmt.Sprintf("%d", tt.in), func(t *testing.T) { 230 got := NewCompactBitArray(tt.in) 231 if g := got != nil; g != tt.mustPass { 232 t.Fatalf("got!=nil=%t, want=%t", g, tt.mustPass) 233 } 234 }) 235 } 236 }