github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/bitarray/bitarray_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package bitarray 12 13 import ( 14 "bytes" 15 "fmt" 16 "reflect" 17 "strconv" 18 "strings" 19 "testing" 20 21 "github.com/cockroachdb/cockroach/pkg/util/randutil" 22 ) 23 24 func TestParseFormat(t *testing.T) { 25 testData := []struct { 26 str string 27 ba BitArray 28 }{ 29 {"", BitArray{words: nil, lastBitsUsed: 0}}, 30 {"0", BitArray{words: []word{0}, lastBitsUsed: 1}}, 31 {"1", BitArray{words: []word{0x8000000000000000}, lastBitsUsed: 1}}, 32 {"0000", BitArray{words: []word{0}, lastBitsUsed: 4}}, 33 {"1010", BitArray{words: []word{0xA000000000000000}, lastBitsUsed: 4}}, 34 {"10111010101111101111101011001110" + "11001010111111101011101010111110", 35 BitArray{words: []word{0xBABEFACECAFEBABE}, lastBitsUsed: 64}}, 36 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + 37 "110010101101110100011110", 38 BitArray{words: []word{0xBABEFACECAFEBABE, 0xCADD1E0000000000}, lastBitsUsed: 24}}, 39 } 40 41 for _, test := range testData { 42 t.Run(test.str, func(t *testing.T) { 43 ba, err := Parse(test.str) 44 if err != nil { 45 t.Fatalf("error during parse: %v", err) 46 } 47 48 if !reflect.DeepEqual(ba, test.ba) { 49 t.Fatalf("expected %+v, got %+v", test.ba, ba) 50 } 51 52 res := ba.String() 53 if res != test.str { 54 t.Fatalf("format expected %q, got %q", test.str, res) 55 } 56 }) 57 } 58 } 59 60 func TestFromEncodingParts(t *testing.T) { 61 testData := []struct { 62 words []uint64 63 lastBitsUsed uint64 64 ba BitArray 65 err string 66 }{ 67 {nil, 0, BitArray{words: nil, lastBitsUsed: 0}, ""}, 68 {[]uint64{0}, 0, BitArray{words: []word{0}, lastBitsUsed: 0}, ""}, 69 {[]uint64{42}, 3, BitArray{words: []word{42}, lastBitsUsed: 3}, ""}, 70 {[]uint64{42}, 65, BitArray{}, "FromEncodingParts: lastBitsUsed must not exceed 64, got 65"}, 71 } 72 73 for _, test := range testData { 74 t.Run(fmt.Sprintf("{%v,%d}", test.words, test.lastBitsUsed), func(t *testing.T) { 75 ba, err := FromEncodingParts(test.words, test.lastBitsUsed) 76 if test.err != "" && (err == nil || test.err != err.Error()) { 77 t.Errorf("expected %q error, but got: %+v", test.err, err) 78 } else if test.err == "" && err != nil { 79 t.Errorf("unexpected error: %s", err) 80 } else if !reflect.DeepEqual(ba, test.ba) { 81 t.Errorf("expected %s, got %s", test.ba.viz(), ba.viz()) 82 } 83 }) 84 } 85 } 86 87 func (d BitArray) viz() string { 88 var buf bytes.Buffer 89 buf.WriteString("bitarray{[") 90 comma := "" 91 for _, w := range d.words { 92 buf.WriteString(comma) 93 for i := 60; i > 0; i -= 4 { 94 if i < 60 { 95 buf.WriteByte(' ') 96 } 97 c := strconv.FormatUint((w>>uint(i))&0xf, 2) 98 if len(c) < 4 { 99 fmt.Fprintf(&buf, "%0*d", 4-len(c), 0) 100 } 101 buf.WriteString(c) 102 } 103 comma = "," 104 } 105 fmt.Fprintf(&buf, "],%d}", d.lastBitsUsed) 106 return buf.String() 107 } 108 109 func TestToWidth(t *testing.T) { 110 testData := []struct { 111 str string 112 toWidth uint 113 ba BitArray 114 }{ 115 {"", 0, BitArray{words: nil, lastBitsUsed: 0}}, 116 {"", 1, BitArray{words: []word{0}, lastBitsUsed: 1}}, 117 {"", 64, BitArray{words: []word{0}, lastBitsUsed: 64}}, 118 {"", 100, BitArray{words: []word{0, 0}, lastBitsUsed: 36}}, 119 {"0", 0, BitArray{words: nil, lastBitsUsed: 0}}, 120 {"0", 1, BitArray{words: []word{0}, lastBitsUsed: 1}}, 121 {"0", 100, BitArray{words: []word{0, 0}, lastBitsUsed: 36}}, 122 {"1", 1, BitArray{words: []word{0x8000000000000000}, lastBitsUsed: 1}}, 123 {"1", 64, BitArray{words: []word{0x8000000000000000}, lastBitsUsed: 64}}, 124 {"1", 100, BitArray{words: []word{0x8000000000000000, 0}, lastBitsUsed: 36}}, 125 {"0000", 4, BitArray{words: []word{0}, lastBitsUsed: 4}}, 126 {"1010", 4, BitArray{words: []word{0xA000000000000000}, lastBitsUsed: 4}}, 127 {"0000", 0, BitArray{words: nil, lastBitsUsed: 0}}, 128 {"1010", 2, BitArray{words: []word{0x8000000000000000}, lastBitsUsed: 2}}, 129 {"10111010101111101111101011001110" + "11001010111111101011101010111110", 130 64, 131 BitArray{words: []word{0xBABEFACECAFEBABE}, lastBitsUsed: 64}}, 132 {"10111010101111101111101011001110" + "11001010111111101011101010111110", 133 16, 134 BitArray{words: []word{0xBABE000000000000}, lastBitsUsed: 16}}, 135 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + 136 "110010101101110100011110", 137 60, 138 BitArray{words: []word{0xBABEFACECAFEBAB0}, lastBitsUsed: 60}}, 139 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + 140 "110010101101110100011110", 141 100, 142 BitArray{words: []word{0xBABEFACECAFEBABE, 0xCADD1E0000000000}, lastBitsUsed: 36}}, 143 } 144 145 for _, test := range testData { 146 t.Run(fmt.Sprintf("%s/%d", test.str, test.toWidth), func(t *testing.T) { 147 ba, err := Parse(test.str) 148 if err != nil { 149 t.Fatalf("error during parse: %v", err) 150 } 151 152 ba = ba.ToWidth(test.toWidth) 153 154 if !reflect.DeepEqual(ba, test.ba) { 155 t.Fatalf("expected %s, got %s", test.ba.viz(), ba.viz()) 156 } 157 158 vs := ba.String() 159 if uint(len(vs)) != test.toWidth { 160 t.Fatalf("expected len %d in representation, got %d", test.toWidth, len(vs)) 161 } 162 if uint(len(test.str)) < test.toWidth { 163 exp := test.str + fmt.Sprintf("%0*d", int(test.toWidth)-len(test.str), 0) 164 if vs != exp { 165 t.Fatalf("expected %q, got %q", exp, vs) 166 } 167 } else { 168 if test.str[:int(test.toWidth)] != vs { 169 t.Fatalf("expected %q, got %q", test.str[:int(test.toWidth)], vs) 170 } 171 } 172 }) 173 } 174 } 175 176 func TestToInt(t *testing.T) { 177 testData := []struct { 178 str string 179 nbits uint 180 exp int64 181 expbits string 182 }{ 183 {"", 0, 0, "0"}, 184 {"", 1, 0, "0"}, 185 {"", 64, 0, "0"}, 186 {"0", 0, 0, "0"}, 187 {"0", 1, 0, "0"}, 188 {"0", 64, 0, "0"}, 189 {"1", 0, 0, "0"}, 190 {"1", 1, -1, "1111111111111111111111111111111111111111111111111111111111111111"}, 191 {"1", 64, 1, "1"}, 192 {"01", 0, 0, "0"}, 193 {"01", 1, -1, "1111111111111111111111111111111111111111111111111111111111111111"}, 194 {"01", 2, 1, "1"}, 195 {"01", 64, 1, "1"}, 196 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + 197 "110010101101110100011110", 6, 30, "11110"}, 198 {"10111010101111101111101011001110" + "11001010111111101011101000111110" + 199 "110010101101110100011110", 32, 0x3ECADD1E, 200 "111110" + "110010101101110100011110"}, 201 } 202 203 for _, test := range testData { 204 t.Run(fmt.Sprintf("%s/%d", test.str, test.nbits), func(t *testing.T) { 205 expbits := strconv.FormatUint(uint64(test.exp), 2) 206 if expbits != test.expbits { 207 t.Fatalf("programming error: invalid expbits: got %q, expected %q", expbits, test.expbits) 208 } 209 ba, err := Parse(test.str) 210 if err != nil { 211 t.Fatal(err) 212 } 213 if ba.String() != test.str { 214 t.Fatalf("expected %q, got %q", test.str, ba.String()) 215 } 216 res := ba.AsInt64(test.nbits) 217 if res != test.exp { 218 t.Fatalf("expected %d (%b), got %d (%b)", test.exp, test.exp, res, uint64(res)) 219 } 220 }) 221 } 222 } 223 224 func TestFromInt(t *testing.T) { 225 largeVal := uint64(0xCAFEBABEDEADBEEF) 226 sLarge := int64(largeVal) 227 uLarge := int64(largeVal ^ (1 << 63)) 228 t.Logf("sLarge = %d (%#x)", sLarge, sLarge) 229 t.Logf("uLarge = %d (%#x)", uLarge, uLarge) 230 testData := []struct { 231 bitlen uint 232 val int64 233 valWidth uint 234 exp string 235 }{ 236 {0, 123, 0, ""}, 237 {0, 123, 64, ""}, 238 {1, 0x1, 0, "0"}, 239 {1, 0x1, 1, "1"}, 240 {2, 0x1, 1, "11" /* sign extend from 1 to 2 bits */}, 241 {64, 0x2, 2, "11111111111111111111111111111111" + "11111111111111111111111111111110"}, 242 {64, 0x2, 3, "00000000000000000000000000000000" + "00000000000000000000000000000010"}, 243 {67, 0x2, 2, "11111111111111111111111111111111" + "11111111111111111111111111111111" + "110"}, 244 {67, 0x2, 3, "00000000000000000000000000000000" + "00000000000000000000000000000000" + "010"}, 245 {131, 0x2, 2, 246 "11111111111111111111111111111111" + "11111111111111111111111111111111" + 247 "11111111111111111111111111111111" + "11111111111111111111111111111111" + "110"}, 248 {131, 0x2, 3, 249 "00000000000000000000000000000000" + "00000000000000000000000000000000" + 250 "00000000000000000000000000000000" + "00000000000000000000000000000000" + "010"}, 251 {67, 0xAA, 8, "11111111111111111111111111111111" + "11111111111111111111111111110101" + "010"}, 252 {67, 0xAA, 9, "00000000000000000000000000000000" + "00000000000000000000000000010101" + "010"}, 253 {131, 0xAA, 8, 254 "11111111111111111111111111111111" + "11111111111111111111111111111111" + 255 "11111111111111111111111111111111" + "11111111111111111111111111110101" + "010"}, 256 {131, 0xAA, 9, 257 "00000000000000000000000000000000" + "00000000000000000000000000000000" + 258 "00000000000000000000000000000000" + "00000000000000000000000000010101" + "010"}, 259 {12, sLarge, 64, "111011101111"}, 260 {64, sLarge, 64, "11001010111111101011101010111110" + "11011110101011011011111011101111"}, 261 {64, uLarge, 64, "01001010111111101011101010111110" + "11011110101011011011111011101111"}, 262 {67, sLarge, 64, "111" + "11001010111111101011101010111110" + "11011110101011011011111011101111"}, 263 {67, uLarge, 64, "000" + "01001010111111101011101010111110" + "11011110101011011011111011101111"}, 264 } 265 266 for _, test := range testData { 267 t.Run(fmt.Sprintf("%d/%0*b", test.bitlen, test.valWidth, test.val), func(t *testing.T) { 268 d := MakeBitArrayFromInt64(test.bitlen, test.val, test.valWidth) 269 res := d.String() 270 if res != test.exp { 271 t.Fatalf("expected %q, got %q", test.exp, res) 272 } 273 }) 274 } 275 276 } 277 278 func TestAnd(t *testing.T) { 279 testData := []struct { 280 lhs, rhs, result string 281 }{ 282 {"", "", ""}, 283 {"0", "0", "0"}, 284 {"0", "1", "0"}, 285 {"1", "0", "0"}, 286 {"1", "1", "1"}, 287 {"1111", "1100", "1100"}, 288 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + "010", 289 "11001010111111101011101010111110" + "10111010101111101111101011001110" + "011", 290 "10001010101111101011101010001110" + "10001010101111101011101010001110" + "010"}, 291 } 292 293 for _, test := range testData { 294 t.Run(test.lhs+"&"+test.rhs, func(t *testing.T) { 295 lhs, err := Parse(test.lhs) 296 if err != nil { 297 t.Fatalf("error during parse: %v", err) 298 } 299 rhs, err := Parse(test.rhs) 300 if err != nil { 301 t.Fatalf("error during parse: %v", err) 302 } 303 res := And(lhs, rhs) 304 resStr := res.String() 305 if resStr != test.result { 306 t.Fatalf("concat expected %q, got %q", test.result, resStr) 307 } 308 res2, err := Parse(resStr) 309 if err != nil { 310 t.Fatal(err) 311 } 312 if !reflect.DeepEqual(res2, res) { 313 t.Fatalf("result does not roundrip, expected %s, got %s", res.viz(), res2.viz()) 314 } 315 }) 316 } 317 } 318 319 func TestOr(t *testing.T) { 320 testData := []struct { 321 lhs, rhs, result string 322 }{ 323 {"", "", ""}, 324 {"0", "0", "0"}, 325 {"0", "1", "1"}, 326 {"1", "0", "1"}, 327 {"1", "1", "1"}, 328 {"1100", "0101", "1101"}, 329 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + "010", 330 "11001010111111101011101010111110" + "10111010101111101111101011001110" + "011", 331 "11111010111111101111101011111110" + "11111010111111101111101011111110" + "011"}, 332 } 333 334 for _, test := range testData { 335 t.Run(test.lhs+"|"+test.rhs, func(t *testing.T) { 336 lhs, err := Parse(test.lhs) 337 if err != nil { 338 t.Fatalf("error during parse: %v", err) 339 } 340 rhs, err := Parse(test.rhs) 341 if err != nil { 342 t.Fatalf("error during parse: %v", err) 343 } 344 res := Or(lhs, rhs) 345 resStr := res.String() 346 if resStr != test.result { 347 t.Fatalf("concat expected %q, got %q", test.result, resStr) 348 } 349 350 res2, err := Parse(resStr) 351 if err != nil { 352 t.Fatal(err) 353 } 354 if !reflect.DeepEqual(res2, res) { 355 t.Fatalf("result does not roundrip, expected %s, got %s", res.viz(), res2.viz()) 356 } 357 }) 358 } 359 } 360 361 func TestXor(t *testing.T) { 362 testData := []struct { 363 lhs, rhs, result string 364 }{ 365 {"", "", ""}, 366 {"0", "0", "0"}, 367 {"0", "1", "1"}, 368 {"1", "0", "1"}, 369 {"1", "1", "0"}, 370 {"1100", "0101", "1001"}, 371 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + "010", 372 "11001010111111101011101010111110" + "10111010101111101111101011001110" + "011", 373 "01110000010000000100000001110000" + "01110000010000000100000001110000" + "001"}, 374 } 375 376 for _, test := range testData { 377 t.Run(test.lhs+"^"+test.rhs, func(t *testing.T) { 378 lhs, err := Parse(test.lhs) 379 if err != nil { 380 t.Fatalf("error during parse: %v", err) 381 } 382 rhs, err := Parse(test.rhs) 383 if err != nil { 384 t.Fatalf("error during parse: %v", err) 385 } 386 res := Xor(lhs, rhs) 387 resStr := res.String() 388 if resStr != test.result { 389 t.Fatalf("concat expected %q, got %q", test.result, resStr) 390 } 391 392 res2, err := Parse(resStr) 393 if err != nil { 394 t.Fatal(err) 395 } 396 if !reflect.DeepEqual(res2, res) { 397 t.Fatalf("result does not roundrip, expected %s, got %s", res.viz(), res2.viz()) 398 } 399 }) 400 } 401 } 402 403 func TestNot(t *testing.T) { 404 testData := []struct { 405 val, res string 406 }{ 407 {"", ""}, 408 {"0", "1"}, 409 {"1", "0"}, 410 {"1100", "0011"}, 411 {"10111010101111101111101011001110" + "11001010111111101011101010111110", 412 "01000101010000010000010100110001" + "00110101000000010100010101000001"}, 413 {"10111010101111101111101011001110" + "11001010111111101011101010111110" + "111", 414 "01000101010000010000010100110001" + "00110101000000010100010101000001" + "000"}, 415 } 416 417 for _, test := range testData { 418 t.Run(test.val, func(t *testing.T) { 419 ba, err := Parse(test.val) 420 if err != nil { 421 t.Fatal(err) 422 } 423 424 res := Not(ba) 425 resStr := res.String() 426 if resStr != test.res { 427 t.Fatalf("not: expected %q, got %q", test.res, resStr) 428 } 429 430 res2, err := Parse(resStr) 431 if err != nil { 432 t.Fatal(err) 433 } 434 if !reflect.DeepEqual(res2, res) { 435 t.Fatalf("result does not roundrip, expected %s, got %s", res.viz(), res2.viz()) 436 } 437 }) 438 } 439 } 440 441 func TestNext(t *testing.T) { 442 testData := []struct { 443 val, res string 444 }{ 445 {"", "0"}, 446 {"0", "00"}, 447 {"1", "10"}, 448 {"1100", "11000"}, 449 {"10111010101111101111101011001110" + "11001010111111101011101010111110", 450 "10111010101111101111101011001110" + "11001010111111101011101010111110" + "0"}, 451 } 452 453 for _, test := range testData { 454 t.Run(test.val, func(t *testing.T) { 455 ba, err := Parse(test.val) 456 if err != nil { 457 t.Fatal(err) 458 } 459 460 res := Next(ba) 461 resStr := res.String() 462 if resStr != test.res { 463 t.Fatalf("not: expected %q, got %q", test.res, resStr) 464 } 465 466 res2, err := Parse(resStr) 467 if err != nil { 468 t.Fatal(err) 469 } 470 if !reflect.DeepEqual(res2, res) { 471 t.Fatalf("result does not roundrip, expected %s, got %s", res.viz(), res2.viz()) 472 } 473 }) 474 } 475 } 476 477 func TestCompare(t *testing.T) { 478 const lt = -1 479 const eq = 0 480 const gt = 1 481 const big = "10111010101111101111101011001110" + "11001010111111101011101010111110" 482 testData := []struct { 483 lhs string 484 cmp int 485 rhs string 486 }{ 487 {"", eq, ""}, 488 {"", lt, "0"}, 489 {"0", lt, "1"}, 490 {"", lt, "1"}, 491 {"0", eq, "0"}, 492 {"0", gt, ""}, 493 {"1", gt, "0"}, 494 {"1", gt, ""}, 495 {"1", eq, "1"}, 496 {"0", lt, "0000"}, 497 {"0000", lt, "00001"}, 498 {"00001", lt, "0001"}, 499 {"0001", lt, "00100"}, 500 {"00100", lt, "00110"}, 501 {"00110", lt, "010"}, 502 {"010", lt, "01001001010101"}, 503 {"01001001010101", lt, "1"}, 504 {"1", lt, "10"}, 505 {"10", lt, "1001001010101"}, 506 {"1001001010101", lt, "11"}, 507 {"11", lt, "11001001010101"}, 508 } 509 510 for _, prefix := range []string{"", big} { 511 for _, test := range testData { 512 const chars = "<=>" 513 t.Run(prefix+test.lhs+chars[test.cmp+1:test.cmp+2]+prefix+test.rhs, func(t *testing.T) { 514 lhs, err := Parse(prefix + test.lhs) 515 if err != nil { 516 t.Fatal(err) 517 } 518 rhs, err := Parse(prefix + test.rhs) 519 if err != nil { 520 t.Fatal(err) 521 } 522 cmp := Compare(lhs, rhs) 523 if cmp != test.cmp { 524 t.Fatalf("compare expected %d, got %d", test.cmp, cmp) 525 } 526 }) 527 } 528 } 529 } 530 531 func TestShift(t *testing.T) { 532 const big = "10111010101111101111101011001110" + "11001010111111101011101010111110" + 533 "11001010111111101011101010111110" + "10111010101111101111101011001110" 534 535 const big2s = "1111 0101 0011 1011 1110 1001 0010 1100" + 536 "0110 1110 1111 0011 0001 1010 1100 0110" + 537 "0000 0011 1101 1110 0101 0100 0010 1010" 538 big2 := strings.Replace(big2s, " ", "", -1) 539 540 testData := []struct { 541 src string 542 sh int64 543 res string 544 }{ 545 {"", 0, ""}, 546 {"", 1, ""}, 547 {"", -1, ""}, 548 {"", 100, ""}, 549 {"", -100, ""}, 550 {"0", 0, "0"}, 551 {"0", 1, "0"}, 552 {"0", -1, "0"}, 553 {"0", 100, "0"}, 554 {"0", -100, "0"}, 555 {"1", 0, "1"}, 556 {"1", 1, "0"}, 557 {"1", -1, "0"}, 558 {"1", 100, "0"}, 559 {"1", -100, "0"}, 560 {"010", 0, "010"}, 561 {"010", 1, "100"}, 562 {"010", -1, "001"}, 563 {"010", 100, "000"}, 564 {"010", -100, "000"}, 565 {big, 1, big[1:] + "0"}, 566 {big, -1, "0" + big[:len(big)-1]}, 567 {big, 100, big[100:] + fmt.Sprintf("%0*d", 100, 0)}, 568 {big, -100, fmt.Sprintf("%0*d", 100, 0) + big[:len(big)-100]}, 569 {big2, 32, big2[32:] + fmt.Sprintf("%0*d", 32, 0)}, 570 // Regression test for #36606. 571 {big2, -32, fmt.Sprintf("%0*d", 32, 0) + big2[:len(big2)-32]}, 572 {big2, 31, big2[31:] + fmt.Sprintf("%0*d", 31, 0)}, 573 // Regression test for #36606. 574 {big2, -31, fmt.Sprintf("%0*d", 31, 0) + big2[:len(big2)-31]}, 575 } 576 577 for _, test := range testData { 578 t.Run(fmt.Sprintf("%s<<%d", test.src, test.sh), func(t *testing.T) { 579 val, err := Parse(test.src) 580 if err != nil { 581 t.Fatal(err) 582 } 583 t.Logf("source val:\n%s", val.viz()) 584 res := val.LeftShiftAny(test.sh) 585 resStr := res.String() 586 if resStr != test.res { 587 t.Fatalf("expected %q, got %q", test.res, resStr) 588 } 589 590 res2, err := Parse(resStr) 591 if err != nil { 592 t.Fatal(err) 593 } 594 if !reflect.DeepEqual(res2, res) { 595 t.Fatalf("result does not roundrip, expected:\n%s, got:\n%s", res.viz(), res2.viz()) 596 } 597 }) 598 } 599 } 600 601 func TestConcat(t *testing.T) { 602 testData := []struct { 603 lhs, rhs, result string 604 }{ 605 {"", "", ""}, 606 {"0", "", "0"}, 607 {"", "0", "0"}, 608 {"0", "0", "00"}, 609 {"1111", "00", "111100"}, 610 {"11", "0000", "110000"}, 611 {"10111010101111101111101011001110" + "11001010111111101011101010111110", "000", 612 "10111010101111101111101011001110" + "11001010111111101011101010111110" + "000"}, 613 {"10111010101111101111101011001110", "11001010111111101011101010111110" + "000", 614 "10111010101111101111101011001110" + "11001010111111101011101010111110" + "000"}, 615 {"000", "10111010101111101111101011001110" + "11001010111111101011101010111110", 616 "000" + "10111010101111101111101011001110" + "11001010111111101011101010111110"}, 617 {"000" + "10111010101111101111101011001110", "11001010111111101011101010111110", 618 "000" + "10111010101111101111101011001110" + "11001010111111101011101010111110"}, 619 {"10111010101111101111101011001110" + "11001010111111101011101010111110", "001", 620 "10111010101111101111101011001110" + "11001010111111101011101010111110" + "001"}, 621 {"10111010101111101111101011001110", "11001010111111101011101010111110" + "001", 622 "10111010101111101111101011001110" + "11001010111111101011101010111110" + "001"}, 623 {"001", "10111010101111101111101011001110" + "11001010111111101011101010111110", 624 "001" + "10111010101111101111101011001110" + "11001010111111101011101010111110"}, 625 {"001" + "10111010101111101111101011001110", "11001010111111101011101010111110", 626 "001" + "10111010101111101111101011001110" + "11001010111111101011101010111110"}, 627 } 628 629 for _, test := range testData { 630 t.Run(test.lhs+"+"+test.rhs, func(t *testing.T) { 631 lhs, err := Parse(test.lhs) 632 if err != nil { 633 t.Fatalf("error during parse: %v", err) 634 } 635 rhs, err := Parse(test.rhs) 636 if err != nil { 637 t.Fatalf("error during parse: %v", err) 638 } 639 res := Concat(lhs, rhs) 640 resStr := res.String() 641 if resStr != test.result { 642 t.Fatalf("concat expected %q, got %q", test.result, resStr) 643 } 644 645 res2, err := Parse(resStr) 646 if err != nil { 647 t.Fatal(err) 648 } 649 if !reflect.DeepEqual(res2, res) { 650 t.Fatalf("result does not roundrip, expected %s, got %s", res.viz(), res2.viz()) 651 } 652 }) 653 } 654 } 655 656 func TestConcatRand(t *testing.T) { 657 rng, _ := randutil.NewPseudoRand() 658 659 for i := 0; i < 1000; i++ { 660 w1 := uint(rng.Int31n(256)) 661 w2 := uint(rng.Int31n(256)) 662 lhs := Rand(rng, w1) 663 rhs := Rand(rng, w2) 664 665 r1c := Concat(lhs, rhs) 666 r1 := r1c.String() 667 r2 := lhs.String() + rhs.String() 668 if r1 != r2 { 669 t.Errorf("%q || %q: expected %q, got %q", lhs, rhs, r2, r1) 670 } 671 672 res2, err := Parse(r1) 673 if err != nil { 674 t.Fatal(err) 675 } 676 if !reflect.DeepEqual(res2, r1c) { 677 t.Fatalf("result does not roundrip, expected %s, got %s", r1c.viz(), res2.viz()) 678 } 679 680 } 681 } 682 683 func TestGetBitAtIndex(t *testing.T) { 684 testData := []struct { 685 bitString, err string 686 index, res int 687 }{ 688 {"1001010", "", 0, 1}, 689 {"1010101", "", 1, 0}, 690 {"111111111111110001010101000000", "", 20, 0}, 691 {"111111111111110001011101000000", "", 20, 1}, 692 {"11111111", "", 7, 1}, 693 {"010110", "GetBitAtIndex: bit index -1 out of valid range (0..5)", -1, 0}, 694 {"", "GetBitAtIndex: bit index 0 out of valid range (0..-1)", 0, 0}, 695 {"10100110", "GetBitAtIndex: bit index 8 out of valid range (0..7)", 8, 0}, 696 } 697 for _, test := range testData { 698 t.Run(fmt.Sprintf("{%v,%d}", test.bitString, test.index), func(t *testing.T) { 699 ba, err := Parse(test.bitString) 700 if err != nil { 701 t.Fatal(err) 702 } 703 res, err := ba.GetBitAtIndex(test.index) 704 if test.err != "" && (err == nil || test.err != err.Error()) { 705 t.Errorf("expected %q error, but got: %+v", test.err, err) 706 } else if test.err == "" && err != nil { 707 t.Errorf("unexpected error: %s", err.Error()) 708 } else if !reflect.DeepEqual(test.res, res) { 709 t.Errorf("expected %d, got %d", test.res, res) 710 } 711 }) 712 } 713 } 714 715 func TestSetBitAtIndex(t *testing.T) { 716 testData := []struct { 717 bitString, err, res string 718 index, toSet int 719 }{ 720 {"1001010", "", "1101010", 1, 1}, 721 {"1010101", "", "0010101", 0, 0}, 722 {"1010101011", "", "1010101011", 0, 1}, 723 {"1010101011", "", "1010101011", 1, 0}, 724 {"111111111111110001010101000000", "", "111111111111110001011101000000", 20, 1}, 725 {"010110", "SetBitAtIndex: bit index -1 out of valid range (0..5)", "", -1, 0}, 726 {"10100110", "SetBitAtIndex: bit index 8 out of valid range (0..7)", "", 8, 0}, 727 {"", "SetBitAtIndex: bit index 0 out of valid range (0..-1)", "", 0, 0}, 728 } 729 for _, test := range testData { 730 t.Run(fmt.Sprintf("{%v,%d,%d}", test.bitString, test.index, test.toSet), func(t *testing.T) { 731 ba, err := Parse(test.bitString) 732 if err != nil { 733 t.Fatal(err) 734 } 735 res, err := ba.SetBitAtIndex(test.index, test.toSet) 736 if test.err != "" && (err == nil || test.err != err.Error()) { 737 t.Errorf("expected %q error, but got: %+v", test.err, err) 738 } else if test.err == "" && err != nil { 739 t.Errorf("unexpected error: %s", err.Error()) 740 } else if !reflect.DeepEqual(test.res, res.String()) { 741 t.Errorf("expected %s, got %s", test.res, res.String()) 742 } 743 }) 744 } 745 }