github.com/ledgerwatch/erigon-lib@v1.0.0/patricia/patricia_fuzz_test.go (about) 1 //go:build !nofuzz 2 3 /* 4 Copyright 2021 Erigon contributors 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 package patricia 19 20 import ( 21 "bytes" 22 "encoding/binary" 23 "fmt" 24 "testing" 25 ) 26 27 // go test -trimpath -v -fuzz=FuzzPatricia -fuzztime=10s ./patricia 28 29 func FuzzPatricia(f *testing.F) { 30 f.Fuzz(func(t *testing.T, build []byte, test []byte) { 31 var n node 32 keyMap := make(map[string][]byte) 33 i := 0 34 for i < len(build) { 35 keyLen := int(build[i]>>4) + 1 36 valLen := int(build[i]&15) + 1 37 i++ 38 var key []byte 39 var val []byte 40 for keyLen > 0 && i < len(build) { 41 key = append(key, build[i]) 42 i++ 43 keyLen-- 44 } 45 for valLen > 0 && i < len(build) { 46 val = append(val, build[i]) 47 i++ 48 valLen-- 49 } 50 n.insert(key, val) 51 keyMap[string(key)] = val 52 } 53 var testKeys [][]byte 54 i = 0 55 for i < len(test) { 56 keyLen := int(test[i]>>4) + 1 57 i++ 58 var key []byte 59 for keyLen > 0 && i < len(test) { 60 key = append(key, test[i]) 61 i++ 62 keyLen-- 63 } 64 if _, ok := keyMap[string(key)]; !ok { 65 testKeys = append(testKeys, key) 66 } 67 } 68 // Test for keys 69 for key, vals := range keyMap { 70 v, ok := n.get([]byte(key)) 71 if ok { 72 if !bytes.Equal(vals, v.([]byte)) { 73 t.Errorf("for key %x expected value %x, got %x", key, vals, v.([]byte)) 74 } 75 } 76 } 77 // Test for non-existent keys 78 for _, key := range testKeys { 79 _, ok := n.get(key) 80 if ok { 81 t.Errorf("unexpected key found [%x]", key) 82 } 83 } 84 }) 85 } 86 87 func FuzzLongestMatch(f *testing.F) { 88 f.Fuzz(func(t *testing.T, build []byte, test []byte) { 89 var pt PatriciaTree 90 keyMap := make(map[string][]byte) 91 i := 0 92 for i < len(build) { 93 keyLen := int(build[i]>>4) + 1 94 valLen := int(build[i]&15) + 1 95 i++ 96 var key []byte 97 var val []byte 98 for keyLen > 0 && i < len(build) { 99 key = append(key, build[i]) 100 i++ 101 keyLen-- 102 } 103 for valLen > 0 && i < len(build) { 104 val = append(val, build[i]) 105 i++ 106 valLen-- 107 } 108 pt.Insert(key, val) 109 keyMap[string(key)] = val 110 } 111 var keys []string 112 for key := range keyMap { 113 keys = append(keys, key) 114 } 115 if len(keys) == 0 { 116 t.Skip() 117 } 118 var data []byte 119 for i := 0; i < 4*(len(test)/4); i += 4 { 120 keyIdx := int(binary.BigEndian.Uint32(test[i : i+4])) 121 keyIdx = keyIdx % len(keys) 122 key := []byte(keys[keyIdx]) 123 data = append(data, key...) 124 for j := 0; j < len(key); j++ { 125 data = append(data, key[len(key)-1-j]) 126 } 127 } 128 mf := NewMatchFinder(&pt) 129 m1 := mf.FindLongestMatches(data) 130 mf2 := NewMatchFinder2(&pt) 131 m2 := mf2.FindLongestMatches(data) 132 if len(m1) == len(m2) { 133 for i, m := range m1 { 134 mm := m2[i] 135 if m.Start != mm.Start || m.End != mm.End { 136 t.Errorf("mismatch, expected %+v, got %+v", m, mm) 137 } 138 } 139 } else { 140 t.Errorf("matches %d, expected %d", len(m2), len(m1)) 141 for _, m := range m1 { 142 fmt.Printf("%+v, match1: [%x]\n", m, data[m.Start:m.End]) 143 } 144 for _, m := range m2 { 145 fmt.Printf("%+v, match2: [%x]\n", m, data[m.Start:m.End]) 146 } 147 } 148 }) 149 }