github.com/MetalBlockchain/metalgo@v1.11.9/utils/bloom/optimal_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package bloom 5 6 import ( 7 "fmt" 8 "math" 9 "testing" 10 11 "github.com/stretchr/testify/require" 12 ) 13 14 const largestFloat64LessThan1 float64 = 1 - 1e-16 15 16 func TestOptimalHashes(t *testing.T) { 17 tests := []struct { 18 numEntries int 19 count int 20 expectedHashes int 21 }{ 22 { // invalid params 23 numEntries: 0, 24 count: 1024, 25 expectedHashes: minHashes, 26 }, 27 { // invalid params 28 numEntries: 1024, 29 count: 0, 30 expectedHashes: maxHashes, 31 }, 32 { 33 numEntries: math.MaxInt, 34 count: 1, 35 expectedHashes: maxHashes, 36 }, 37 { 38 numEntries: 1, 39 count: math.MaxInt, 40 expectedHashes: minHashes, 41 }, 42 { 43 numEntries: 1024, 44 count: 1024, 45 expectedHashes: 6, 46 }, 47 } 48 for _, test := range tests { 49 t.Run(fmt.Sprintf("%d_%d", test.numEntries, test.count), func(t *testing.T) { 50 hashes := OptimalHashes(test.numEntries, test.count) 51 require.Equal(t, test.expectedHashes, hashes) 52 }) 53 } 54 } 55 56 func TestOptimalEntries(t *testing.T) { 57 tests := []struct { 58 count int 59 falsePositiveProbability float64 60 expectedEntries int 61 }{ 62 { // invalid params 63 count: 0, 64 falsePositiveProbability: .5, 65 expectedEntries: minEntries, 66 }, 67 { // invalid params 68 count: 1, 69 falsePositiveProbability: 0, 70 expectedEntries: math.MaxInt, 71 }, 72 { // invalid params 73 count: 1, 74 falsePositiveProbability: 1, 75 expectedEntries: minEntries, 76 }, 77 { 78 count: math.MaxInt, 79 falsePositiveProbability: math.SmallestNonzeroFloat64, 80 expectedEntries: math.MaxInt, 81 }, 82 { 83 count: 1024, 84 falsePositiveProbability: largestFloat64LessThan1, 85 expectedEntries: minEntries, 86 }, 87 { 88 count: 1024, 89 falsePositiveProbability: .01, 90 expectedEntries: 1227, 91 }, 92 } 93 for _, test := range tests { 94 t.Run(fmt.Sprintf("%d_%f", test.count, test.falsePositiveProbability), func(t *testing.T) { 95 entries := OptimalEntries(test.count, test.falsePositiveProbability) 96 require.Equal(t, test.expectedEntries, entries) 97 }) 98 } 99 } 100 101 func TestEstimateEntries(t *testing.T) { 102 tests := []struct { 103 numHashes int 104 numEntries int 105 falsePositiveProbability float64 106 expectedEntries int 107 }{ 108 { // invalid params 109 numHashes: 0, 110 numEntries: 2_048, 111 falsePositiveProbability: .5, 112 expectedEntries: 0, 113 }, 114 { // invalid params 115 numHashes: 1, 116 numEntries: 0, 117 falsePositiveProbability: .5, 118 expectedEntries: 0, 119 }, 120 { // invalid params 121 numHashes: 1, 122 numEntries: 1, 123 falsePositiveProbability: 2, 124 expectedEntries: math.MaxInt, 125 }, 126 { // invalid params 127 numHashes: 1, 128 numEntries: 1, 129 falsePositiveProbability: -1, 130 expectedEntries: 0, 131 }, 132 { 133 numHashes: 8, 134 numEntries: 2_048, 135 falsePositiveProbability: 0, 136 expectedEntries: 0, 137 }, 138 { // params from OptimalParameters(10_000, .01) 139 numHashes: 7, 140 numEntries: 11_982, 141 falsePositiveProbability: .01, 142 expectedEntries: 9_993, 143 }, 144 { // params from OptimalParameters(100_000, .001) 145 numHashes: 10, 146 numEntries: 179_720, 147 falsePositiveProbability: .001, 148 expectedEntries: 100_000, 149 }, 150 { // params from OptimalParameters(10_000, .01) 151 numHashes: 7, 152 numEntries: 11_982, 153 falsePositiveProbability: .05, 154 expectedEntries: 14_449, 155 }, 156 { // params from OptimalParameters(10_000, .01) 157 numHashes: 7, 158 numEntries: 11_982, 159 falsePositiveProbability: 1, 160 expectedEntries: math.MaxInt, 161 }, 162 { // params from OptimalParameters(10_000, .01) 163 numHashes: 7, 164 numEntries: 11_982, 165 falsePositiveProbability: math.SmallestNonzeroFloat64, 166 expectedEntries: 0, 167 }, 168 { // params from OptimalParameters(10_000, .01) 169 numHashes: 7, 170 numEntries: 11_982, 171 falsePositiveProbability: largestFloat64LessThan1, 172 expectedEntries: math.MaxInt, 173 }, 174 } 175 for _, test := range tests { 176 t.Run(fmt.Sprintf("%d_%d_%f", test.numHashes, test.numEntries, test.falsePositiveProbability), func(t *testing.T) { 177 entries := EstimateCount(test.numHashes, test.numEntries, test.falsePositiveProbability) 178 require.Equal(t, test.expectedEntries, entries) 179 }) 180 } 181 } 182 183 func FuzzOptimalHashes(f *testing.F) { 184 f.Fuzz(func(t *testing.T, numEntries, count int) { 185 hashes := OptimalHashes(numEntries, count) 186 require.GreaterOrEqual(t, hashes, minHashes) 187 require.LessOrEqual(t, hashes, maxHashes) 188 }) 189 } 190 191 func FuzzOptimalEntries(f *testing.F) { 192 f.Fuzz(func(t *testing.T, count int, falsePositiveProbability float64) { 193 entries := OptimalEntries(count, falsePositiveProbability) 194 require.GreaterOrEqual(t, entries, minEntries) 195 }) 196 } 197 198 func FuzzEstimateEntries(f *testing.F) { 199 f.Fuzz(func(t *testing.T, numHashes, numEntries int, falsePositiveProbability float64) { 200 entries := EstimateCount(numHashes, numEntries, falsePositiveProbability) 201 require.GreaterOrEqual(t, entries, 0) 202 }) 203 }