github.com/tunabay/go-bitarray@v1.3.1/builder_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 "bytes" 9 "errors" 10 "fmt" 11 "math/rand" 12 "testing" 13 "testing/iotest" 14 "time" 15 16 "github.com/tunabay/go-bitarray" 17 ) 18 19 func TestNewBuilder(t *testing.T) { 20 bb1 := bitarray.NewBuilder( 21 bitarray.NewZeroFilled(10), 22 nil, 23 bitarray.NewOneFilled(10), 24 bitarray.New(), 25 bitarray.MustParse("0101"), 26 bitarray.NewZeroFilled(10).ZExpand(), 27 bitarray.NewOneFilled(10), 28 nil, 29 ) 30 got1 := bb1.BitArray() 31 got1.V() 32 want1 := bitarray.MustParse("0000000000 1111111111 0101 0000000000 1111111111") 33 if !got1.Equal(want1) { 34 t.Error("unexpected result:") 35 t.Logf(" got: %#b", got1) 36 t.Logf(" got: %s", got1.D()) 37 t.Logf("want: %#b", want1) 38 } 39 40 bb2 := bitarray.NewBuilder() 41 got2 := bb2.BitArray() 42 got2.V() 43 if !got2.IsZero() { 44 t.Error("unexpected result: want zero") 45 t.Logf(" got: %#b", got1) 46 t.Logf(" got: %s", got1.D()) 47 } 48 } 49 50 func TestBuilder_BitArray(t *testing.T) { 51 b1 := []byte{0b_1111_0000, 0b_1010_1010, 0b_0000_1111, 0b_1100_1100} 52 bb1 := bitarray.NewBuilder( 53 nil, 54 bitarray.NewZeroFilled(5), // 00000 55 bitarray.NewOneFilled(5), // 11111 56 bitarray.NewByRunLength(1, 2, 3, 4), // 0110001111 57 ) 58 bb1.A(b1, 5, 0, false) // (empty) 59 bb1.A(b1, 2, 5, false) // 11000 60 bb1.A(b1, 22, 10, false) // 11 1100 1100 61 bb1.A(b1, 4, 4, true) // 0000 62 got1 := bb1.BitArray() 63 got1.V() 64 want1 := bitarray.MustParse("00000 11111 0110001111 11000 11 1100 1100 0000") 65 if !got1.Equal(want1) { 66 t.Error("unexpected result:") 67 t.Logf(" got: %#b", got1) 68 t.Logf(" got: %s", got1.D()) 69 t.Logf("want: %#b", want1) 70 } 71 if bb1.String() != want1.String() { 72 t.Error("unexpected result:") 73 t.Logf(" got: %s", bb1.String()) 74 t.Logf("want: %s", want1.String()) 75 } 76 if bb1.Len() != want1.Len() { 77 t.Errorf("unexpected Len: got %d, want %d", bb1.Len(), want1.Len()) 78 } 79 } 80 81 func TestBuilder_String(t *testing.T) { 82 b1 := []byte{0b_1111_0000, 0b_1010_1010, 0b_0000_1111, 0b_1100_1100} 83 bb1 := bitarray.NewBuilder( 84 nil, 85 bitarray.NewZeroFilled(7), // 0000000 86 bitarray.NewOneFilled(7), // 1111111 87 bitarray.NewByRunLength(4, 3, 2, 1), // 0000111001 88 ) 89 bb1.A(b1, 15, 0, false) // (empty) 90 bb1.A(b1, 6, 4, false) // 0010 91 bb1.A(b1, 6, 14, false) // 00 10101010 0000 92 bb1.A(b1, 12, 8, false) // 10100000 93 bb1.A(b1, 16, 9, false) // 00001111 1 94 bb1.A(b1, 4, 4, true) // 0000 95 got1 := bb1.String() 96 want1 := "000000011111110000111001001000101010100000101000000000111110000" 97 if got1 != want1 { 98 t.Error("unexpected result:") 99 t.Logf(" got: %s", got1) 100 t.Logf("want: %s", want1) 101 } 102 if bb1.Len() != len(want1) { 103 t.Errorf("unexpected Len: got %d, want %d", bb1.Len(), len(want1)) 104 } 105 } 106 107 func TestBuilder_WriteByteBits_rand(t *testing.T) { 108 const ( 109 testIterations = 1000 110 testAppends = 30 111 ) 112 var ( 113 bb bitarray.Builder 114 want string 115 ) 116 117 appendB := func(n int) { 118 bits := make([]byte, n) 119 for i := 0; i < n; i++ { 120 bits[i] = byte(rand.Intn(2)) 121 want += string([]byte{'0' + bits[i]}) 122 } 123 bb.WriteByteBits(bits) 124 } 125 126 for i := 0; i < testIterations; i++ { 127 bb.Reset() 128 want = "" 129 for j := 0; j < testAppends; j++ { 130 appendB(rand.Intn(128)) 131 gsd := bb.String() 132 gsa := bb.BitArray().String() 133 if gsd != want || gsa != want { 134 t.Errorf("unexpected result:") 135 t.Logf(" got(direct): %s", gsd) 136 t.Logf(" got(convert): %s", gsa) 137 t.Logf(" want: %s", want) 138 } 139 } 140 // t.Logf("pass: %s", bb.String()) 141 } 142 } 143 144 func TestBuilder_WriteBitsFromBytes_rand(t *testing.T) { 145 const ( 146 testIterations = 2000 147 testAppends = 50 148 ) 149 var ( 150 bb bitarray.Builder 151 want string 152 ) 153 hist := make([]string, 0, 100) 154 155 logf := func(f string, p ...interface{}) { 156 hist = append(hist, fmt.Sprintf(f, p...)) 157 } 158 appendB := func() { 159 off := rand.Intn(32) 160 nBits := rand.Intn(32) 161 logf("append: %d bits, off %d", nBits, off) 162 nBytes := (off + nBits + 7) >> 3 163 buf := make([]byte, nBytes) 164 for i := off; i < off+nBits; i++ { 165 b := byte(rand.Intn(2)) & 1 166 iby := i >> 3 167 ibi := i & 7 168 buf[iby] |= b << (7 - ibi) 169 want += string([]byte{'0' + b}) 170 } 171 logf("append: %08b", buf) 172 bb.WriteBitsFromBytes(buf, off, nBits) 173 } 174 175 for i := 0; i < testIterations; i++ { 176 bb.Reset() 177 want = "" 178 hist = hist[:0] 179 for j := 0; j < testAppends; j++ { 180 appendB() 181 gsd := bb.String() 182 gsa := bb.BitArray().String() 183 if gsd != want || gsa != want { 184 t.Errorf("unexpected result:") 185 t.Logf(" got(direct): %s", gsd) 186 t.Logf(" got(convert): %s", gsa) 187 t.Logf(" want: %s", want) 188 t.Logf("history:") 189 for k, h := range hist { 190 t.Logf("#%3d: %s", k, h) 191 } 192 t.FailNow() 193 } 194 } 195 // t.Logf("pass: %s", bb.String()) 196 } 197 } 198 199 func TestBuilder_Write(t *testing.T) { 200 buf := []byte{0xff, 0x00, 0xcc, 0x33, 0xaa, 0x55, 0xee, 0x77} 201 bb := bitarray.NewBuilder(bitarray.NewOneFilled(2)) 202 wantS := "11" 203 add := func(off, n int) { 204 sb := buf[off : off+n] 205 for _, b := range sb { 206 wantS += fmt.Sprintf("%08b", b) 207 } 208 wn, err := bb.Write(sb) 209 if wn != n || err != nil { 210 t.Errorf("Write: n=%d, want=%d, err=%s", wn, n, err) 211 } 212 } 213 add(3, 0) 214 add(0, 3) 215 add(0, 8) 216 add(1, 6) 217 add(7, 1) 218 add(5, 2) 219 220 if gotS := bb.String(); gotS != wantS { 221 t.Error("unexpected result:") 222 t.Logf(" got: %s", gotS) 223 t.Logf("want: %s", wantS) 224 } 225 if bb.Len() != len(wantS) { 226 t.Errorf("unexpected result: got %d, want %d", bb.Len(), len(wantS)) 227 } 228 gotB := bb.BitArray() 229 gotB.V() 230 wantB := bitarray.MustParse(wantS) 231 if !gotB.Equal(wantB) { 232 t.Error("unexpected result:") 233 t.Logf(" got: %#b", gotB) 234 t.Logf(" got: %s", gotB.D()) 235 t.Logf("want: %#b", wantB) 236 } 237 } 238 239 func TestBuilder_WriteByte_zero(t *testing.T) { 240 const nBytes = 123 241 nBits := nBytes << 3 242 243 bb := bitarray.NewBuilder() 244 for i := 0; i < nBytes; i++ { 245 if err := bb.WriteByte(0); err != nil { 246 t.Fatalf("WriteByte: %s", err) 247 } 248 } 249 wantB := bitarray.NewZeroFilled(nBits) 250 wantS := wantB.String() 251 if n := bb.Len(); n != nBits { 252 t.Errorf("unexpeted Len: got %d, want %d", n, nBits) 253 } 254 if gotS := bb.String(); gotS != wantS { 255 t.Error("unexpected result:") 256 t.Logf(" got: %s", gotS) 257 t.Logf("want: %s", wantS) 258 } 259 gotB := bb.BitArray() 260 gotB.V() 261 if !gotB.Equal(wantB) { 262 t.Error("unexpected result:") 263 t.Logf(" got: %#b", gotB) 264 t.Logf(" got: %s", gotB.D()) 265 t.Logf("want: %#b", wantB) 266 } 267 } 268 269 func TestBuilder_WriteByte_rand(t *testing.T) { 270 const testIterations = 10000 271 rand.Seed(time.Now().UnixNano()) 272 for i := 0; i < testIterations; i++ { 273 bb := bitarray.NewBuilder() 274 wantS := "" 275 maxAdds := 16 276 if rand.Intn(5) == 0 { 277 maxAdds = 256 278 } 279 nadds := rand.Intn(maxAdds) 280 for j := 0; j < nadds; j++ { 281 if rand.Intn(5) == 0 { 282 nBits := 1 + rand.Intn(7) 283 for k := 0; k < nBits; k++ { 284 bit := byte(rand.Intn(2)) 285 if err := bb.WriteBit(bit); err != nil { 286 t.Fatalf("WriteBit: %s", err) 287 } 288 wantS += fmt.Sprintf("%b", bit) 289 } 290 continue 291 } 292 b := byte(rand.Intn(0x100)) 293 if err := bb.WriteByte(b); err != nil { 294 t.Fatalf("WriteByte: %s", err) 295 } 296 wantS += fmt.Sprintf("%08b", b) 297 } 298 if gotS := bb.String(); gotS != wantS { 299 t.Error("unexpected result:") 300 t.Logf(" got: %s", gotS) 301 t.Logf("want: %s", wantS) 302 } 303 if bb.Len() != len(wantS) { 304 t.Errorf("unexpected len: got %d, want %d", bb.Len(), len(wantS)) 305 } 306 gotB := bb.BitArray() 307 gotB.V() 308 wantB := bitarray.MustParse(wantS) 309 if !gotB.Equal(wantB) { 310 t.Error("unexpected result:") 311 t.Logf(" got: %#b", gotB) 312 t.Logf(" got: %s", gotB.D()) 313 t.Logf("want: %#b", wantB) 314 } 315 // if i < 32 { 316 // t.Logf("pass: %#b", gotB) 317 // } 318 } 319 } 320 321 func TestBuilder_ReadFrom(t *testing.T) { 322 b := []byte{0b_1111_1010, 0b_0000_0101, 0b_1110_0111, 0b_1100_0011} 323 r := iotest.OneByteReader(bytes.NewBuffer(b)) 324 325 bb := bitarray.NewBuilder(bitarray.NewZeroFilled(3)) 326 rn, err := bb.ReadFrom(r) 327 if err != nil { 328 t.Errorf("ReadFrom: %s", err) 329 } 330 if rn != 4 { 331 t.Errorf("unexpected length read: got %d, want 4", rn) 332 } 333 bb.WriteByteBits([]byte{0, 1}) 334 335 gotS := bb.String() 336 gotB := bb.BitArray() 337 gotB.V() 338 339 wantS := "0001111101000000101111001111100001101" 340 wantB := bitarray.MustParse(wantS) 341 342 if gotS != wantS { 343 t.Error("unexpected result:") 344 t.Logf(" got: %s", gotS) 345 t.Logf("want: %s", wantS) 346 } 347 if bb.Len() != len(wantS) { 348 t.Errorf("unexpected len: got %d, want %d", bb.Len(), len(wantS)) 349 } 350 if !gotB.Equal(wantB) { 351 t.Error("unexpected result:") 352 t.Logf(" got: %#b", gotB) 353 t.Logf(" got: %s", gotB.D()) 354 t.Logf("want: %#b", wantB) 355 } 356 } 357 358 func TestBuilder_ReadFrom_error(t *testing.T) { 359 myErr := errors.New("test") 360 r := iotest.ErrReader(myErr) 361 362 bb := bitarray.NewBuilder(bitarray.NewZeroFilled(100)) 363 rn, err := bb.ReadFrom(r) 364 if err != nil { 365 if !errors.Is(err, myErr) { 366 t.Errorf("ReadFrom: unexpected error: %s", err) 367 } 368 } else { 369 t.Errorf("ReadFrom: expected error, but no error.") 370 } 371 if rn != 0 { 372 t.Errorf("unexpected length read: got %d, want 0", rn) 373 } 374 } 375 376 func TestBuilder_WriteBitArray(t *testing.T) { 377 bas := []*bitarray.BitArray{ 378 nil, // overwritten 379 nil, 380 bitarray.New(), 381 bitarray.MustParse("1111-00"), 382 bitarray.NewZeroFilled(200), 383 bitarray.NewZeroFilled(200).ZExpand(), 384 } 385 for i, ba := range bas { 386 bb := bitarray.NewBuilder() 387 var wn int 388 var err error 389 if i == 0 { 390 wn, err = bb.WriteBitArray(nil) // untyped 391 } else { 392 wn, err = bb.WriteBitArray(ba) 393 } 394 if wn != ba.Len() { 395 t.Errorf("unexpected length: got %d, want %d", wn, ba.Len()) 396 } 397 if err != nil { 398 t.Errorf("WriteBitArray: %s", err) 399 } 400 if bb.Len() != ba.Len() { 401 t.Errorf("unexpected length: got %d, want %d", bb.Len(), ba.Len()) 402 } 403 wantS := "" 404 if ba != nil { 405 wantS = ba.String() 406 } 407 if gotS := bb.String(); gotS != wantS { 408 t.Error("unexpected result:") 409 t.Logf(" got: %s", gotS) 410 t.Logf("want: %s", wantS) 411 } 412 gotB := bb.BitArray() 413 gotB.V() 414 if !gotB.Equal(ba) { 415 t.Error("unexpected result:") 416 t.Logf(" got: %#b", gotB) 417 t.Logf(" got: %s", gotB.D()) 418 t.Logf("want: %#b", ba) 419 } 420 } 421 } 422 423 func TestBuilder_WriteBitArray_multi(t *testing.T) { 424 var nilba *bitarray.BitArray 425 bas := []bitarray.BitArrayer{ 426 bitarray.New(), 427 bitarray.NewZeroFilled(30).ZOptimize(), 428 bitarray.NewByRunLength(0, 7, 5, 3), // 111111100000111 429 bitarray.NewZeroFilled(20).ZExpand(), 430 bitarray.NewOneFilled(10).ZExpand(), 431 nilba, 432 bitarray.MustParse("0101-1111 1010-0111"), 433 bitarray.MustParse("0"), 434 } 435 436 bb := bitarray.NewBuilder() 437 for _, bai := range bas { 438 var nBits int 439 if bai != nil { 440 ba := bai.BitArray() 441 nBits = ba.Len() 442 } 443 wn, err := bb.WriteBitArray(bai) 444 if err != nil { 445 t.Errorf("WriteBitArray: %s", err) 446 } 447 if wn != nBits { 448 t.Errorf("WriteBitArray: unexpected len: got %d, want %d", wn, nBits) 449 } 450 } 451 452 gotS := bb.String() 453 wantS := "000000000000000000000000000000" + "111111100000111" + 454 "00000000000000000000" + "1111111111" + 455 "01011111" + "10100111" + "0" 456 if gotS != wantS { 457 t.Error("unexpected result:") 458 t.Logf(" got: %s", gotS) 459 t.Logf("want: %s", wantS) 460 } 461 if bb.Len() != len(wantS) { 462 t.Errorf("unexpected result: got %d, want %d", bb.Len(), len(wantS)) 463 } 464 465 gotB := bb.BitArray() 466 gotB.V() 467 wantB := bitarray.MustParse(wantS) 468 if !gotB.Equal(wantB) { 469 t.Error("unexpected result:") 470 t.Logf(" got: %#b", gotB) 471 t.Logf(" got: %s", gotB.D()) 472 t.Logf("want: %#b", wantB) 473 } 474 } 475 476 func TestBuilder_WriteBits(t *testing.T) { 477 srcBA := bitarray.MustParse("1111-0000 1100-0011").Repeat(10) 478 srcBuf := bitarray.NewBufferFromBitArray(srcBA) 479 wantS := "" 480 bb := bitarray.NewBuilder() 481 482 add := func(buf *bitarray.Buffer) { 483 t.Helper() 484 wantS += buf.String() 485 n, err := bb.WriteBits(buf) 486 if err != nil { 487 t.Fatalf("unexpected error: %v", err) 488 } 489 if n != buf.Len() { 490 t.Fatalf("unexpected n: got %d, want %d", n, buf.Len()) 491 } 492 if got, want := bb.BitArray(), bitarray.MustParse(wantS); !got.Equal(want) { 493 t.Errorf("unexpected result:") 494 t.Logf(" got: %#b", got) 495 t.Logf("want: %#b", want) 496 } 497 } 498 for i := 0; i < 35; i++ { 499 for j := 0; j < 35; j++ { 500 add(srcBuf.Slice(i, i+j)) 501 } 502 } 503 srcBuf.FillBits(0) 504 505 if got, want := bb.BitArray(), bitarray.MustParse(wantS); !got.Equal(want) { 506 t.Errorf("unexpected result:") 507 t.Logf(" got: %#b", got) 508 t.Logf("want: %#b", want) 509 } 510 }