github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/m3ninx/postings/roaring/roaring_test.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package roaring
    22  
    23  import (
    24  	"testing"
    25  
    26  	"github.com/m3db/m3/src/m3ninx/postings"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  func TestRoaringPostingsListEmpty(t *testing.T) {
    33  	d := NewPostingsList()
    34  	require.True(t, d.IsEmpty())
    35  	require.Equal(t, 0, d.Len())
    36  }
    37  
    38  func TestRoaringPostingsListMax(t *testing.T) {
    39  	d := NewPostingsList()
    40  	require.NoError(t, d.Insert(42))
    41  	require.NoError(t, d.Insert(78))
    42  	require.NoError(t, d.Insert(103))
    43  
    44  	max, err := d.Max()
    45  	require.NoError(t, err)
    46  	require.Equal(t, postings.ID(103), max)
    47  
    48  	d = NewPostingsList()
    49  	_, err = d.Max()
    50  	require.Error(t, err)
    51  }
    52  
    53  func TestRoaringPostingsListInsert(t *testing.T) {
    54  	d := NewPostingsList()
    55  	require.NoError(t, d.Insert(1))
    56  	require.True(t, d.Contains(1))
    57  	require.Equal(t, 1, d.Len())
    58  	// Idempotency of inserts.
    59  	require.NoError(t, d.Insert(1))
    60  	require.Equal(t, 1, d.Len())
    61  	require.True(t, d.Contains(1))
    62  }
    63  
    64  func TestRoaringPostingsListClone(t *testing.T) {
    65  	d := NewPostingsList()
    66  	require.NoError(t, d.Insert(1))
    67  	require.True(t, d.Contains(1))
    68  	require.Equal(t, 1, d.Len())
    69  
    70  	c := d.CloneAsMutable()
    71  	require.True(t, c.Contains(1))
    72  	require.Equal(t, 1, c.Len())
    73  
    74  	// Ensure only clone is uniquely backed.
    75  	require.NoError(t, c.Insert(2))
    76  	require.True(t, c.Contains(2))
    77  	require.Equal(t, 2, c.Len())
    78  	require.True(t, d.Contains(1))
    79  	require.Equal(t, 1, d.Len())
    80  }
    81  
    82  func TestRoaringPostingsListIntersect(t *testing.T) {
    83  	d := NewPostingsList()
    84  	require.NoError(t, d.Insert(1))
    85  	require.True(t, d.Contains(1))
    86  	require.Equal(t, 1, d.Len())
    87  
    88  	c := d.CloneAsMutable()
    89  	require.True(t, c.Contains(1))
    90  
    91  	require.NoError(t, d.Insert(2))
    92  	require.NoError(t, c.Insert(3))
    93  
    94  	e, err := d.Intersect(c)
    95  	require.NoError(t, err)
    96  	require.True(t, e.Contains(1))
    97  	require.Equal(t, 1, e.Len())
    98  	require.True(t, c.Contains(1))
    99  	require.True(t, c.Contains(3))
   100  	require.Equal(t, 2, c.Len())
   101  }
   102  
   103  func TestRoaringPostingsListDifference(t *testing.T) {
   104  	d := NewPostingsList()
   105  	require.NoError(t, d.Insert(1))
   106  	require.True(t, d.Contains(1))
   107  	require.Equal(t, 1, d.Len())
   108  
   109  	c := d.CloneAsMutable()
   110  	require.True(t, c.Contains(1))
   111  
   112  	require.NoError(t, d.Insert(2))
   113  	require.NoError(t, d.Insert(3))
   114  
   115  	e, err := d.Difference(c)
   116  	require.NoError(t, err)
   117  
   118  	require.False(t, e.Contains(1))
   119  	require.True(t, c.Contains(1))
   120  	require.Equal(t, 2, e.Len())
   121  	require.Equal(t, 1, c.Len())
   122  	require.True(t, e.Contains(3))
   123  	require.True(t, e.Contains(2))
   124  }
   125  
   126  func TestRoaringPostingsListUnion(t *testing.T) {
   127  	d := NewPostingsList()
   128  	require.NoError(t, d.Insert(1))
   129  	require.True(t, d.Contains(1))
   130  	require.Equal(t, 1, d.Len())
   131  
   132  	c := d.CloneAsMutable()
   133  	require.True(t, c.Contains(1))
   134  	require.NoError(t, d.Insert(2))
   135  	require.NoError(t, c.Insert(3))
   136  
   137  	require.NoError(t, d.UnionInPlace(c))
   138  	require.True(t, d.Contains(1))
   139  	require.True(t, d.Contains(2))
   140  	require.True(t, d.Contains(3))
   141  	require.Equal(t, 3, d.Len())
   142  	require.True(t, c.Contains(1))
   143  	require.True(t, c.Contains(3))
   144  	require.Equal(t, 2, c.Len())
   145  }
   146  
   147  func TestRoaringPostingsListAddRange(t *testing.T) {
   148  	d := NewPostingsList()
   149  	require.NoError(t, d.Insert(1))
   150  	require.NoError(t, d.Insert(9))
   151  	require.NoError(t, d.AddRange(3, 5))
   152  
   153  	require.Equal(t, 4, d.Len())
   154  	require.True(t, d.Contains(1))
   155  	require.False(t, d.Contains(2))
   156  	require.True(t, d.Contains(3))
   157  	require.True(t, d.Contains(4))
   158  	require.False(t, d.Contains(5))
   159  	require.True(t, d.Contains(9))
   160  }
   161  
   162  func TestRoaringPostingsListRemoveRange(t *testing.T) {
   163  	d := NewPostingsList()
   164  	require.NoError(t, d.Insert(1))
   165  	require.NoError(t, d.Insert(2))
   166  	require.NoError(t, d.Insert(7))
   167  	require.NoError(t, d.Insert(8))
   168  	require.NoError(t, d.Insert(9))
   169  
   170  	require.NoError(t, d.RemoveRange(2, 8))
   171  	require.Equal(t, 3, d.Len())
   172  	require.True(t, d.Contains(1))
   173  	require.False(t, d.Contains(2))
   174  	require.False(t, d.Contains(7))
   175  	require.True(t, d.Contains(8))
   176  	require.True(t, d.Contains(9))
   177  }
   178  
   179  func TestRoaringPostingsListReset(t *testing.T) {
   180  	d := NewPostingsList()
   181  	require.NoError(t, d.Insert(1))
   182  	require.True(t, d.Contains(1))
   183  	require.Equal(t, 1, d.Len())
   184  	d.Reset()
   185  	require.True(t, d.IsEmpty())
   186  	require.Equal(t, 0, d.Len())
   187  }
   188  
   189  func TestRoaringPostingsListIter(t *testing.T) {
   190  	d := NewPostingsList()
   191  	require.NoError(t, d.Insert(1))
   192  	require.NoError(t, d.Insert(2))
   193  	require.Equal(t, 2, d.Len())
   194  
   195  	it := d.Iterator()
   196  	defer it.Close()
   197  	found := map[postings.ID]bool{
   198  		1: false,
   199  		2: false,
   200  	}
   201  	for it.Next() {
   202  		found[it.Current()] = true
   203  	}
   204  
   205  	for id, ok := range found {
   206  		require.True(t, ok, id)
   207  	}
   208  }
   209  
   210  func TestRoaringPostingsListEqualWithOtherRoaring(t *testing.T) {
   211  	first := NewPostingsList()
   212  	require.NoError(t, first.Insert(42))
   213  	require.NoError(t, first.Insert(44))
   214  	require.NoError(t, first.Insert(51))
   215  
   216  	second := NewPostingsList()
   217  	require.NoError(t, second.Insert(42))
   218  	require.NoError(t, second.Insert(44))
   219  	require.NoError(t, second.Insert(51))
   220  
   221  	require.True(t, first.Equal(second))
   222  }
   223  
   224  func TestRoaringPostingsListNotEqualWithOtherRoaring(t *testing.T) {
   225  	first := NewPostingsList()
   226  	require.NoError(t, first.Insert(42))
   227  	require.NoError(t, first.Insert(44))
   228  	require.NoError(t, first.Insert(51))
   229  
   230  	second := NewPostingsList()
   231  	require.NoError(t, second.Insert(42))
   232  	require.NoError(t, second.Insert(44))
   233  	require.NoError(t, second.Insert(51))
   234  	require.NoError(t, second.Insert(53))
   235  
   236  	require.False(t, first.Equal(second))
   237  }
   238  
   239  func TestRoaringPostingsListEqualWithOtherNonRoaring(t *testing.T) {
   240  	mockCtrl := gomock.NewController(t)
   241  	defer mockCtrl.Finish()
   242  
   243  	first := NewPostingsList()
   244  	require.NoError(t, first.Insert(42))
   245  	require.NoError(t, first.Insert(44))
   246  	require.NoError(t, first.Insert(51))
   247  
   248  	postingsIter := postings.NewMockIterator(mockCtrl)
   249  	gomock.InOrder(
   250  		postingsIter.EXPECT().Next().Return(true),
   251  		postingsIter.EXPECT().Current().Return(postings.ID(42)),
   252  		postingsIter.EXPECT().Next().Return(true),
   253  		postingsIter.EXPECT().Current().Return(postings.ID(44)),
   254  		postingsIter.EXPECT().Next().Return(true),
   255  		postingsIter.EXPECT().Current().Return(postings.ID(51)),
   256  	)
   257  
   258  	second := postings.NewMockList(mockCtrl)
   259  	gomock.InOrder(
   260  		second.EXPECT().Len().Return(3),
   261  		second.EXPECT().Iterator().Return(postingsIter),
   262  	)
   263  
   264  	require.True(t, first.Equal(second))
   265  }
   266  
   267  func TestRoaringPostingsListNotEqualWithOtherNonRoaring(t *testing.T) {
   268  	mockCtrl := gomock.NewController(t)
   269  	defer mockCtrl.Finish()
   270  
   271  	first := NewPostingsList()
   272  	require.NoError(t, first.Insert(42))
   273  	require.NoError(t, first.Insert(44))
   274  	require.NoError(t, first.Insert(51))
   275  
   276  	postingsIter := postings.NewMockIterator(mockCtrl)
   277  	gomock.InOrder(
   278  		postingsIter.EXPECT().Next().Return(true),
   279  		postingsIter.EXPECT().Current().Return(postings.ID(42)),
   280  		postingsIter.EXPECT().Next().Return(true),
   281  		postingsIter.EXPECT().Current().Return(postings.ID(44)),
   282  		postingsIter.EXPECT().Next().Return(true),
   283  		postingsIter.EXPECT().Current().Return(postings.ID(53)),
   284  	)
   285  
   286  	second := postings.NewMockList(mockCtrl)
   287  	gomock.InOrder(
   288  		second.EXPECT().Len().Return(3),
   289  		second.EXPECT().Iterator().Return(postingsIter),
   290  	)
   291  
   292  	require.False(t, first.Equal(second))
   293  }
   294  
   295  func TestRoaringPostingsAddIterator(t *testing.T) {
   296  	mockCtrl := gomock.NewController(t)
   297  	defer mockCtrl.Finish()
   298  
   299  	first := NewPostingsList()
   300  
   301  	postingsIter := postings.NewMockIterator(mockCtrl)
   302  	gomock.InOrder(
   303  		postingsIter.EXPECT().Next().Return(true),
   304  		postingsIter.EXPECT().Current().Return(postings.ID(42)),
   305  		postingsIter.EXPECT().Next().Return(true),
   306  		postingsIter.EXPECT().Current().Return(postings.ID(44)),
   307  		postingsIter.EXPECT().Next().Return(true),
   308  		postingsIter.EXPECT().Current().Return(postings.ID(51)),
   309  		postingsIter.EXPECT().Next().Return(false),
   310  		postingsIter.EXPECT().Err().Return(nil),
   311  		postingsIter.EXPECT().Close().Return(nil),
   312  	)
   313  
   314  	require.NoError(t, first.AddIterator(postingsIter))
   315  	require.Equal(t, 3, first.Len())
   316  	require.True(t, first.Contains(postings.ID(42)))
   317  	require.True(t, first.Contains(postings.ID(44)))
   318  	require.True(t, first.Contains(postings.ID(51)))
   319  }