-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathqf_test.go
134 lines (122 loc) · 2.87 KB
/
qf_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package qf
import (
"fmt"
"math/rand"
"testing"
"time"
)
func TestNewProbability(t *testing.T) {
tests := []struct {
P float64
S int
}{{0.001, 10000}, {0.01, 10000}, {0.1, 10000}, {0.3, 10000},
{0.001, 100000}, {0.01, 100000}, {0.1, 100000}, {0.3, 100000}}
for _, test := range tests {
qf := NewProbability(test.S, test.P)
qf.AddAll(generateItems(test.S))
if qf.FPProbability() > test.P {
t.Fatal("False positive rate too high, asked", test.P, "got", qf.FPProbability(), "test", test)
}
}
}
func TestAddBasic(t *testing.T) {
qf := New(8, 3)
added := generateItems(100) // []string{"brown", "fox", "jump"}
not := []string{"turbo", "negro"}
qf.AddAll(added)
qf.info()
for _, s := range added {
if !qf.Contains(s) {
t.Fatal("Filter returned false for an added item")
}
}
for _, s := range not {
if qf.Contains(s) {
t.Fatal("Filter returned true for not added item")
}
}
}
func TestFalseNegatives(t *testing.T) {
tests := []struct {
P float64
S int
}{{0.01, 1000}, {0.01, 10000}, {0.01, 100000}}
for _, test := range tests {
qf := NewProbability(test.S, test.P)
items := generateItems(test.S / 2)
qf.AddAll(items)
for _, item := range items {
if !qf.Contains(item) {
t.Fatal("False negative, key:", item, "size", test.S, "probability", test.P)
}
}
}
}
func TestFalsePositives(t *testing.T) {
tests := []struct {
P float64
S int
}{{0.001, 1000}, {0.01, 1000}, {0.1, 1000}, {0.3, 1000},
{0.001, 10000}, {0.01, 10000}, {0.1, 10000}, {0.3, 10000},
{0.001, 100000}, {0.01, 100000}, {0.1, 100000}, {0.3, 100000}}
for _, test := range tests {
qf := NewProbability(test.S, test.P)
items := generateItems(test.S / 2)
itemsB := generateItems(test.S / 2)
qf.AddAll(items)
var positives int
for _, item := range itemsB {
if qf.Contains(item) {
positives++
}
}
for _, item := range items {
if !qf.Contains(item) {
t.Fatal("False negative")
}
}
allowed := float64(test.S) * test.P * 2.0
if float64(positives) > allowed {
t.Fatal("Too many positives, got", positives, "limit is", allowed, "test:", test)
}
}
}
func BenchmarkAdd(b *testing.B) {
qf := NewProbability(b.N*2, 0.01)
items := generateItems(b.N)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
qf.Add(items[i])
}
b.StopTimer()
}
func BenchmarkContains(b *testing.B) {
qf := NewProbability(b.N*2, 0.01)
items := generateItems(b.N)
for i := 0; i < b.N; i++ {
if i%2 == 0 {
qf.Add(items[i])
}
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
qf.Contains(items[i])
}
b.StopTimer()
}
var generatedSet int
func init() {
rand.Seed(time.Now().UTC().UnixNano())
generatedSet = rand.Int()
}
func generateItems(len int) []string {
setNum := generatedSet
generatedSet++
out := make([]string, 0, len)
for i := 0; i < len; i++ {
out = append(out, fmt.Sprintf("item:%d:%d", setNum, i))
}
return out
}