github.com/fx-zpy/BloomFilter@v0.0.0-20230301111708-fc3d7eb48353/Bloom_test.go (about)

     1  package BloomFilter
     2  
     3  import (
     4  	"math/rand"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  var dict = []rune("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")
    11  
    12  func RandStringRunes(n int) string {
    13  	rand.Seed(time.Now().UnixNano())
    14  	a := make([]rune, n)
    15  	for i := range a {
    16  		a[i] = dict[rand.Intn(len(dict))]
    17  	}
    18  	return string(a)
    19  }
    20  
    21  func TestAdd(t *testing.T) {
    22  	filter := New(1024, 3, false)
    23  	filter.Add([]byte("bloom")).
    24  		AddString("filter").
    25  		AddUint16(uint16(1)).
    26  		AddUint32(uint32(2)).
    27  		AddUint64(uint64(4)).
    28  		AddUint16Batch([]uint16{17, 21, 38}).
    29  		AddUint32Batch([]uint32{22, 31, 109}).
    30  		AddUint64Batch([]uint64{35, 29, 91})
    31  
    32  	t.Logf("bloom exist:%t", filter.Test([]byte("bloom")))
    33  	t.Logf("filter exist:%t", filter.TestString("filter"))
    34  	t.Logf("uint16(1) exist:%t", filter.TestUint16(uint16(1)))
    35  	t.Logf("uint16(17) exist:%t", filter.TestUint16(uint16(17)))
    36  	t.Logf("uint32(2) exist:%t", filter.TestUint32(uint32(2)))
    37  	t.Logf("uint32(22) exist:%t", filter.TestUint32(uint32(22)))
    38  	t.Logf("uint32(4) exist:%t", filter.TestUint64(uint64(4)))
    39  	t.Logf("uint32(35) exist:%t", filter.TestUint64(uint64(35)))
    40  
    41  	t.Logf("blllm exist:%t", filter.Test([]byte("blllm")))
    42  	t.Logf("filtrr exist:%t", filter.TestString("filtrr"))
    43  	t.Logf("uint16(2) exist:%t", filter.TestUint16(uint16(2)))
    44  	t.Logf("uint16(21) exist:%t", filter.TestUint16(uint16(21)))
    45  	t.Logf("uint32(67) exist:%t", filter.TestUint32(uint32(67)))
    46  	t.Logf("uint32(31) exist:%t", filter.TestUint32(uint32(31)))
    47  	t.Logf("uint32(3) exist:%t", filter.TestUint64(uint64(3)))
    48  	t.Logf("uint32(91) exist:%t", filter.TestUint64(uint64(91)))
    49  
    50  }
    51  
    52  func TestAddAndGet(t *testing.T) {
    53  	dataSize := 1000000
    54  	dataMap := make(map[string]struct{}, dataSize)
    55  	stringLen := 30
    56  	filter := New(uint64(dataSize), 3, false)
    57  	for i := 0; i < dataSize; i++ {
    58  		randStr := RandStringRunes(stringLen)
    59  		// add unique random string
    60  		if _, ok := dataMap[randStr]; !ok {
    61  			dataMap[randStr] = struct{}{}
    62  			filter.Add([]byte(randStr))
    63  		}
    64  	}
    65  	for k := range dataMap {
    66  		exist := filter.Test([]byte(k))
    67  		if !exist {
    68  			t.Fatalf("key %s not exist", k)
    69  		}
    70  	}
    71  }
    72  
    73  func TestSync(t *testing.T) {
    74  	sizeData := 100000
    75  	stringLen := 30
    76  	parts := 10
    77  
    78  	filter := New(uint64(sizeData), 3, true)
    79  	// concurrent write and read
    80  	fn := func(size int, wg *sync.WaitGroup) {
    81  		defer wg.Done()
    82  		m := make(map[string]struct{}, size)
    83  		for i := 0; i < size; i++ {
    84  			randStr := RandStringRunes(stringLen)
    85  			// add unique random string
    86  			if _, ok := m[randStr]; !ok {
    87  				m[randStr] = struct{}{}
    88  				// write
    89  				filter.AddString(randStr)
    90  				// read
    91  				exist := filter.TestString(randStr)
    92  				if !exist {
    93  					t.Errorf("key %s not exist", randStr)
    94  				}
    95  			}
    96  		}
    97  	}
    98  	var waitGroup sync.WaitGroup
    99  	for i := 0; i < parts; i++ {
   100  		waitGroup.Add(1)
   101  		go fn(sizeData/parts, &waitGroup)
   102  	}
   103  	waitGroup.Wait()
   104  }
   105  
   106  func TestFalsePositive(t *testing.T) {
   107  	dataSize := 1000000
   108  	dataNoSize := 100000
   109  	dataMap := make(map[string]struct{}, dataSize)
   110  	dataNoMap := make(map[string]struct{}, dataNoSize)
   111  	stringLen := 30
   112  	filter := New(uint64(dataSize), 3, false)
   113  
   114  	for i := 0; i < dataSize; i++ {
   115  		randStr := RandStringRunes(stringLen)
   116  		if _, ok := dataMap[randStr]; !ok {
   117  			dataMap[randStr] = struct{}{}
   118  			filter.AddString(randStr)
   119  		}
   120  	}
   121  	for i := 0; i < dataNoSize; i++ {
   122  		randStr := RandStringRunes(stringLen)
   123  		// add unique random string
   124  		_, ok := dataMap[randStr]
   125  		if !ok {
   126  			dataNoMap[randStr] = struct{}{}
   127  		}
   128  	}
   129  	falsePositiveCount := 0
   130  	for k := range dataNoMap {
   131  		exist := filter.TestString(k)
   132  		if exist {
   133  			falsePositiveCount++
   134  		}
   135  	}
   136  	falsePositiveRatio := float64(falsePositiveCount) / float64(dataNoSize)
   137  	t.Logf("false positive count:%d,false positive ratio:%f", falsePositiveCount, falsePositiveRatio)
   138  }
   139  
   140  func BenchmarkFilter_Add(b *testing.B) {
   141  	b.StopTimer()
   142  	dataTestSize := 100000
   143  	dataTestMap := make(map[string]struct{}, dataTestSize)
   144  	dataTestArr := make([]string, dataTestSize)
   145  	stringLen := 100
   146  	for i := 0; i < dataTestSize; i++ {
   147  		randStr := RandStringRunes(stringLen)
   148  		dataTestMap[randStr] = struct{}{}
   149  		dataTestArr = append(dataTestArr, randStr)
   150  	}
   151  	filter := New(uint64(dataTestSize), 3, false)
   152  	b.ResetTimer()
   153  	b.StartTimer()
   154  	for i := 0; i < len(dataTestArr); i++ {
   155  		filter.Add([]byte(dataTestArr[i]))
   156  	}
   157  
   158  }