gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/bitmap/bitmap_test.go (about)

     1  // Copyright 2021 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package bitmap
    16  
    17  import (
    18  	"math"
    19  	"slices"
    20  	"testing"
    21  )
    22  
    23  // generateFilledSlice generates a slice fill with numbers.
    24  func generateFilledSlice(min, max, length int) []uint32 {
    25  	if max == min {
    26  		return []uint32{uint32(min)}
    27  	}
    28  	if length > (max - min) {
    29  		return nil
    30  	}
    31  	randSlice := make([]uint32, length)
    32  	if length != 0 {
    33  		rangeNum := uint32((max - min) / length)
    34  		randSlice[0], randSlice[length-1] = uint32(min), uint32(max)
    35  		for i := 1; i < length-1; i++ {
    36  			randSlice[i] = randSlice[i-1] + rangeNum
    37  		}
    38  	}
    39  	return randSlice
    40  }
    41  
    42  // generateFilledBitmap generates a Bitmap filled with fillNum of numbers,
    43  // and returns the slice and bitmap.
    44  func generateFilledBitmap(min, max, fillNum int) ([]uint32, Bitmap) {
    45  	bitmap := New(uint32(max))
    46  	randSlice := generateFilledSlice(min, max, fillNum)
    47  	for i := 0; i < fillNum; i++ {
    48  		bitmap.Add(randSlice[i])
    49  	}
    50  	return randSlice, bitmap
    51  }
    52  
    53  func TestNewBitmap(t *testing.T) {
    54  	tests := []struct {
    55  		name       string
    56  		size       int
    57  		expectSize int
    58  	}{
    59  		{"length 1", 1, 1},
    60  		{"length 1024", 1024, 16},
    61  		{"length 1025", 1025, 17},
    62  	}
    63  
    64  	for _, tt := range tests {
    65  		tt := tt
    66  		t.Run(tt.name, func(t *testing.T) {
    67  			if bitmap := New(uint32(tt.size)); len(bitmap.bitBlock) != tt.expectSize {
    68  				t.Errorf("New created bitmap with %v, bitBlock size: %d, wanted: %d", tt.name, len(bitmap.bitBlock), tt.expectSize)
    69  			}
    70  		})
    71  	}
    72  }
    73  
    74  func TestAdd(t *testing.T) {
    75  	tests := []struct {
    76  		name       string
    77  		bitmapSize int
    78  		addNum     int
    79  	}{
    80  		{"Add with null bitmap.bitBlock", 0, 10},
    81  		{"Add without extending bitBlock", 64, 10},
    82  		{"Add without extending bitblock with margin number", 63, 64},
    83  		{"Add with extended one block", 1024, 1025},
    84  		{"Add with extended more then one block", 1024, 2048},
    85  	}
    86  
    87  	for _, tt := range tests {
    88  		tt := tt
    89  		t.Run(tt.name, func(t *testing.T) {
    90  			bitmap := New(uint32(tt.bitmapSize))
    91  			bitmap.Add(uint32(tt.addNum))
    92  			bitmapSlice := bitmap.ToSlice()
    93  			if bitmapSlice[0] != uint32(tt.addNum) {
    94  				t.Errorf("%v, get number: %d, wanted: %d.", tt.name, bitmapSlice[0], tt.addNum)
    95  			}
    96  		})
    97  	}
    98  }
    99  
   100  func TestRemove(t *testing.T) {
   101  	bitmap := New(uint32(1024))
   102  	firstSlice := generateFilledSlice(0, 511, 50)
   103  	secondSlice := generateFilledSlice(512, 1024, 50)
   104  	for i := 0; i < 50; i++ {
   105  		bitmap.Add(firstSlice[i])
   106  		bitmap.Add(secondSlice[i])
   107  	}
   108  
   109  	for i := 0; i < 50; i++ {
   110  		bitmap.Remove(firstSlice[i])
   111  	}
   112  	bitmapSlice := bitmap.ToSlice()
   113  	if !slices.Equal(bitmapSlice, secondSlice) {
   114  		t.Errorf("After Remove() firstSlice, remained slice: %v, wanted: %v", bitmapSlice, secondSlice)
   115  	}
   116  
   117  	for i := 0; i < 50; i++ {
   118  		bitmap.Remove(secondSlice[i])
   119  	}
   120  	bitmapSlice = bitmap.ToSlice()
   121  	emptySlice := make([]uint32, 0)
   122  	if !slices.Equal(bitmapSlice, emptySlice) {
   123  		t.Errorf("After Remove secondSlice, remained slice: %v, wanted: %v", bitmapSlice, emptySlice)
   124  	}
   125  
   126  }
   127  
   128  // Verify flip bits within one bitBlock, one bit and bits cross multi bitBlocks.
   129  func TestFlipRange(t *testing.T) {
   130  	tests := []struct {
   131  		name           string
   132  		flipRangeMin   int
   133  		flipRangeMax   int
   134  		filledSliceLen int
   135  	}{
   136  		{"Flip one number in bitmap", 77, 77, 1},
   137  		{"Flip numbers within one bitBlocks", 5, 60, 20},
   138  		{"Flip numbers that cross multi bitBlocks", 20, 1000, 300},
   139  	}
   140  
   141  	for _, tt := range tests {
   142  		tt := tt
   143  		t.Run(tt.name, func(t *testing.T) {
   144  			fillSlice, bitmap := generateFilledBitmap(tt.flipRangeMin, tt.flipRangeMax, tt.filledSliceLen)
   145  			flipFillSlice := make([]uint32, 0)
   146  			for i, j := tt.flipRangeMin, 0; i <= tt.flipRangeMax; i++ {
   147  				if uint32(i) != fillSlice[j] {
   148  					flipFillSlice = append(flipFillSlice, uint32(i))
   149  				} else {
   150  					j++
   151  				}
   152  			}
   153  
   154  			bitmap.FlipRange(uint32(tt.flipRangeMin), uint32(tt.flipRangeMax+1))
   155  			flipBitmapSlice := bitmap.ToSlice()
   156  			if !slices.Equal(flipFillSlice, flipBitmapSlice) {
   157  				t.Errorf("%v, flipped slice: %v, wanted: %v", tt.name, flipBitmapSlice, flipFillSlice)
   158  			}
   159  		})
   160  	}
   161  }
   162  
   163  // Verify clear bits within one bitBlock, one bit and bits cross multi bitBlocks.
   164  func TestClearRange(t *testing.T) {
   165  	tests := []struct {
   166  		name          string
   167  		clearRangeMin int
   168  		clearRangeMax int
   169  		bitmapSize    int
   170  	}{
   171  		{"ClearRange clear one number", 5, 5, 64},
   172  		{"ClearRange clear numbers within one bitBlock", 4, 61, 64},
   173  		{"ClearRange clear numbers cross multi bitBlocks", 20, 254, 512},
   174  	}
   175  
   176  	for _, tt := range tests {
   177  		tt := tt
   178  		t.Run(tt.name, func(t *testing.T) {
   179  			bitmap := New(uint32(tt.bitmapSize))
   180  			bitmap.FlipRange(uint32(0), uint32(tt.bitmapSize))
   181  			bitmap.ClearRange(uint32(tt.clearRangeMin), uint32(tt.clearRangeMax+1))
   182  			clearedBitmapSlice := bitmap.ToSlice()
   183  			clearedSlice := make([]uint32, 0)
   184  			for i := 0; i < tt.bitmapSize; i++ {
   185  				if i < tt.clearRangeMin || i > tt.clearRangeMax {
   186  					clearedSlice = append(clearedSlice, uint32(i))
   187  				}
   188  			}
   189  			if !slices.Equal(clearedSlice, clearedBitmapSlice) {
   190  				t.Errorf("%v, cleared slice: %v, wanted: %v", tt.name, clearedBitmapSlice, clearedSlice)
   191  			}
   192  		})
   193  
   194  	}
   195  }
   196  
   197  func TestMinimum(t *testing.T) {
   198  	randSlice, bitmap := generateFilledBitmap(0, 1024, 200)
   199  	min := bitmap.Minimum()
   200  	if min != randSlice[0] {
   201  		t.Errorf("Minimum() returns: %v, wanted: %v", min, randSlice[0])
   202  	}
   203  
   204  	bitmap.ClearRange(uint32(0), uint32(200))
   205  	min = bitmap.Minimum()
   206  	bitmapSlice := bitmap.ToSlice()
   207  	if min != bitmapSlice[0] {
   208  		t.Errorf("After ClearRange, Minimum() returns: %v, wanted: %v", min, bitmapSlice[0])
   209  	}
   210  
   211  	bitmap.FlipRange(uint32(2), uint32(11))
   212  	min = bitmap.Minimum()
   213  	bitmapSlice = bitmap.ToSlice()
   214  	if min != bitmapSlice[0] {
   215  		t.Errorf("After Flip, Minimum() returns: %v, wanted: %v", min, bitmapSlice[0])
   216  	}
   217  }
   218  
   219  func TestMaximum(t *testing.T) {
   220  	randSlice, bitmap := generateFilledBitmap(0, 1024, 200)
   221  	max := bitmap.Maximum()
   222  	if max != randSlice[len(randSlice)-1] {
   223  		t.Errorf("Maximum() returns: %v, wanted: %v", max, randSlice[len(randSlice)-1])
   224  	}
   225  
   226  	bitmap.ClearRange(uint32(1000), uint32(1025))
   227  	max = bitmap.Maximum()
   228  	bitmapSlice := bitmap.ToSlice()
   229  	if max != bitmapSlice[len(bitmapSlice)-1] {
   230  		t.Errorf("After ClearRange, Maximum() returns: %v, wanted: %v", max, bitmapSlice[len(bitmapSlice)-1])
   231  	}
   232  
   233  	bitmap.FlipRange(uint32(1001), uint32(1021))
   234  	max = bitmap.Maximum()
   235  	bitmapSlice = bitmap.ToSlice()
   236  	if max != bitmapSlice[len(bitmapSlice)-1] {
   237  		t.Errorf("After Flip, Maximum() returns: %v, wanted: %v", max, bitmapSlice[len(bitmapSlice)-1])
   238  	}
   239  }
   240  
   241  func TestBitmapNumOnes(t *testing.T) {
   242  	randSlice, bitmap := generateFilledBitmap(0, 1024, 200)
   243  	bitmapOnes := bitmap.GetNumOnes()
   244  	if bitmapOnes != uint32(200) {
   245  		t.Errorf("GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 200)
   246  	}
   247  	// Remove 10 numbers.
   248  	for i := 5; i < 15; i++ {
   249  		bitmap.Remove(randSlice[i])
   250  	}
   251  	bitmapOnes = bitmap.GetNumOnes()
   252  	if bitmapOnes != uint32(190) {
   253  		t.Errorf("After Remove 10 number, GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 190)
   254  	}
   255  	// Remove the 10 number again, the length supposed not change.
   256  	for i := 5; i < 15; i++ {
   257  		bitmap.Remove(randSlice[i])
   258  	}
   259  	bitmapOnes = bitmap.GetNumOnes()
   260  	if bitmapOnes != uint32(190) {
   261  		t.Errorf("After Remove the 10 number again, GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 190)
   262  	}
   263  
   264  	// Add 10 number.
   265  	for i := 1080; i < 1090; i++ {
   266  		bitmap.Add(uint32(i))
   267  	}
   268  	bitmapOnes = bitmap.GetNumOnes()
   269  	if bitmapOnes != uint32(200) {
   270  		t.Errorf("After Add 10 number, GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 200)
   271  	}
   272  
   273  	// Add the 10 number again, the length supposed not change.
   274  	for i := 1080; i < 1090; i++ {
   275  		bitmap.Add(uint32(i))
   276  	}
   277  	bitmapOnes = bitmap.GetNumOnes()
   278  	if bitmapOnes != uint32(200) {
   279  		t.Errorf("After Add the 10 number again, GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 200)
   280  	}
   281  
   282  	// Flip 10 bits from 0 to 1.
   283  	bitmap.FlipRange(uint32(1025), uint32(1035))
   284  	bitmapOnes = bitmap.GetNumOnes()
   285  	if bitmapOnes != uint32(210) {
   286  		t.Errorf("After Flip, GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 210)
   287  	}
   288  
   289  	// ClearRange numbers range from [0, 1025).
   290  	bitmap.ClearRange(uint32(0), uint32(1025))
   291  	bitmapOnes = bitmap.GetNumOnes()
   292  	if bitmapOnes != uint32(20) {
   293  		t.Errorf("After ClearRange, GetNumOnes() returns: %v, wanted: %v", bitmapOnes, 20)
   294  	}
   295  }
   296  
   297  type bitmapForEachTestcase struct {
   298  	start, end uint32
   299  	expected   map[uint32]bool
   300  }
   301  
   302  func TestForEach(t *testing.T) {
   303  	const bitmapSize = 1 << 20
   304  	bitmap := New(bitmapSize)
   305  	bitmap.FlipRange(200, 400)
   306  	bitmap.FlipRange(1003, 1004)
   307  	bitmap.FlipRange(1005, 1006)
   308  	bitmap.FlipRange(1096, 1098)
   309  	testcases := []bitmapForEachTestcase{
   310  		{0, 0, map[uint32]bool{}},
   311  		{0, 100, map[uint32]bool{}},
   312  		{1003, 1004, map[uint32]bool{1003: true}},
   313  		{1003, 1006, map[uint32]bool{1003: true, 1005: true}},
   314  		{1000, 2000, map[uint32]bool{1003: true, 1005: true, 1096: true, 1097: true}},
   315  		{1000, 1097, map[uint32]bool{1003: true, 1005: true, 1096: true}},
   316  		{1060, 1097, map[uint32]bool{1096: true}},
   317  		{0, bitmapSize, func() map[uint32]bool {
   318  			m := make(map[uint32]bool)
   319  			for _, i := range bitmap.ToSlice() {
   320  				m[i] = true
   321  			}
   322  			return m
   323  		}()},
   324  		{234, 356, func() map[uint32]bool {
   325  			m := make(map[uint32]bool)
   326  			for i := uint32(234); i < 356; i++ {
   327  				m[i] = true
   328  			}
   329  			return m
   330  		}()},
   331  	}
   332  	for _, tc := range testcases {
   333  		bitmap.ForEach(tc.start, tc.end, func(idx uint32) bool {
   334  			if _, ok := tc.expected[idx]; !ok {
   335  				t.Errorf("[%d, %d): unexpeced index: %d", tc.start, tc.end, idx)
   336  				return false
   337  			}
   338  			delete(tc.expected, idx)
   339  			return true
   340  		})
   341  		if len(tc.expected) != 0 {
   342  			t.Errorf("[%d-%d): leftover: %#v", tc.start, tc.end, tc.expected)
   343  		}
   344  	}
   345  }
   346  
   347  type BitmapGetFirstTestcase struct {
   348  	queryValue    uint32
   349  	expectedValue uint32
   350  	wantErr       bool
   351  }
   352  
   353  func TestFirstZero(t *testing.T) {
   354  	bitmap := New(uint32(1000))
   355  	bitmap.FlipRange(200, 400)
   356  	testcases := []BitmapGetFirstTestcase{
   357  		{0, 0, false},
   358  		{201, 400, false},
   359  		{200, 400, false},
   360  		{199, 199, false},
   361  		{400, 400, false},
   362  		{10000, math.MaxInt32, true},
   363  	}
   364  	for _, tc := range testcases {
   365  		v, err := bitmap.FirstZero(tc.queryValue)
   366  		if v != tc.expectedValue && (err != nil) == tc.wantErr {
   367  			t.Errorf("FirstZero() returns: %v, wanted: %v", v, tc.expectedValue)
   368  		}
   369  	}
   370  }
   371  
   372  func TestFirstOne(t *testing.T) {
   373  	bitmap := New(uint32(1000))
   374  	bitmap.FlipRange(200, 400)
   375  	bitmap.FlipRange(700, 701)
   376  	testcases := []BitmapGetFirstTestcase{
   377  		{0, 200, false},
   378  		{199, 200, false},
   379  		{200, 200, false},
   380  		{399, 399, false},
   381  		{400, 700, false},
   382  		{700, 700, false},
   383  		{701, math.MaxInt32, true},
   384  		{10000, math.MaxInt32, true},
   385  	}
   386  	for _, tc := range testcases {
   387  		v, err := bitmap.FirstOne(tc.queryValue)
   388  		if v != tc.expectedValue && (err != nil) == tc.wantErr {
   389  			t.Errorf("FirstOne() returns: %v, wanted: %v", v, tc.expectedValue)
   390  		}
   391  	}
   392  }
   393  
   394  func TestGrow(t *testing.T) {
   395  	bitmap := New(uint32(64))
   396  	bitmap.FlipRange(0, 64)
   397  	bitmap.Grow(64)
   398  
   399  	want := make([]uint32, 64)
   400  	for i := 0; i < 128; i++ {
   401  		if i < 64 {
   402  			want[i] = uint32(i)
   403  		}
   404  	}
   405  	if !slices.Equal(bitmap.ToSlice(), want) {
   406  		t.Errorf("Grow() got: %v, want: %v", bitmap.ToSlice(), want)
   407  	}
   408  }