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