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