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  }