github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/asserts/internal/grouping_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package internal_test 21 22 import ( 23 "encoding/base64" 24 "errors" 25 "testing" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/asserts/internal" 30 ) 31 32 func TestInternal(t *testing.T) { TestingT(t) } 33 34 type groupingsSuite struct{} 35 36 var _ = Suite(&groupingsSuite{}) 37 38 func (s *groupingsSuite) TestNewGroupings(c *C) { 39 tests := []struct { 40 n int 41 err string 42 }{ 43 {-10, `n=-10 groups is outside of valid range \(0, 65536\]`}, 44 {0, `n=0 groups is outside of valid range \(0, 65536\]`}, 45 {9, "n=9 groups is not a multiple of 16"}, 46 {16, ""}, 47 {255, "n=255 groups is not a multiple of 16"}, 48 {256, ""}, 49 {1024, ""}, 50 {65536, ""}, 51 {65537, `n=65537 groups is outside of valid range \(0, 65536\]`}, 52 } 53 54 for _, t := range tests { 55 comm := Commentf("%d", t.n) 56 gr, err := internal.NewGroupings(t.n) 57 if t.err == "" { 58 c.Check(err, IsNil, comm) 59 c.Check(gr, NotNil, comm) 60 c.Check(gr.N(), Equals, t.n) 61 } else { 62 c.Check(gr, IsNil, comm) 63 c.Check(err, ErrorMatches, t.err, comm) 64 } 65 } 66 } 67 68 func (s *groupingsSuite) TestAddToAndContains(c *C) { 69 var g internal.Grouping 70 71 gr, err := internal.NewGroupings(16) 72 c.Assert(err, IsNil) 73 74 err = gr.AddTo(&g, 1) 75 c.Assert(err, IsNil) 76 err = gr.AddTo(&g, 3) 77 c.Assert(err, IsNil) 78 err = gr.AddTo(&g, 0) 79 c.Assert(err, IsNil) 80 err = gr.AddTo(&g, 4) 81 c.Assert(err, IsNil) 82 err = gr.AddTo(&g, 2) 83 c.Assert(err, IsNil) 84 85 for i := uint16(0); i < 5; i++ { 86 c.Check(gr.Contains(&g, i), Equals, true) 87 } 88 89 c.Check(gr.Contains(&g, 5), Equals, false) 90 } 91 92 func (s *groupingsSuite) TestOutsideRange(c *C) { 93 var g internal.Grouping 94 95 gr, err := internal.NewGroupings(16) 96 c.Assert(err, IsNil) 97 98 // sanity 99 err = gr.AddTo(&g, 15) 100 c.Assert(err, IsNil) 101 102 err = gr.AddTo(&g, 16) 103 c.Check(err, ErrorMatches, "group exceeds admissible maximum: 16 >= 16") 104 105 err = gr.AddTo(&g, 99) 106 c.Check(err, ErrorMatches, "group exceeds admissible maximum: 99 >= 16") 107 } 108 109 func (s *groupingsSuite) TestSerializeLabel(c *C) { 110 var g internal.Grouping 111 112 gr, err := internal.NewGroupings(128) 113 c.Assert(err, IsNil) 114 115 err = gr.AddTo(&g, 1) 116 c.Assert(err, IsNil) 117 err = gr.AddTo(&g, 3) 118 c.Assert(err, IsNil) 119 err = gr.AddTo(&g, 0) 120 c.Assert(err, IsNil) 121 err = gr.AddTo(&g, 4) 122 c.Assert(err, IsNil) 123 err = gr.AddTo(&g, 2) 124 c.Assert(err, IsNil) 125 126 l := gr.Serialize(&g) 127 128 g1, err := gr.Deserialize(l) 129 c.Check(err, IsNil) 130 131 c.Check(g1, DeepEquals, &g) 132 } 133 134 func (s *groupingsSuite) TestDeserializeLabelErrors(c *C) { 135 var g internal.Grouping 136 137 gr, err := internal.NewGroupings(64) 138 c.Assert(err, IsNil) 139 140 err = gr.AddTo(&g, 0) 141 c.Assert(err, IsNil) 142 err = gr.AddTo(&g, 1) 143 c.Assert(err, IsNil) 144 err = gr.AddTo(&g, 2) 145 c.Assert(err, IsNil) 146 err = gr.AddTo(&g, 3) 147 c.Assert(err, IsNil) 148 err = gr.AddTo(&g, 4) 149 c.Assert(err, IsNil) 150 151 const errPrefix = "invalid serialized grouping label: " 152 153 invalidLabels := []struct { 154 invalid, errSuffix string 155 }{ 156 // not base64 157 {"\x0a\x02\xf4", `illegal base64 data.*`}, 158 // wrong length 159 {base64.RawURLEncoding.EncodeToString([]byte{1}), `not divisible into 16-bits words`}, 160 // not a known group 161 {internal.Serialize([]uint16{5}), `element larger than maximum group`}, 162 // not in order 163 {internal.Serialize([]uint16{0, 2, 1}), `not sorted`}, 164 // bitset: too many words 165 {internal.Serialize([]uint16{0, 0, 0, 0, 0, 0}), `too large`}, 166 // bitset: larger than maxgroup 167 {internal.Serialize([]uint16{6, 0, 0, 0, 0}), `bitset size cannot be possibly larger than maximum group plus 1`}, 168 // bitset: grouping size is too small 169 {internal.Serialize([]uint16{0, 0, 0, 0, 0}), `bitset for too few elements`}, 170 {internal.Serialize([]uint16{1, 0, 0, 0, 0}), `bitset for too few elements`}, 171 {internal.Serialize([]uint16{4, 0, 0, 0, 0}), `bitset for too few elements`}, 172 } 173 174 for _, il := range invalidLabels { 175 _, err := gr.Deserialize(il.invalid) 176 c.Check(err, ErrorMatches, errPrefix+il.errSuffix) 177 } 178 } 179 180 func (s *groupingsSuite) TestIter(c *C) { 181 var g internal.Grouping 182 183 gr, err := internal.NewGroupings(128) 184 c.Assert(err, IsNil) 185 186 err = gr.AddTo(&g, 1) 187 c.Assert(err, IsNil) 188 err = gr.AddTo(&g, 3) 189 c.Assert(err, IsNil) 190 err = gr.AddTo(&g, 0) 191 c.Assert(err, IsNil) 192 err = gr.AddTo(&g, 4) 193 c.Assert(err, IsNil) 194 err = gr.AddTo(&g, 2) 195 c.Assert(err, IsNil) 196 197 elems := []uint16{} 198 f := func(group uint16) error { 199 elems = append(elems, group) 200 return nil 201 } 202 203 err = gr.Iter(&g, f) 204 c.Assert(err, IsNil) 205 c.Check(elems, DeepEquals, []uint16{0, 1, 2, 3, 4}) 206 } 207 208 func (s *groupingsSuite) TestIterError(c *C) { 209 var g internal.Grouping 210 211 gr, err := internal.NewGroupings(32) 212 c.Assert(err, IsNil) 213 214 err = gr.AddTo(&g, 1) 215 c.Assert(err, IsNil) 216 err = gr.AddTo(&g, 3) 217 c.Assert(err, IsNil) 218 219 errBoom := errors.New("boom") 220 n := 0 221 f := func(group uint16) error { 222 n++ 223 return errBoom 224 } 225 226 err = gr.Iter(&g, f) 227 c.Check(err, Equals, errBoom) 228 c.Check(n, Equals, 1) 229 } 230 231 func (s *groupingsSuite) TestRepeated(c *C) { 232 var g internal.Grouping 233 234 gr, err := internal.NewGroupings(64) 235 c.Assert(err, IsNil) 236 237 err = gr.AddTo(&g, 1) 238 c.Assert(err, IsNil) 239 err = gr.AddTo(&g, 0) 240 c.Assert(err, IsNil) 241 err = gr.AddTo(&g, 2) 242 c.Assert(err, IsNil) 243 244 err = gr.AddTo(&g, 1) 245 c.Assert(err, IsNil) 246 err = gr.AddTo(&g, 0) 247 c.Assert(err, IsNil) 248 249 elems := []uint16{} 250 f := func(group uint16) error { 251 elems = append(elems, group) 252 return nil 253 } 254 255 err = gr.Iter(&g, f) 256 c.Assert(err, IsNil) 257 c.Check(elems, DeepEquals, []uint16{0, 1, 2}) 258 } 259 260 func (s *groupingsSuite) TestCopy(c *C) { 261 var g internal.Grouping 262 263 gr, err := internal.NewGroupings(16) 264 c.Assert(err, IsNil) 265 266 err = gr.AddTo(&g, 1) 267 c.Assert(err, IsNil) 268 err = gr.AddTo(&g, 3) 269 c.Assert(err, IsNil) 270 err = gr.AddTo(&g, 0) 271 c.Assert(err, IsNil) 272 err = gr.AddTo(&g, 4) 273 c.Assert(err, IsNil) 274 err = gr.AddTo(&g, 2) 275 c.Assert(err, IsNil) 276 277 g2 := g.Copy() 278 c.Check(g2, DeepEquals, g) 279 280 err = gr.AddTo(&g2, 7) 281 c.Assert(err, IsNil) 282 283 c.Check(gr.Contains(&g, 7), Equals, false) 284 c.Check(gr.Contains(&g2, 7), Equals, true) 285 286 c.Check(g2, Not(DeepEquals), g) 287 } 288 func (s *groupingsSuite) TestBitsetSerializeAndIterSimple(c *C) { 289 gr, err := internal.NewGroupings(32) 290 c.Assert(err, IsNil) 291 292 var elems []uint16 293 f := func(group uint16) error { 294 elems = append(elems, group) 295 return nil 296 } 297 298 var g internal.Grouping 299 err = gr.AddTo(&g, 1) 300 c.Assert(err, IsNil) 301 err = gr.AddTo(&g, 5) 302 c.Assert(err, IsNil) 303 err = gr.AddTo(&g, 17) 304 c.Assert(err, IsNil) 305 err = gr.AddTo(&g, 24) 306 c.Assert(err, IsNil) 307 308 l := gr.Serialize(&g) 309 c.Check(l, DeepEquals, 310 internal.Serialize([]uint16{4, 311 uint16(1<<1 | 1<<5), 312 uint16(1<<(17-16) | 1<<(24-16)), 313 })) 314 315 err = gr.Iter(&g, f) 316 c.Assert(err, IsNil) 317 c.Check(elems, DeepEquals, []uint16{1, 5, 17, 24}) 318 } 319 320 func (s *groupingsSuite) TestBitSet(c *C) { 321 var g internal.Grouping 322 323 gr, err := internal.NewGroupings(64) 324 c.Assert(err, IsNil) 325 326 for i := uint16(0); i < 64; i++ { 327 err := gr.AddTo(&g, i) 328 c.Assert(err, IsNil) 329 c.Check(gr.Contains(&g, i), Equals, true) 330 331 l := gr.Serialize(&g) 332 333 switch i { 334 case 4: 335 c.Check(l, Equals, internal.Serialize([]uint16{5, 0x1f, 0, 0, 0})) 336 case 15: 337 c.Check(l, Equals, internal.Serialize([]uint16{16, 0xffff, 0, 0, 0})) 338 case 16: 339 c.Check(l, Equals, internal.Serialize([]uint16{17, 0xffff, 0x1, 0, 0})) 340 case 63: 341 c.Check(l, Equals, internal.Serialize([]uint16{64, 0xffff, 0xffff, 0xffff, 0xffff})) 342 } 343 344 g1, err := gr.Deserialize(l) 345 c.Check(err, IsNil) 346 347 c.Check(g1, DeepEquals, &g) 348 } 349 350 for i := uint16(63); ; i-- { 351 err := gr.AddTo(&g, i) 352 c.Assert(err, IsNil) 353 c.Check(gr.Contains(&g, i), Equals, true) 354 if i == 0 { 355 break 356 } 357 358 l := gr.Serialize(&g) 359 360 g1, err := gr.Deserialize(l) 361 c.Check(err, IsNil) 362 363 c.Check(g1, DeepEquals, &g) 364 } 365 } 366 367 func (s *groupingsSuite) TestBitsetIter(c *C) { 368 gr, err := internal.NewGroupings(32) 369 c.Assert(err, IsNil) 370 371 var elems []uint16 372 f := func(group uint16) error { 373 elems = append(elems, group) 374 return nil 375 } 376 377 for i := uint16(2); i < 32; i++ { 378 var g internal.Grouping 379 380 err := gr.AddTo(&g, i-2) 381 c.Assert(err, IsNil) 382 err = gr.AddTo(&g, i-1) 383 c.Assert(err, IsNil) 384 err = gr.AddTo(&g, i) 385 c.Assert(err, IsNil) 386 387 err = gr.Iter(&g, f) 388 c.Assert(err, IsNil) 389 c.Check(elems, DeepEquals, []uint16{i - 2, i - 1, i}) 390 391 elems = nil 392 } 393 394 var g internal.Grouping 395 for i := uint16(0); i < 32; i++ { 396 err = gr.AddTo(&g, i) 397 c.Assert(err, IsNil) 398 } 399 400 err = gr.Iter(&g, f) 401 c.Assert(err, IsNil) 402 c.Check(elems, HasLen, 32) 403 } 404 405 func (s *groupingsSuite) TestBitsetIterError(c *C) { 406 gr, err := internal.NewGroupings(16) 407 c.Assert(err, IsNil) 408 409 var g internal.Grouping 410 411 err = gr.AddTo(&g, 0) 412 c.Assert(err, IsNil) 413 err = gr.AddTo(&g, 1) 414 c.Assert(err, IsNil) 415 416 errBoom := errors.New("boom") 417 n := 0 418 f := func(group uint16) error { 419 n++ 420 return errBoom 421 } 422 423 err = gr.Iter(&g, f) 424 c.Check(err, Equals, errBoom) 425 c.Check(n, Equals, 1) 426 } 427 428 func BenchmarkIterBaseline(b *testing.B) { 429 b.StopTimer() 430 431 n := 0 432 f := func(group uint16) error { 433 n++ 434 return nil 435 } 436 437 b.StartTimer() 438 for i := 0; i < b.N; i++ { 439 n = 0 440 for j := uint16(0); j < 64; j++ { 441 f(j) 442 } 443 if n != 64 { 444 b.FailNow() 445 } 446 } 447 } 448 449 func BenchmarkIter4Elems(b *testing.B) { 450 b.StopTimer() 451 452 gr, err := internal.NewGroupings(64) 453 if err != nil { 454 b.FailNow() 455 } 456 457 n := 0 458 f := func(group uint16) error { 459 n++ 460 return nil 461 } 462 463 var g internal.Grouping 464 gr.AddTo(&g, 1) 465 gr.AddTo(&g, 5) 466 gr.AddTo(&g, 17) 467 gr.AddTo(&g, 24) 468 469 b.StartTimer() 470 for i := 0; i < b.N; i++ { 471 n = 0 472 gr.Iter(&g, f) 473 if n != 4 { 474 b.FailNow() 475 } 476 } 477 } 478 479 func BenchmarkIterBitset5Elems(b *testing.B) { 480 b.StopTimer() 481 482 gr, err := internal.NewGroupings(64) 483 if err != nil { 484 b.FailNow() 485 } 486 487 n := 0 488 f := func(group uint16) error { 489 n++ 490 return nil 491 } 492 493 var g internal.Grouping 494 gr.AddTo(&g, 1) 495 gr.AddTo(&g, 5) 496 gr.AddTo(&g, 17) 497 gr.AddTo(&g, 24) 498 gr.AddTo(&g, 33) 499 500 b.StartTimer() 501 for i := 0; i < b.N; i++ { 502 n = 0 503 gr.Iter(&g, f) 504 if n != 5 { 505 b.FailNow() 506 } 507 } 508 } 509 510 func BenchmarkIterBitsetEmptyStretches(b *testing.B) { 511 b.StopTimer() 512 513 gr, err := internal.NewGroupings(64) 514 if err != nil { 515 b.FailNow() 516 } 517 518 n := 0 519 f := func(group uint16) error { 520 n++ 521 return nil 522 } 523 524 var g internal.Grouping 525 gr.AddTo(&g, 0) 526 gr.AddTo(&g, 15) 527 gr.AddTo(&g, 16) 528 gr.AddTo(&g, 31) 529 gr.AddTo(&g, 32) 530 531 b.StartTimer() 532 for i := 0; i < b.N; i++ { 533 n = 0 534 gr.Iter(&g, f) 535 if n != 5 { 536 b.FailNow() 537 } 538 } 539 } 540 541 func BenchmarkIterBitsetEven(b *testing.B) { 542 b.StopTimer() 543 544 gr, err := internal.NewGroupings(64) 545 if err != nil { 546 b.FailNow() 547 } 548 549 n := 0 550 f := func(group uint16) error { 551 n++ 552 return nil 553 } 554 555 var g internal.Grouping 556 for i := 0; i <= 63; i += 2 { 557 gr.AddTo(&g, uint16(i)) 558 } 559 560 b.StartTimer() 561 for i := 0; i < b.N; i++ { 562 n = 0 563 gr.Iter(&g, f) 564 if n != 32 { 565 b.FailNow() 566 } 567 } 568 } 569 570 func BenchmarkIterBitsetOdd(b *testing.B) { 571 b.StopTimer() 572 573 gr, err := internal.NewGroupings(64) 574 if err != nil { 575 b.FailNow() 576 } 577 578 n := 0 579 f := func(group uint16) error { 580 n++ 581 return nil 582 } 583 584 var g internal.Grouping 585 for i := 1; i <= 63; i += 2 { 586 gr.AddTo(&g, uint16(i)) 587 } 588 589 b.StartTimer() 590 for i := 0; i < b.N; i++ { 591 n = 0 592 gr.Iter(&g, f) 593 if n != 32 { 594 b.FailNow() 595 } 596 } 597 } 598 599 func BenchmarkIterBitset0Inc3(b *testing.B) { 600 b.StopTimer() 601 602 gr, err := internal.NewGroupings(64) 603 if err != nil { 604 b.FailNow() 605 } 606 607 n := 0 608 f := func(group uint16) error { 609 n++ 610 return nil 611 } 612 613 var g internal.Grouping 614 for i := 0; i <= 63; i += 3 { 615 gr.AddTo(&g, uint16(i)) 616 } 617 618 b.StartTimer() 619 for i := 0; i < b.N; i++ { 620 n = 0 621 gr.Iter(&g, f) 622 if n != 22 { 623 b.FailNow() 624 } 625 } 626 } 627 628 func BenchmarkIterBitset1Inc3(b *testing.B) { 629 b.StopTimer() 630 631 gr, err := internal.NewGroupings(64) 632 if err != nil { 633 b.FailNow() 634 } 635 636 n := 0 637 f := func(group uint16) error { 638 n++ 639 return nil 640 } 641 642 var g internal.Grouping 643 for i := 1; i <= 63; i += 3 { 644 gr.AddTo(&g, uint16(i)) 645 } 646 647 b.StartTimer() 648 for i := 0; i < b.N; i++ { 649 n = 0 650 gr.Iter(&g, f) 651 if n != 21 { 652 b.FailNow() 653 } 654 } 655 } 656 657 func BenchmarkIterBitset0Inc4(b *testing.B) { 658 b.StopTimer() 659 660 gr, err := internal.NewGroupings(64) 661 if err != nil { 662 b.FailNow() 663 } 664 665 n := 0 666 f := func(group uint16) error { 667 n++ 668 return nil 669 } 670 671 var g internal.Grouping 672 for i := 0; i <= 63; i += 4 { 673 gr.AddTo(&g, uint16(i)) 674 } 675 676 b.StartTimer() 677 for i := 0; i < b.N; i++ { 678 n = 0 679 gr.Iter(&g, f) 680 if n != 16 { 681 b.FailNow() 682 } 683 } 684 } 685 686 func BenchmarkIterBitsetComplete(b *testing.B) { 687 b.StopTimer() 688 689 gr, err := internal.NewGroupings(64) 690 if err != nil { 691 b.FailNow() 692 } 693 694 n := 0 695 f := func(group uint16) error { 696 n++ 697 return nil 698 } 699 700 var g internal.Grouping 701 for i := 0; i <= 63; i++ { 702 gr.AddTo(&g, uint16(i)) 703 } 704 705 b.StartTimer() 706 for i := 0; i < b.N; i++ { 707 n = 0 708 gr.Iter(&g, f) 709 if n != 64 { 710 b.FailNow() 711 } 712 } 713 }