github.com/tunabay/go-bitarray@v1.3.1/buffer_test.go (about) 1 // Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved. 2 // Use of this source code is governed by the MIT license that can be found in 3 // the LICENSE file. 4 5 package bitarray_test 6 7 import ( 8 "math/rand" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/tunabay/go-bitarray" 14 ) 15 16 func TestNewBuffer(t *testing.T) { 17 for i := 0; i < 64*4+2; i++ { 18 buf := bitarray.NewBuffer(i) 19 buf.V() 20 if buf.Len() != i { 21 t.Errorf("invalid Len: got %d, want %d", buf.Len(), i) 22 t.Logf(" got: %s", buf.D()) 23 } 24 if ba := buf.BitArray(); ba.OnesCount() != 0 { 25 t.Errorf("invalid BitArray: %s", ba) 26 t.Logf(" got: %s", buf.D()) 27 t.Logf(" ba: %s", ba.D()) 28 } 29 } 30 func() { 31 var buf *bitarray.Buffer 32 defer func() { 33 if recover() == nil { 34 t.Errorf("panic expected: got %s", buf.D()) 35 } 36 }() 37 buf = bitarray.NewBuffer(-1) 38 }() 39 } 40 41 func TestNewBufferFromBitArray(t *testing.T) { 42 chk := func(got *bitarray.Buffer, bawant *bitarray.BitArray) { 43 got.V() 44 bagot := got.BitArray() 45 bagot.V() 46 if !bawant.Equal(bagot) { 47 t.Error("unexpected BitArray exporeted:") 48 t.Logf(" got: %s", got.String()) 49 t.Logf(" got: %s", got.D()) 50 t.Logf(" got: %#b", bagot) 51 t.Logf(" got: %s", bagot.D()) 52 t.Logf("want: %#b", bawant) 53 } 54 gLen, wLen := got.Len(), bawant.Len() 55 if gLen != wLen { 56 t.Errorf("unexpected Len: got %d, want %d", gLen, wLen) 57 } 58 } 59 for i := 0; i < 64*4+2; i++ { 60 ba := bitarray.NewZeroFilled(i) 61 buf := bitarray.NewBufferFromBitArray(ba) 62 chk(buf, ba) 63 64 ba = bitarray.NewOneFilled(i) 65 buf = bitarray.NewBufferFromBitArray(ba) 66 chk(buf, ba) 67 } 68 tds := []string{ 69 "1100-101", 70 "1100-1010", 71 "1100-1010 1", 72 "1100-1010 10", 73 "1100-1010 1010-1111 1111-0000 1010-111", 74 "1100-1010 1010-1111 1111-0000 1010-1111", 75 "1100-1010 1010-1111 1111-0000 1010-1111 1", 76 "1100-1010 1010-1111 1111-0000 1010-1111 11", 77 } 78 for _, td := range tds { 79 ba := bitarray.MustParse(td) 80 buf := bitarray.NewBufferFromBitArray(ba) 81 chk(buf, ba) 82 } 83 84 bufn := bitarray.NewBufferFromBitArray(nil) 85 switch { 86 case bufn == nil: 87 t.Errorf("unexpected nil buf.") 88 case !bufn.IsZero() || bufn.Len() != 0: 89 t.Errorf("unexpected buf: %s", bufn.D()) 90 } 91 } 92 93 func TestNewBufferFromByteSlicePartial(t *testing.T) { 94 dat := []byte{0b_1111_0000, 0b_1010_0101, 0b_1100_0011, 0b_0101_1010} 95 chk := func(off, nBits int, wantS string) { 96 want := bitarray.MustParse(wantS) 97 buf := bitarray.NewBufferFromByteSlicePartial(dat, off, nBits) 98 buf.V() 99 if ba := buf.BitArray(); !ba.Equal(want) { 100 t.Error("unexpected buffer:") 101 t.Logf(" got: %# b", ba) 102 t.Logf("want: %# b", want) 103 t.Logf(" buf: %s", buf.D()) 104 } 105 } 106 chk(0, 0, "") 107 chk(0, 1, "1") 108 chk(0, 4, "1111") 109 chk(0, 7, "1111-000") 110 chk(0, 8, "1111-0000") 111 chk(0, 9, "1111-0000 1") 112 chk(0, 15, "1111-0000 1010-010") 113 chk(0, 16, "1111-0000 1010-0101") 114 chk(0, 17, "1111-0000 1010-0101 1") 115 chk(0, 32, "1111-0000 1010-0101 1100-0011 0101-1010") 116 chk(1, 4, "111-0") 117 chk(2, 4, "11-00") 118 chk(3, 4, "1-000") 119 chk(4, 4, "0000") 120 chk(4, 6, "0000 10") 121 chk(5, 5, "000 10") 122 chk(6, 4, "00 10") 123 chk(7, 0, "") 124 chk(7, 1, "0") 125 chk(7, 2, "0 1") 126 chk(7, 4, "0 101") 127 chk(7, 7, "0 1010-01") 128 chk(7, 8, "0 1010-010") 129 chk(7, 9, "0 1010-0101") 130 chk(7, 10, "0 1010-0101 1") 131 chk(7, 15, "0 1010-0101 1100-00") 132 chk(7, 16, "0 1010-0101 1100-001") 133 chk(7, 17, "0 1010-0101 1100-0011") 134 chk(7, 18, "0 1010-0101 1100-0011 0") 135 chk(7, 24, "0 1010-0101 1100-0011 0101-101") 136 chk(7, 25, "0 1010-0101 1100-0011 0101-1010") 137 chk(8, 0, "") 138 chk(8, 1, "1") 139 chk(8, 4, "1010") 140 chk(8, 7, "1010-010") 141 chk(8, 8, "1010-0101") 142 chk(8, 9, "1010-0101 1") 143 chk(8, 15, "1010-0101 1100-001") 144 chk(8, 16, "1010-0101 1100-0011") 145 chk(8, 17, "1010-0101 1100-0011 0") 146 chk(31, 0, "") 147 chk(31, 1, "0") 148 chk(32, 0, "") 149 chkpanic := func(off, nBits int) { 150 var buf *bitarray.Buffer 151 defer func() { 152 if recover() == nil { 153 t.Errorf("panic expected: off=%d, nBits=%d", off, nBits) 154 t.Errorf("buf: %s", buf.D()) 155 } 156 }() 157 buf = bitarray.NewBufferFromByteSlicePartial(dat, off, nBits) 158 } 159 chkpanic(-1, 4) 160 chkpanic(0, -1) 161 chkpanic(0, 33) 162 chkpanic(1, 32) 163 chkpanic(31, 2) 164 chkpanic(32, 1) 165 chkpanic(33, 0) 166 chkpanic(64, 4) 167 } 168 169 func TestBuffer_Len_edge(t *testing.T) { 170 var buf *bitarray.Buffer 171 if n := buf.Len(); n != 0 { 172 t.Errorf("unexpected nil.Len: got %d, want 0", n) 173 } 174 if !buf.IsZero() { 175 t.Errorf("unexpected nil.IsZero: got false, want true") 176 } 177 buf = &bitarray.Buffer{} 178 if n := buf.Len(); n != 0 { 179 t.Errorf("unexpected zerov.Len: got %d, want 0", n) 180 } 181 if !buf.IsZero() { 182 t.Errorf("unexpected zerov.IsZero: got false, want true") 183 } 184 // other normal cases are covered by TestNewBufferFromBitArray() 185 } 186 187 func TestBuffer_Clone(t *testing.T) { 188 chk := func(buf *bitarray.Buffer, want *bitarray.BitArray) { 189 t.Helper() 190 ba := buf.BitArray() 191 if !ba.Equal(want) { 192 t.Error("unexpected:") 193 t.Logf(" got: %#b", ba) 194 t.Logf("data: %s", buf.D()) 195 t.Logf("want: %#b", want) 196 } 197 } 198 test := func(ba *bitarray.BitArray) { 199 buf := bitarray.NewBufferFromBitArray(ba) 200 buf.V() 201 buf2 := buf.Clone() 202 buf2.V() 203 chk(buf2, ba) 204 buf.PutBitArrayAt(0, bitarray.NewZeroFilled(ba.Len())) 205 chk(buf2, ba) 206 buf.PutBitArrayAt(0, bitarray.NewOneFilled(ba.Len())) 207 chk(buf2, ba) 208 } 209 for i := 0; i < 130; i++ { 210 ba := bitarray.NewZeroFilled(i).ZOptimize() 211 test(ba) 212 test(ba.ZExpand()) 213 ba = bitarray.NewOneFilled(i) 214 test(ba) 215 } 216 } 217 218 // tests BitArray, Len, Clone, String 219 func TestBuffer_rand(t *testing.T) { 220 const testIterations = 30000 221 rand.Seed(time.Now().UnixNano()) 222 for i := 0; i < testIterations; i++ { 223 var nBits int 224 switch rand.Intn(10) { 225 case 0: 226 nBits = rand.Intn(66) 227 case 1: 228 nBits = 8*(1+rand.Intn(32)) - 1 + rand.Intn(3) 229 case 2: 230 nBits = 256 + rand.Intn(2048) 231 default: 232 nBits = rand.Intn(256) 233 } 234 ba := bitarray.PseudoRand(nBits, nil) 235 buf := bitarray.NewBufferFromBitArray(ba) 236 buf.V() 237 got := buf.BitArray() 238 got.V() 239 if !got.Equal(ba) { 240 t.Error("unexpected result:") 241 t.Logf(" got: %#b", got) 242 t.Logf(" got: %s", got.D()) 243 t.Logf("want: %#b", ba) 244 } 245 buf2 := buf.Clone() 246 buf2.V() 247 got = buf2.BitArray() 248 if !got.Equal(ba) { 249 t.Error("unexpected result:") 250 t.Logf(" got: %#b", got) 251 t.Logf(" got: %s", got.D()) 252 t.Logf("want: %#b", ba) 253 } 254 gotS := buf.String() 255 wantS := ba.String() 256 if gotS != wantS { 257 t.Error("unexpected result:") 258 t.Logf(" got: %s", gotS) 259 t.Logf("want: %s", wantS) 260 t.Logf("data: %s", buf.D()) 261 } 262 if buf.Len() != ba.Len() { 263 t.Errorf("unexpected len: got %d, want %d", buf.Len(), ba.Len()) 264 } 265 } 266 } 267 268 func TestBuffer_Resize_edge(t *testing.T) { 269 chk := func(gotBuf *bitarray.Buffer, wantS string) { 270 t.Helper() 271 gotBuf.V() 272 got := gotBuf.BitArray() 273 want := bitarray.MustParse(wantS) 274 if !got.Equal(want) { 275 t.Error("unexpected:") 276 t.Logf(" got: %#b", got) 277 t.Logf(" got: %s", got.D()) 278 t.Logf("want: %#b", want) 279 } 280 } 281 var nilba *bitarray.BitArray 282 buf := bitarray.NewBufferFromBitArray(nilba) 283 buf.V() 284 buf.Resize(20, bitarray.AlignLeft) 285 buf.V() 286 buf.PutByteAt(4, 0xff) 287 chk(buf, "0000-1111 1111-0000 0000") 288 289 buf.Resize(18, bitarray.AlignRight) 290 buf.V() 291 buf.FillBitsAt(12, 2, 1) 292 chk(buf, "00-1111 1111-0011 0000") 293 294 buf.Resize(12, bitarray.AlignLeft) 295 chk(buf, "00-1111 1111-00") 296 297 buf.Resize(1, bitarray.AlignLeft) 298 chk(buf, "0") 299 300 buf.Resize(19, bitarray.AlignLeft) 301 chk(buf, "0000-0000 0000-0000 000") 302 303 buf.Resize(0, bitarray.AlignLeft) 304 chk(buf, "") 305 306 buf.Resize(15, bitarray.AlignLeft) 307 chk(buf, "0000-0000 0000-000") 308 309 // negative size should cause a panic 310 func() { 311 defer func() { 312 if recover() == nil { 313 t.Errorf("panic expected: got %s", buf.D()) 314 } 315 }() 316 buf.Resize(-1, bitarray.AlignLeft) 317 }() 318 } 319 320 func TestBuffer_Resize_rand(t *testing.T) { 321 const testIterations = 50000 322 rand.Seed(time.Now().UnixNano()) 323 rndLen := func() int { 324 switch rand.Intn(5) { 325 case 0: 326 return rand.Intn(66) 327 case 1: 328 return 8*(1+rand.Intn(32)) - 1 + rand.Intn(3) 329 case 2: 330 return 256 + rand.Intn(2048) 331 } 332 return rand.Intn(256) 333 } 334 rndAlign := func() bitarray.Alignment { 335 if rand.Intn(2) == 0 { 336 return bitarray.AlignLeft 337 } 338 return bitarray.AlignRight 339 } 340 for i := 0; i < testIterations/10; i++ { 341 nBits := rndLen() 342 ba := bitarray.PseudoRand(nBits, nil) 343 buf := bitarray.NewBufferFromBitArray(ba) 344 buf.V() 345 for j := 0; j < 10; j++ { 346 oldNBits := buf.Len() 347 oldS := buf.String() 348 oldD := buf.D() 349 newNBits := rndLen() 350 align := rndAlign() 351 newS := oldS 352 switch { 353 case align == bitarray.AlignLeft && newNBits < oldNBits: 354 newS = oldS[:newNBits] 355 case align == bitarray.AlignLeft && oldNBits < newNBits: 356 newS = oldS + strings.Repeat("0", newNBits-oldNBits) 357 case align == bitarray.AlignRight && newNBits < oldNBits: 358 newS = oldS[oldNBits-newNBits:] 359 case align == bitarray.AlignRight && oldNBits < newNBits: 360 newS = strings.Repeat("0", newNBits-oldNBits) + oldS 361 } 362 363 buf.Resize(newNBits, align) 364 buf.V() 365 if n := buf.Len(); n != newNBits { 366 t.Errorf("unexpected len: got %d, want %d", n, newNBits) 367 } 368 gotS := buf.String() 369 if gotS != newS { 370 t.Errorf("unexpected result: %d -> %d", oldNBits, newNBits) 371 t.Logf(" got: %s", gotS) 372 t.Logf("want: %s", newS) 373 t.Logf(" old: %s", oldS) 374 t.Logf(" old: %s", oldD) 375 } 376 // if i < 32 { 377 // t.Logf("%3d: %3d: %4d -> %4d:", i, j, oldNBits, newNBits) 378 // } 379 } 380 } 381 } 382 383 func TestBuffer_FillBitsAt(t *testing.T) { 384 chk := func(gotBuf *bitarray.Buffer, wantS string) { 385 t.Helper() 386 gotBuf.V() 387 got := gotBuf.BitArray() 388 want := bitarray.MustParse(wantS) 389 if !got.Equal(want) { 390 t.Error("unexpected:") 391 t.Logf(" got: %#b", got) 392 t.Logf(" got: %s", got.D()) 393 t.Logf("want: %#b", want) 394 } 395 } 396 buf := bitarray.NewBuffer(20) 397 chk(buf, "0000-0000 0000-0000 0000") 398 buf.FillBitsAt(0, 10, 1) 399 chk(buf, "1111-1111 1100-0000 0000") 400 buf.FillBitsAt(4, 8, 0) 401 chk(buf, "1111-0000 0000-0000 0000") 402 buf.FillBitsAt(6, 8, 1) 403 chk(buf, "1111-0011 1111-1100 0000") 404 buf.FillBitsAt(12, 4, 1) 405 chk(buf, "1111-0011 1111-1111 0000") 406 buf.FillBitsAt(10, 6, 0) 407 chk(buf, "1111-0011 1100-0000 0000") 408 buf.FillBitsAt(2, 18, 1) 409 chk(buf, "1111-1111 1111-1111 1111") 410 buf.FillBitsAt(8, 8, 0) 411 chk(buf, "1111-1111 0000-0000 1111") 412 buf.FillBitsAt(0, 0, 0) 413 chk(buf, "1111-1111 0000-0000 1111") 414 buf.FillBitsAt(20, 0, 0) 415 chk(buf, "1111-1111 0000-0000 1111") 416 417 chkpanic := func(off, nBits int, bit byte) { 418 defer func() { 419 if recover() == nil { 420 t.Errorf("panic expected: off=%d, nBits=%d, bit=%d.", off, nBits, bit) 421 } 422 }() 423 buf.FillBitsAt(off, nBits, bit) 424 } 425 chkpanic(-1, 4, 1) 426 chkpanic(0, -1, 1) 427 chkpanic(16, 8, 1) 428 chkpanic(99, 8, 1) 429 chkpanic(0, 99, 1) 430 }