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  }