github.com/ledgerwatch/erigon-lib@v1.0.0/recsplit/eliasfano32/elias_fano_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 eliasfano32 19 20 import ( 21 "bytes" 22 "testing" 23 ) 24 25 // go test -trimpath -v -fuzz=FuzzSingleEliasFano ./recsplit/eliasfano32 26 // go test -trimpath -v -fuzz=FuzzDoubleEliasFano ./recsplit/eliasfano32 27 28 func FuzzSingleEliasFano(f *testing.F) { 29 f.Fuzz(func(t *testing.T, in []byte) { 30 if len(in)%2 == 1 { 31 t.Skip() 32 } 33 if len(in) == 0 { 34 t.Skip() 35 } 36 for len(in) < int(2*superQ) { // make input large enough to trigger supreQ jump logic 37 in = append(in, in...) 38 } 39 40 // Treat each byte of the sequence as difference between previous value and the next 41 count := len(in) 42 keys := make([]uint64, count+1) 43 for i, b := range in { 44 keys[i+1] = keys[i] + uint64(b) 45 } 46 ef := NewEliasFano(uint64(count+1), keys[count]) 47 for _, c := range keys { 48 ef.AddOffset(c) 49 } 50 ef.Build() 51 52 // Try to read from ef 53 for i := 0; i < count; i++ { 54 if ef.Get(uint64(i)) != keys[i] { 55 t.Fatalf("i %d: got %d, expected %d", i, ef.Get(uint64(i)), keys[i]) 56 } 57 } 58 59 it := ef.Iterator() 60 for it.HasNext() { 61 it.Next() 62 } 63 buf := bytes.NewBuffer(nil) 64 ef.Write(buf) 65 if ef.Max() != Max(buf.Bytes()) { 66 t.Fatalf("max: got %d, expected %d", ef.Max(), Max(buf.Bytes())) 67 } 68 if ef.Min() != Min(buf.Bytes()) { 69 t.Fatalf("min: got %d, expected %d", ef.Min(), Min(buf.Bytes())) 70 } 71 if ef.Count() != Count(buf.Bytes()) { 72 t.Fatalf("max: got %d, expected %d", ef.Count(), Count(buf.Bytes())) 73 } 74 }) 75 } 76 77 func FuzzDoubleEliasFano(f *testing.F) { 78 f.Fuzz(func(t *testing.T, in []byte) { 79 if len(in)%2 == 1 { 80 t.Skip() 81 } 82 if len(in) == 0 { 83 t.Skip() 84 } 85 for len(in) < int(2*superQ) { // make input large enough to trigger supreQ jump logic 86 in = append(in, in...) 87 } 88 89 var ef DoubleEliasFano 90 // Treat each byte of the sequence as difference between previous value and the next 91 numBuckets := len(in) / 2 92 cumKeys := make([]uint64, numBuckets+1) 93 position := make([]uint64, numBuckets+1) 94 for i, b := range in[:numBuckets] { 95 cumKeys[i+1] = cumKeys[i] + uint64(b) 96 } 97 for i, b := range in[numBuckets:] { 98 position[i+1] = position[i] + uint64(b) 99 } 100 ef1 := NewEliasFano(uint64(numBuckets+1), cumKeys[numBuckets]) 101 for _, c := range cumKeys { 102 ef1.AddOffset(c) 103 } 104 ef1.Build() 105 ef2 := NewEliasFano(uint64(numBuckets+1), position[numBuckets]) 106 for _, p := range position { 107 ef2.AddOffset(p) 108 } 109 ef2.Build() 110 ef.Build(cumKeys, position) 111 // Try to read from ef 112 for bucket := 0; bucket < numBuckets; bucket++ { 113 cumKey, bitPos := ef.Get2(uint64(bucket)) 114 if cumKey != cumKeys[bucket] { 115 t.Fatalf("bucket %d: cumKey from EF = %d, expected %d", bucket, cumKey, cumKeys[bucket]) 116 } 117 if bitPos != position[bucket] { 118 t.Fatalf("bucket %d: position from EF = %d, expected %d", bucket, bitPos, position[bucket]) 119 } 120 cumKey = ef1.Get(uint64(bucket)) 121 if cumKey != cumKeys[bucket] { 122 t.Fatalf("bucket %d: cumKey from EF1 = %d, expected %d", bucket, cumKey, cumKeys[bucket]) 123 } 124 bitPos = ef2.Get(uint64(bucket)) 125 if bitPos != position[bucket] { 126 t.Fatalf("bucket %d: position from EF2 = %d, expected %d", bucket, bitPos, position[bucket]) 127 } 128 } 129 for bucket := 0; bucket < numBuckets; bucket++ { 130 cumKey, cumKeysNext, bitPos := ef.Get3(uint64(bucket)) 131 if cumKey != cumKeys[bucket] { 132 t.Fatalf("bucket %d: cumKey from EF = %d, expected %d", bucket, cumKey, cumKeys[bucket]) 133 } 134 if bitPos != position[bucket] { 135 t.Fatalf("bucket %d: position from EF = %d, expected %d", bucket, bitPos, position[bucket]) 136 } 137 if cumKeysNext != cumKeys[bucket+1] { 138 t.Fatalf("bucket %d: cumKeysNext from EF = %d, expected %d", bucket, cumKeysNext, cumKeys[bucket+1]) 139 } 140 } 141 }) 142 }