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 }