You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
4.7 KiB

  1. package bitarray
  2. import (
  3. "encoding/json"
  4. "math/rand"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. )
  10. func randCompactBitArray(bits int) (*CompactBitArray, []byte) {
  11. numBytes := (bits + 7) / 8
  12. src := cmn.RandBytes((bits + 7) / 8)
  13. bA := NewCompactBitArray(bits)
  14. for i := 0; i < numBytes-1; i++ {
  15. for j := uint8(0); j < 8; j++ {
  16. bA.SetIndex(i*8+int(j), src[i]&(uint8(1)<<(8-j)) > 0)
  17. }
  18. }
  19. // Set remaining bits
  20. for i := uint8(0); i < 8-uint8(bA.ExtraBitsStored); i++ {
  21. bA.SetIndex(numBytes*8+int(i), src[numBytes-1]&(uint8(1)<<(8-i)) > 0)
  22. }
  23. return bA, src
  24. }
  25. func TestNewBitArrayNeverCrashesOnNegatives(t *testing.T) {
  26. bitList := []int{-127, -128, -1 << 31}
  27. for _, bits := range bitList {
  28. bA := NewCompactBitArray(bits)
  29. require.Nil(t, bA)
  30. }
  31. }
  32. func TestJSONMarshalUnmarshal(t *testing.T) {
  33. bA1 := NewCompactBitArray(0)
  34. bA2 := NewCompactBitArray(1)
  35. bA3 := NewCompactBitArray(1)
  36. bA3.SetIndex(0, true)
  37. bA4 := NewCompactBitArray(5)
  38. bA4.SetIndex(0, true)
  39. bA4.SetIndex(1, true)
  40. bA5 := NewCompactBitArray(9)
  41. bA5.SetIndex(0, true)
  42. bA5.SetIndex(1, true)
  43. bA5.SetIndex(8, true)
  44. bA6 := NewCompactBitArray(16)
  45. bA6.SetIndex(0, true)
  46. bA6.SetIndex(1, true)
  47. bA6.SetIndex(8, false)
  48. bA6.SetIndex(15, true)
  49. testCases := []struct {
  50. bA *CompactBitArray
  51. marshalledBA string
  52. }{
  53. {nil, `null`},
  54. {bA1, `null`},
  55. {bA2, `"_"`},
  56. {bA3, `"x"`},
  57. {bA4, `"xx___"`},
  58. {bA5, `"xx______x"`},
  59. {bA6, `"xx_____________x"`},
  60. }
  61. for _, tc := range testCases {
  62. t.Run(tc.bA.String(), func(t *testing.T) {
  63. bz, err := json.Marshal(tc.bA)
  64. require.NoError(t, err)
  65. assert.Equal(t, tc.marshalledBA, string(bz))
  66. var unmarshalledBA *CompactBitArray
  67. err = json.Unmarshal(bz, &unmarshalledBA)
  68. require.NoError(t, err)
  69. if tc.bA == nil {
  70. require.Nil(t, unmarshalledBA)
  71. } else {
  72. require.NotNil(t, unmarshalledBA)
  73. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  74. if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) {
  75. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  76. }
  77. }
  78. })
  79. }
  80. }
  81. func TestCompactMarshalUnmarshal(t *testing.T) {
  82. bA1 := NewCompactBitArray(0)
  83. bA2 := NewCompactBitArray(1)
  84. bA3 := NewCompactBitArray(1)
  85. bA3.SetIndex(0, true)
  86. bA4 := NewCompactBitArray(5)
  87. bA4.SetIndex(0, true)
  88. bA4.SetIndex(1, true)
  89. bA5 := NewCompactBitArray(9)
  90. bA5.SetIndex(0, true)
  91. bA5.SetIndex(1, true)
  92. bA5.SetIndex(8, true)
  93. bA6 := NewCompactBitArray(16)
  94. bA6.SetIndex(0, true)
  95. bA6.SetIndex(1, true)
  96. bA6.SetIndex(8, false)
  97. bA6.SetIndex(15, true)
  98. testCases := []struct {
  99. bA *CompactBitArray
  100. marshalledBA []byte
  101. }{
  102. {nil, []byte("null")},
  103. {bA1, []byte("null")},
  104. {bA2, []byte{byte(1), byte(0)}},
  105. {bA3, []byte{byte(1), byte(128)}},
  106. {bA4, []byte{byte(5), byte(192)}},
  107. {bA5, []byte{byte(9), byte(192), byte(128)}},
  108. {bA6, []byte{byte(16), byte(192), byte(1)}},
  109. }
  110. for _, tc := range testCases {
  111. t.Run(tc.bA.String(), func(t *testing.T) {
  112. bz := tc.bA.CompactMarshal()
  113. assert.Equal(t, tc.marshalledBA, bz)
  114. unmarshalledBA, err := CompactUnmarshal(bz)
  115. require.NoError(t, err)
  116. if tc.bA == nil {
  117. require.Nil(t, unmarshalledBA)
  118. } else {
  119. require.NotNil(t, unmarshalledBA)
  120. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  121. if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) {
  122. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  123. }
  124. }
  125. })
  126. }
  127. }
  128. func TestCompactBitArrayNumOfTrueBitsBefore(t *testing.T) {
  129. testCases := []struct {
  130. marshalledBA string
  131. bAIndex []int
  132. trueValueIndex []int
  133. }{
  134. {`"_____"`, []int{0, 1, 2, 3, 4}, []int{0, 0, 0, 0, 0}},
  135. {`"x"`, []int{0}, []int{0}},
  136. {`"_x"`, []int{1}, []int{0}},
  137. {`"x___xxxx"`, []int{0, 4, 5, 6, 7}, []int{0, 1, 2, 3, 4}},
  138. {`"__x_xx_x__x_x___"`, []int{2, 4, 5, 7, 10, 12}, []int{0, 1, 2, 3, 4, 5}},
  139. {`"______________xx"`, []int{14, 15}, []int{0, 1}},
  140. }
  141. for tcIndex, tc := range testCases {
  142. t.Run(tc.marshalledBA, func(t *testing.T) {
  143. var bA *CompactBitArray
  144. err := json.Unmarshal([]byte(tc.marshalledBA), &bA)
  145. require.NoError(t, err)
  146. for i := 0; i < len(tc.bAIndex); i++ {
  147. require.Equal(t, tc.trueValueIndex[i], bA.NumTrueBitsBefore(tc.bAIndex[i]), "tc %d, i %d", tcIndex, i)
  148. }
  149. })
  150. }
  151. }
  152. func TestCompactBitArrayGetSetIndex(t *testing.T) {
  153. r := rand.New(rand.NewSource(100))
  154. numTests := 10
  155. numBitsPerArr := 100
  156. for i := 0; i < numTests; i++ {
  157. bits := r.Intn(1000)
  158. bA, _ := randCompactBitArray(bits)
  159. for j := 0; j < numBitsPerArr; j++ {
  160. copy := bA.Copy()
  161. index := r.Intn(bits)
  162. val := (r.Int63() % 2) == 0
  163. bA.SetIndex(index, val)
  164. require.Equal(t, val, bA.GetIndex(index), "bA.SetIndex(%d, %v) failed on bit array: %s", index, val, copy)
  165. }
  166. }
  167. }