github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/bloom/bloom_test.go (about) 1 package bloom 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/fluhus/gostuff/bnry" 9 "github.com/fluhus/gostuff/gnum" 10 ) 11 12 func TestLen(t *testing.T) { 13 tests := []struct { 14 bits int 15 want int 16 }{ 17 {1, 8}, 18 {2, 8}, 19 {3, 8}, 20 {4, 8}, 21 {5, 8}, 22 {6, 8}, 23 {7, 8}, 24 {8, 8}, 25 {9, 16}, 26 {16, 16}, 27 {17, 24}, 28 } 29 30 for _, test := range tests { 31 f := New(test.bits, 1) 32 if l := f.NBits(); l != test.want { 33 t.Errorf("New(%v,1).Len()=%v, want %v", 34 test.bits, l, test.want) 35 } 36 if f.NHash() != 1 { 37 t.Errorf("New(%v,1).K()=%v, want 1", 38 test.bits, f.NHash()) 39 } 40 } 41 } 42 43 func TestFilter(t *testing.T) { 44 f := New(80, 4) 45 data := []byte{1, 2, 3, 4} 46 if f.Has(data) { 47 t.Fatalf("Has(%v)=true, want false", data) 48 } 49 if f.Add(data) { 50 t.Fatalf("Add(%v)=true, want false", data) 51 } 52 if !f.Has(data) { 53 t.Fatalf("Has(%v)=false, want true", data) 54 } 55 if !f.Add(data) { 56 t.Fatalf("Add(%v)=false, want true", data) 57 } 58 59 data2 := []byte{4, 3, 2, 1} 60 if f.Has(data2) { 61 t.Fatalf("Has(%v)=true, want false", data2) 62 } 63 } 64 65 func TestNewOptimal(t *testing.T) { 66 n := 1000000 67 p := 0.01 68 f := NewOptimal(n, p) 69 t.Logf("bits=%v, k=%v", f.NBits(), f.NHash()) 70 fp := 0 71 for i := 0; i < n; i++ { 72 buf := bnry.MarshalBinary(uint64(i)) 73 if f.Add(buf) { 74 fp++ 75 } 76 } 77 if fpr := float64(fp) / float64(n); fpr > p { 78 t.Fatalf("fp=%v, want <%v", fpr, p) 79 } 80 } 81 82 func TestEncode(t *testing.T) { 83 data1 := []byte{1, 2, 3, 4} 84 data2 := []byte{4, 3, 2, 1} 85 f1 := New(80, 4) 86 f1.SetSeed(5678) 87 f1.Add(data1) 88 89 if !f1.Has(data1) { 90 t.Fatalf("Has(%v)=false, want true", data1) 91 } 92 if f1.Has(data2) { 93 t.Fatalf("Has(%v)=true, want false", data2) 94 } 95 96 buf := bytes.NewBuffer(nil) 97 if err := f1.Encode(buf); err != nil { 98 t.Fatalf("Encode(...) failed: %v", err) 99 } 100 f2 := &Filter{} 101 if err := f2.Decode(buf); err != nil { 102 t.Fatalf("Decode(...) failed: %v", err) 103 } 104 105 if !bytes.Equal(f1.b, f2.b) { 106 t.Fatalf("Decode(...) bytes=%v, want %v", f2.b, f1.b) 107 } 108 if f1.seed != f2.seed { 109 t.Fatalf("Decode(...) seed=%v, want %v", f2.seed, f1.seed) 110 } 111 112 if !f2.Has(data1) { 113 t.Fatalf("Decode(...).Has(%v)=false, want true", data1) 114 } 115 if f2.Has(data2) { 116 t.Fatalf("Decode(...).Has(%v)=true, want false", data2) 117 } 118 } 119 120 func TestAddFilter(t *testing.T) { 121 data := [][]byte{ 122 {1, 2, 3, 4}, 123 {5, 6, 7, 8}, 124 {9, 10}, 125 } 126 f1 := New(100, 3) 127 f2 := New(100, 3) 128 f2.SetSeed(f1.Seed()) 129 130 f1.Add(data[0]) 131 f2.Add(data[1]) 132 f1.AddFilter(f2) 133 134 if !f1.Has(data[0]) { 135 t.Fatalf("Has(%v)=false, want true", data[0]) 136 } 137 if !f1.Has(data[1]) { 138 t.Fatalf("Has(%v)=false, want true", data[1]) 139 } 140 if f1.Has(data[2]) { 141 t.Fatalf("Has(%v)=true, want false", data[2]) 142 } 143 } 144 145 func TestNElements(t *testing.T) { 146 bf := New(2000, 4) 147 bf.SetSeed(0) 148 n := 100 149 errs := 0 150 for i := 1; i <= n; i++ { 151 bf.Add([]byte{byte(i)}) 152 if gnum.Diff(bf.NElements(), i) > 1 { 153 errs++ 154 } 155 } 156 if errs > n/10 { 157 t.Fatalf("Too many errors: %v, want %v", errs, n/10) 158 } 159 } 160 161 func BenchmarkHas(b *testing.B) { 162 for _, n := range []int{10, 30, 100} { 163 for k := 1; k <= 3; k++ { 164 b.Run(fmt.Sprintf("n=%v,k=%v", n, k), func(b *testing.B) { 165 f := New(1000000, k) 166 buf := make([]byte, n) 167 f.Add(buf) 168 b.ResetTimer() 169 for i := 0; i < b.N; i++ { 170 f.Has(buf) 171 } 172 }) 173 } 174 } 175 } 176 177 func BenchmarkAdd(b *testing.B) { 178 for _, n := range []int{10, 30, 100} { 179 for k := 1; k <= 3; k++ { 180 b.Run(fmt.Sprintf("n=%v,k=%v", n, k), func(b *testing.B) { 181 f := New(1000000, k) 182 buf := make([]byte, n) 183 b.ResetTimer() 184 for i := 0; i < b.N; i++ { 185 f.Add(buf) 186 } 187 }) 188 } 189 } 190 }