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.

202 lines
4.8 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. tmrand "github.com/tendermint/tendermint/libs/rand"
  9. )
  10. func randCompactBitArray(bits int) (*CompactBitArray, []byte) {
  11. numBytes := (bits + 7) / 8
  12. src := tmrand.Bytes((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-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. tc := tc
  63. t.Run(tc.bA.String(), func(t *testing.T) {
  64. bz, err := json.Marshal(tc.bA)
  65. require.NoError(t, err)
  66. assert.Equal(t, tc.marshalledBA, string(bz))
  67. var unmarshalledBA *CompactBitArray
  68. err = json.Unmarshal(bz, &unmarshalledBA)
  69. require.NoError(t, err)
  70. if tc.bA == nil {
  71. require.Nil(t, unmarshalledBA)
  72. } else {
  73. require.NotNil(t, unmarshalledBA)
  74. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  75. if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) {
  76. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  77. }
  78. }
  79. })
  80. }
  81. }
  82. func TestCompactMarshalUnmarshal(t *testing.T) {
  83. bA1 := NewCompactBitArray(0)
  84. bA2 := NewCompactBitArray(1)
  85. bA3 := NewCompactBitArray(1)
  86. bA3.SetIndex(0, true)
  87. bA4 := NewCompactBitArray(5)
  88. bA4.SetIndex(0, true)
  89. bA4.SetIndex(1, true)
  90. bA5 := NewCompactBitArray(9)
  91. bA5.SetIndex(0, true)
  92. bA5.SetIndex(1, true)
  93. bA5.SetIndex(8, true)
  94. bA6 := NewCompactBitArray(16)
  95. bA6.SetIndex(0, true)
  96. bA6.SetIndex(1, true)
  97. bA6.SetIndex(8, false)
  98. bA6.SetIndex(15, true)
  99. testCases := []struct {
  100. bA *CompactBitArray
  101. marshalledBA []byte
  102. }{
  103. {nil, []byte("null")},
  104. {bA1, []byte("null")},
  105. {bA2, []byte{byte(1), byte(0)}},
  106. {bA3, []byte{byte(1), byte(128)}},
  107. {bA4, []byte{byte(5), byte(192)}},
  108. {bA5, []byte{byte(9), byte(192), byte(128)}},
  109. {bA6, []byte{byte(16), byte(192), byte(1)}},
  110. }
  111. for _, tc := range testCases {
  112. tc := tc
  113. t.Run(tc.bA.String(), func(t *testing.T) {
  114. bz := tc.bA.CompactMarshal()
  115. assert.Equal(t, tc.marshalledBA, bz)
  116. unmarshalledBA, err := CompactUnmarshal(bz)
  117. require.NoError(t, err)
  118. if tc.bA == nil {
  119. require.Nil(t, unmarshalledBA)
  120. } else {
  121. require.NotNil(t, unmarshalledBA)
  122. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  123. if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) {
  124. assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems)
  125. }
  126. }
  127. })
  128. }
  129. }
  130. func TestCompactBitArrayNumOfTrueBitsBefore(t *testing.T) {
  131. testCases := []struct {
  132. marshalledBA string
  133. bAIndex []int
  134. trueValueIndex []int
  135. }{
  136. {`"_____"`, []int{0, 1, 2, 3, 4}, []int{0, 0, 0, 0, 0}},
  137. {`"x"`, []int{0}, []int{0}},
  138. {`"_x"`, []int{1}, []int{0}},
  139. {`"x___xxxx"`, []int{0, 4, 5, 6, 7}, []int{0, 1, 2, 3, 4}},
  140. {`"__x_xx_x__x_x___"`, []int{2, 4, 5, 7, 10, 12}, []int{0, 1, 2, 3, 4, 5}},
  141. {`"______________xx"`, []int{14, 15}, []int{0, 1}},
  142. }
  143. for tcIndex, tc := range testCases {
  144. tc := tc
  145. tcIndex := tcIndex
  146. t.Run(tc.marshalledBA, func(t *testing.T) {
  147. var bA *CompactBitArray
  148. err := json.Unmarshal([]byte(tc.marshalledBA), &bA)
  149. require.NoError(t, err)
  150. for i := 0; i < len(tc.bAIndex); i++ {
  151. require.Equal(t, tc.trueValueIndex[i], bA.NumTrueBitsBefore(tc.bAIndex[i]), "tc %d, i %d", tcIndex, i)
  152. }
  153. })
  154. }
  155. }
  156. func TestCompactBitArrayGetSetIndex(t *testing.T) {
  157. r := rand.New(rand.NewSource(100))
  158. numTests := 10
  159. numBitsPerArr := 100
  160. for i := 0; i < numTests; i++ {
  161. bits := r.Intn(1000)
  162. bA, _ := randCompactBitArray(bits)
  163. for j := 0; j < numBitsPerArr; j++ {
  164. copy := bA.Copy()
  165. index := r.Intn(bits)
  166. val := (r.Int63() % 2) == 0
  167. bA.SetIndex(index, val)
  168. require.Equal(t, val, bA.GetIndex(index), "bA.SetIndex(%d, %v) failed on bit array: %s", index, val, copy)
  169. }
  170. }
  171. }