github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/node_test.go (about)

     1  package iavl
     2  
     3  import (
     4  	"bytes"
     5  	"math/rand"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestNode_aminoSize(t *testing.T) {
    13  	node := &Node{
    14  		key:       randBytes(10),
    15  		value:     randBytes(10),
    16  		version:   1,
    17  		height:    0,
    18  		size:      100,
    19  		hash:      randBytes(20),
    20  		leftHash:  randBytes(20),
    21  		leftNode:  nil,
    22  		rightHash: randBytes(20),
    23  		rightNode: nil,
    24  		persisted: false,
    25  	}
    26  
    27  	// leaf node
    28  	require.Equal(t, 26, node.aminoSize())
    29  
    30  	// non-leaf node
    31  	node.height = 1
    32  	require.Equal(t, 57, node.aminoSize())
    33  }
    34  
    35  func TestNode_validate(t *testing.T) {
    36  	k := []byte("key")
    37  	v := []byte("value")
    38  	h := []byte{1, 2, 3}
    39  	c := &Node{key: []byte("child"), value: []byte("x"), version: 1, size: 1}
    40  
    41  	testcases := map[string]struct {
    42  		node  *Node
    43  		valid bool
    44  	}{
    45  		"nil node":               {nil, false},
    46  		"leaf":                   {&Node{key: k, value: v, version: 1, size: 1}, true},
    47  		"leaf with nil key":      {&Node{key: nil, value: v, version: 1, size: 1}, false},
    48  		"leaf with empty key":    {&Node{key: []byte{}, value: v, version: 1, size: 1}, true},
    49  		"leaf with nil value":    {&Node{key: k, value: nil, version: 1, size: 1}, false},
    50  		"leaf with empty value":  {&Node{key: k, value: []byte{}, version: 1, size: 1}, true},
    51  		"leaf with version 0":    {&Node{key: k, value: v, version: 0, size: 1}, false},
    52  		"leaf with version -1":   {&Node{key: k, value: v, version: -1, size: 1}, false},
    53  		"leaf with size 0":       {&Node{key: k, value: v, version: 1, size: 0}, false},
    54  		"leaf with size 2":       {&Node{key: k, value: v, version: 1, size: 2}, false},
    55  		"leaf with size -1":      {&Node{key: k, value: v, version: 1, size: -1}, false},
    56  		"leaf with left hash":    {&Node{key: k, value: v, version: 1, size: 1, leftHash: h}, false},
    57  		"leaf with left child":   {&Node{key: k, value: v, version: 1, size: 1, leftNode: c}, false},
    58  		"leaf with right hash":   {&Node{key: k, value: v, version: 1, size: 1, rightNode: c}, false},
    59  		"leaf with right child":  {&Node{key: k, value: v, version: 1, size: 1, rightNode: c}, false},
    60  		"inner":                  {&Node{key: k, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, true},
    61  		"inner with nil key":     {&Node{key: nil, value: v, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, false},
    62  		"inner with value":       {&Node{key: k, value: v, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, false},
    63  		"inner with empty value": {&Node{key: k, value: []byte{}, version: 1, size: 1, height: 1, leftHash: h, rightHash: h}, false},
    64  		"inner with left child":  {&Node{key: k, version: 1, size: 1, height: 1, leftHash: h}, true},
    65  		"inner with right child": {&Node{key: k, version: 1, size: 1, height: 1, rightHash: h}, true},
    66  		"inner with no child":    {&Node{key: k, version: 1, size: 1, height: 1}, false},
    67  		"inner with height 0":    {&Node{key: k, version: 1, size: 1, height: 0, leftHash: h, rightHash: h}, false},
    68  	}
    69  
    70  	for desc, tc := range testcases {
    71  		tc := tc // appease scopelint
    72  		t.Run(desc, func(t *testing.T) {
    73  			err := tc.node.validate()
    74  			if tc.valid {
    75  				assert.NoError(t, err)
    76  			} else {
    77  				assert.Error(t, err)
    78  			}
    79  		})
    80  	}
    81  }
    82  
    83  func BenchmarkNode_aminoSize(b *testing.B) {
    84  	node := &Node{
    85  		key:       randBytes(25),
    86  		value:     randBytes(100),
    87  		version:   rand.Int63n(10000000),
    88  		height:    1,
    89  		size:      rand.Int63n(10000000),
    90  		leftHash:  randBytes(20),
    91  		rightHash: randBytes(20),
    92  	}
    93  	b.ReportAllocs()
    94  	b.ResetTimer()
    95  	for i := 0; i < b.N; i++ {
    96  		node.aminoSize()
    97  	}
    98  }
    99  
   100  func BenchmarkNode_WriteBytes(b *testing.B) {
   101  	node := &Node{
   102  		key:       randBytes(25),
   103  		value:     randBytes(100),
   104  		version:   rand.Int63n(10000000),
   105  		height:    1,
   106  		size:      rand.Int63n(10000000),
   107  		leftHash:  randBytes(20),
   108  		rightHash: randBytes(20),
   109  	}
   110  	b.ResetTimer()
   111  	b.Run("NoPreAllocate", func(sub *testing.B) {
   112  		sub.ReportAllocs()
   113  		for i := 0; i < sub.N; i++ {
   114  			var buf bytes.Buffer
   115  			buf.Reset()
   116  			_ = node.writeBytes(&buf)
   117  		}
   118  	})
   119  	b.Run("PreAllocate", func(sub *testing.B) {
   120  		sub.ReportAllocs()
   121  		for i := 0; i < sub.N; i++ {
   122  			var buf bytes.Buffer
   123  			buf.Grow(node.aminoSize())
   124  			_ = node.writeBytes(&buf)
   125  		}
   126  	})
   127  	b.Run("PreAllocate-buffer", func(sub *testing.B) {
   128  		sub.ReportAllocs()
   129  		for i := 0; i < sub.N; i++ {
   130  			var buf bytes.Buffer
   131  			buf.Grow(node.aminoSize())
   132  			_ = node.writeBytesToBuffer(&buf)
   133  		}
   134  	})
   135  }