summaryrefslogtreecommitdiffstats
path: root/mfbt/tests/TestBloomFilter.cpp
blob: a2338588266cfbf731d1c7f043bbc57e8fbdafb0 (plain)
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
135
136
137
138
139
140
141
142
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/Assertions.h"
#include "mozilla/BloomFilter.h"
#include "mozilla/UniquePtr.h"

#include <stddef.h>
#include <stdint.h>

using mozilla::BitBloomFilter;
using mozilla::CountingBloomFilter;

class FilterChecker {
 public:
  explicit FilterChecker(uint32_t aHash) : mHash(aHash) {}

  uint32_t hash() const { return mHash; }

 private:
  uint32_t mHash;
};

void testBitBloomFilter() {
  const mozilla::UniquePtr filter =
      mozilla::MakeUnique<BitBloomFilter<12, FilterChecker>>();
  MOZ_RELEASE_ASSERT(filter);

  FilterChecker one(1);
  FilterChecker two(0x20000);

  filter->add(&one);
  MOZ_RELEASE_ASSERT(filter->mightContain(&one), "Filter should contain 'one'");

  MOZ_RELEASE_ASSERT(!filter->mightContain(&two),
                     "Filter claims to contain 'two' when it should not");

  // Test multiple addition
  filter->add(&two);
  MOZ_RELEASE_ASSERT(filter->mightContain(&two),
                     "Filter should contain 'two' after 'two' is added");
  filter->add(&two);
  MOZ_RELEASE_ASSERT(filter->mightContain(&two),
                     "Filter should contain 'two' after 'two' is added again");

  filter->clear();

  MOZ_RELEASE_ASSERT(!filter->mightContain(&one), "clear() failed to work");
  MOZ_RELEASE_ASSERT(!filter->mightContain(&two), "clear() failed to work");
}

void testCountingBloomFilter() {
  const mozilla::UniquePtr filter =
      mozilla::MakeUnique<CountingBloomFilter<12, FilterChecker>>();
  MOZ_RELEASE_ASSERT(filter);

  FilterChecker one(1);
  FilterChecker two(0x20000);
  FilterChecker many(0x10000);
  FilterChecker multiple(0x20001);

  filter->add(&one);
  MOZ_RELEASE_ASSERT(filter->mightContain(&one), "Filter should contain 'one'");

  MOZ_RELEASE_ASSERT(!filter->mightContain(&multiple),
                     "Filter claims to contain 'multiple' when it should not");

  MOZ_RELEASE_ASSERT(filter->mightContain(&many),
                     "Filter should contain 'many' (false positive)");

  filter->add(&two);
  MOZ_RELEASE_ASSERT(filter->mightContain(&multiple),
                     "Filter should contain 'multiple' (false positive)");

  // Test basic removals
  filter->remove(&two);
  MOZ_RELEASE_ASSERT(
      !filter->mightContain(&multiple),
      "Filter claims to contain 'multiple' when it should not after two "
      "was removed");

  // Test multiple addition/removal
  const size_t FILTER_SIZE = 255;
  for (size_t i = 0; i < FILTER_SIZE - 1; ++i) {
    filter->add(&two);
  }
  MOZ_RELEASE_ASSERT(
      filter->mightContain(&multiple),
      "Filter should contain 'multiple' after 'two' added lots of times "
      "(false positive)");

  for (size_t i = 0; i < FILTER_SIZE - 1; ++i) {
    filter->remove(&two);
  }
  MOZ_RELEASE_ASSERT(
      !filter->mightContain(&multiple),
      "Filter claims to contain 'multiple' when it should not after two "
      "was removed lots of times");

  // Test overflowing the filter buckets
  for (size_t i = 0; i < FILTER_SIZE + 1; ++i) {
    filter->add(&two);
  }
  MOZ_RELEASE_ASSERT(
      filter->mightContain(&multiple),
      "Filter should contain 'multiple' after 'two' added lots more "
      "times (false positive)");

  for (size_t i = 0; i < FILTER_SIZE + 1; ++i) {
    filter->remove(&two);
  }
  MOZ_RELEASE_ASSERT(
      filter->mightContain(&multiple),
      "Filter claims to not contain 'multiple' even though we should "
      "have run out of space in the buckets (false positive)");
  MOZ_RELEASE_ASSERT(
      filter->mightContain(&two),
      "Filter claims to not contain 'two' even though we should have "
      "run out of space in the buckets (false positive)");

  filter->remove(&one);

  MOZ_RELEASE_ASSERT(
      !filter->mightContain(&one),
      "Filter should not contain 'one', because we didn't overflow its "
      "bucket");

  filter->clear();

  MOZ_RELEASE_ASSERT(!filter->mightContain(&multiple),
                     "clear() failed to work");
}

int main() {
  testBitBloomFilter();
  testCountingBloomFilter();

  return 0;
}