github.com/onflow/atree@v0.6.0/basicarray_test.go (about) 1 /* 2 * Atree - Scalable Arrays and Ordered Maps 3 * 4 * Copyright 2021 Dapper Labs, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package atree 20 21 import ( 22 "math" 23 "testing" 24 25 "github.com/fxamacker/cbor/v2" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func TestBasicArrayAppendAndGet(t *testing.T) { 30 31 const arraySize = 1024 * 16 32 33 storage := newTestBasicStorage(t) 34 35 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 36 37 array, err := NewBasicArray(storage, address) 38 require.NoError(t, err) 39 40 for i := uint64(0); i < arraySize; i++ { 41 err := array.Append(Uint64Value(i)) 42 require.NoError(t, err) 43 } 44 45 for i := uint64(0); i < arraySize; i++ { 46 e, err := array.Get(i) 47 require.NoError(t, err) 48 49 v, ok := e.(Uint64Value) 50 require.True(t, ok) 51 require.Equal(t, i, uint64(v)) 52 } 53 } 54 55 func TestBasicArraySetAndGet(t *testing.T) { 56 57 const arraySize = 1024 * 16 58 59 storage := newTestBasicStorage(t) 60 61 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 62 63 array, err := NewBasicArray(storage, address) 64 require.NoError(t, err) 65 66 for i := uint64(0); i < arraySize; i++ { 67 err := array.Append(Uint64Value(i)) 68 require.NoError(t, err) 69 } 70 71 for i := uint64(0); i < arraySize; i++ { 72 err := array.Set(i, Uint64Value(i*10)) 73 require.NoError(t, err) 74 } 75 76 for i := uint64(0); i < arraySize; i++ { 77 e, err := array.Get(i) 78 require.NoError(t, err) 79 80 v, ok := e.(Uint64Value) 81 require.True(t, ok) 82 require.Equal(t, i*10, uint64(v)) 83 } 84 } 85 86 func TestBasicArrayInsertAndGet(t *testing.T) { 87 t.Run("insert-first", func(t *testing.T) { 88 89 const arraySize = 1024 * 16 90 91 storage := newTestBasicStorage(t) 92 93 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 94 95 array, err := NewBasicArray(storage, address) 96 require.NoError(t, err) 97 98 for i := uint64(0); i < arraySize; i++ { 99 err := array.Insert(0, Uint64Value(arraySize-i-1)) 100 require.NoError(t, err) 101 } 102 103 for i := uint64(0); i < arraySize; i++ { 104 e, err := array.Get(i) 105 require.NoError(t, err) 106 107 v, ok := e.(Uint64Value) 108 require.True(t, ok) 109 require.Equal(t, i, uint64(v)) 110 } 111 }) 112 113 t.Run("insert-last", func(t *testing.T) { 114 115 const arraySize = 1024 * 16 116 117 storage := newTestBasicStorage(t) 118 119 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 120 121 array, err := NewBasicArray(storage, address) 122 require.NoError(t, err) 123 124 for i := uint64(0); i < arraySize; i++ { 125 err := array.Insert(i, Uint64Value(i)) 126 require.NoError(t, err) 127 } 128 129 for i := uint64(0); i < arraySize; i++ { 130 e, err := array.Get(i) 131 require.NoError(t, err) 132 133 v, ok := e.(Uint64Value) 134 require.True(t, ok) 135 require.Equal(t, i, uint64(v)) 136 } 137 }) 138 139 t.Run("insert", func(t *testing.T) { 140 141 const arraySize = 1024 * 16 142 143 storage := newTestBasicStorage(t) 144 145 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 146 147 array, err := NewBasicArray(storage, address) 148 require.NoError(t, err) 149 150 for i := uint64(0); i < arraySize; i += 2 { 151 err := array.Append(Uint64Value(i)) 152 require.NoError(t, err) 153 } 154 155 for i := uint64(1); i < arraySize; i += 2 { 156 err := array.Insert(i, Uint64Value(i)) 157 require.NoError(t, err) 158 } 159 160 for i := uint64(0); i < arraySize; i++ { 161 e, err := array.Get(i) 162 require.NoError(t, err) 163 164 v, ok := e.(Uint64Value) 165 require.True(t, ok) 166 require.Equal(t, i, uint64(v)) 167 } 168 }) 169 } 170 171 func TestBasicArrayRemove(t *testing.T) { 172 173 t.Run("remove-first", func(t *testing.T) { 174 175 const arraySize = 1024 * 16 176 177 storage := newTestBasicStorage(t) 178 179 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 180 181 array, err := NewBasicArray(storage, address) 182 require.NoError(t, err) 183 184 for i := uint64(0); i < arraySize; i++ { 185 err := array.Append(Uint64Value(i)) 186 require.NoError(t, err) 187 } 188 189 require.Equal(t, uint64(arraySize), array.Count()) 190 191 for i := uint64(0); i < arraySize; i++ { 192 v, err := array.Remove(0) 193 require.NoError(t, err) 194 195 e, ok := v.(Uint64Value) 196 require.True(t, ok) 197 require.Equal(t, i, uint64(e)) 198 199 require.Equal(t, arraySize-i-1, array.Count()) 200 } 201 202 require.Equal(t, uint64(0), array.Count()) 203 }) 204 205 t.Run("remove-last", func(t *testing.T) { 206 207 const arraySize = 1024 * 16 208 209 storage := newTestBasicStorage(t) 210 211 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 212 213 array, err := NewBasicArray(storage, address) 214 require.NoError(t, err) 215 216 for i := uint64(0); i < arraySize; i++ { 217 err := array.Append(Uint64Value(i)) 218 require.NoError(t, err) 219 } 220 221 require.Equal(t, uint64(arraySize), array.Count()) 222 223 for i := arraySize - 1; i >= 0; i-- { 224 v, err := array.Remove(uint64(i)) 225 require.NoError(t, err) 226 227 e, ok := v.(Uint64Value) 228 require.True(t, ok) 229 require.Equal(t, uint64(i), uint64(e)) 230 231 require.Equal(t, uint64(i), array.Count()) 232 } 233 234 require.Equal(t, uint64(0), array.Count()) 235 }) 236 237 t.Run("remove", func(t *testing.T) { 238 239 const arraySize = 1024 * 16 240 241 storage := newTestBasicStorage(t) 242 243 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 244 245 array, err := NewBasicArray(storage, address) 246 require.NoError(t, err) 247 248 for i := uint64(0); i < arraySize; i++ { 249 err := array.Append(Uint64Value(i)) 250 require.NoError(t, err) 251 } 252 253 require.Equal(t, uint64(arraySize), array.Count()) 254 255 // Remove every other elements 256 for i := uint64(0); i < array.Count(); i++ { 257 e, err := array.Get(i) 258 require.NoError(t, err) 259 260 v, err := array.Remove(i) 261 require.NoError(t, err) 262 263 require.Equal(t, e, v) 264 } 265 266 for i, j := uint64(0), uint64(1); i < array.Count(); i, j = i+1, j+2 { 267 v, err := array.Get(i) 268 require.NoError(t, err) 269 270 e, ok := v.(Uint64Value) 271 require.True(t, ok) 272 require.Equal(t, j, uint64(e)) 273 } 274 }) 275 } 276 277 func TestBasicArrayRandomAppendSetInsertRemoveMixedTypes(t *testing.T) { 278 279 const ( 280 AppendAction = iota 281 SetAction 282 InsertAction 283 RemoveAction 284 MaxAction 285 ) 286 287 const ( 288 Uint8Type = iota 289 Uint16Type 290 Uint32Type 291 Uint64Type 292 MaxType 293 ) 294 295 const actionCount = 1024 * 16 296 297 r := newRand(t) 298 299 storage := newTestBasicStorage(t) 300 301 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 302 303 array, err := NewBasicArray(storage, address) 304 require.NoError(t, err) 305 306 values := make([]Value, 0, actionCount) 307 308 for i := uint64(0); i < actionCount; i++ { 309 310 var v Value 311 312 switch r.Intn(MaxType) { 313 case Uint8Type: 314 n := r.Intn(math.MaxUint8 + 1) 315 v = Uint8Value(n) 316 case Uint16Type: 317 n := r.Intn(math.MaxUint16 + 1) 318 v = Uint16Value(n) 319 case Uint32Type: 320 v = Uint32Value(r.Uint32()) 321 case Uint64Type: 322 v = Uint64Value(r.Uint64()) 323 } 324 325 switch r.Intn(MaxAction) { 326 327 case AppendAction: 328 values = append(values, v) 329 err := array.Append(v) 330 require.NoError(t, err) 331 332 case SetAction: 333 if array.Count() == 0 { 334 continue 335 } 336 k := r.Intn(int(array.Count())) 337 338 values[k] = v 339 340 err := array.Set(uint64(k), v) 341 require.NoError(t, err) 342 343 case InsertAction: 344 k := r.Intn(int(array.Count() + 1)) 345 346 if k == int(array.Count()) { 347 values = append(values, v) 348 } else { 349 values = append(values, nil) 350 copy(values[k+1:], values[k:]) 351 values[k] = v 352 } 353 354 err := array.Insert(uint64(k), v) 355 require.NoError(t, err) 356 357 case RemoveAction: 358 if array.Count() > 0 { 359 k := r.Intn(int(array.Count())) 360 361 v, err := array.Remove(uint64(k)) 362 require.NoError(t, err) 363 364 require.Equal(t, values[k], v) 365 366 copy(values[k:], values[k+1:]) 367 values = values[:len(values)-1] 368 } 369 } 370 371 require.Equal(t, array.Count(), uint64(len(values))) 372 } 373 374 for k, v := range values { 375 e, err := array.Get(uint64(k)) 376 require.NoError(t, err) 377 require.Equal(t, v, e) 378 } 379 } 380 381 func TestBasicArrayDecodeEncodeRandomData(t *testing.T) { 382 const ( 383 Uint8Type = iota 384 Uint16Type 385 Uint32Type 386 Uint64Type 387 MaxType 388 ) 389 390 encMode, err := cbor.EncOptions{}.EncMode() 391 require.NoError(t, err) 392 393 decMode, err := cbor.DecOptions{}.DecMode() 394 require.NoError(t, err) 395 396 storage := NewBasicSlabStorage(encMode, decMode, decodeStorable, decodeTypeInfo) 397 398 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 399 400 array, err := NewBasicArray(storage, address) 401 require.NoError(t, err) 402 403 r := newRand(t) 404 405 const arraySize = 1024 * 4 406 values := make([]Value, arraySize) 407 for i := uint64(0); i < arraySize; i++ { 408 409 var v Value 410 411 switch r.Intn(MaxType) { 412 case Uint8Type: 413 n := r.Intn(math.MaxUint8 + 1) 414 v = Uint8Value(n) 415 case Uint16Type: 416 n := r.Intn(math.MaxUint16 + 1) 417 v = Uint16Value(n) 418 case Uint32Type: 419 v = Uint32Value(r.Uint32()) 420 case Uint64Type: 421 v = Uint64Value(r.Uint64()) 422 } 423 424 values[i] = v 425 426 err := array.Append(v) 427 require.NoError(t, err) 428 } 429 430 rootID := array.root.Header().id 431 432 // Encode slabs with random data of mixed types 433 m1, err := storage.Encode() 434 require.NoError(t, err) 435 436 // Decode data to new storage 437 438 storage2 := newTestPersistentStorageWithData(t, m1) 439 440 // Create new array from new storage 441 array2, err := NewBasicArrayWithRootID(storage2, rootID) 442 require.NoError(t, err) 443 444 // Get and check every element from new array. 445 for i := uint64(0); i < arraySize; i++ { 446 e, err := array2.Get(i) 447 require.NoError(t, err) 448 require.Equal(t, values[i], e) 449 } 450 }