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  }