View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.bloomfilter;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertNotEquals;
21  import static org.junit.Assert.assertNotSame;
22  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertSame;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.LinkedList;
31  import java.util.List;
32  import java.util.NoSuchElementException;
33  import java.util.function.Consumer;
34  import java.util.function.Predicate;
35  
36  import org.junit.jupiter.api.Test;
37  import org.junit.jupiter.params.ParameterizedTest;
38  import org.junit.jupiter.params.provider.ValueSource;
39  
40  public class LayerManagerTest {
41  
42      private Shape shape = Shape.fromKM(17, 72);
43  
44      @ParameterizedTest
45      @ValueSource(ints = {4, 10, 2, 1})
46      public void testAdvanceOnCount(int breakAt) {
47          Predicate<LayerManager> underTest = LayerManager.ExtendCheck.advanceOnCount(breakAt);
48          LayerManager layerManager = testingBuilder().build();
49          for (int i = 0; i < breakAt - 1; i++) {
50              assertFalse(underTest.test(layerManager), "at " + i);
51              layerManager.getTarget().merge(TestingHashers.FROM1);
52          }
53          assertTrue(underTest.test(layerManager));
54      }
55  
56      @Test
57      public void testAdvanceOnCountInvalidArguments() {
58          assertThrows(IllegalArgumentException.class, () -> LayerManager.ExtendCheck.advanceOnCount(0));
59          assertThrows(IllegalArgumentException.class, () -> LayerManager.ExtendCheck.advanceOnCount(-1));
60      }
61  
62      @Test
63      public void testAdvanceOnPopulated() {
64          Predicate<LayerManager> underTest = LayerManager.ExtendCheck.advanceOnPopulated();
65          LayerManager layerManager = testingBuilder().build();
66          assertFalse(underTest.test(layerManager));
67          layerManager.getTarget().merge(TestingHashers.FROM1);
68          assertTrue(underTest.test(layerManager));
69      }
70  
71      @Test
72      public void testAdvanceOnSaturation() {
73          Double maxN = shape.estimateMaxN();
74          int hashStart = 0;
75          Predicate<LayerManager> underTest = LayerManager.ExtendCheck.advanceOnSaturation(maxN);
76          LayerManager layerManager = testingBuilder().build();
77          while (layerManager.getTarget().getShape().estimateN(layerManager.getTarget().cardinality()) < maxN) {
78              assertFalse(underTest.test(layerManager));
79              layerManager.getTarget().merge(new IncrementingHasher(hashStart, shape.getNumberOfHashFunctions()));
80              hashStart+=shape.getNumberOfHashFunctions();
81          }
82          assertTrue(underTest.test(layerManager));
83          assertThrows(IllegalArgumentException.class, () -> LayerManager.ExtendCheck.advanceOnSaturation(0));
84          assertThrows(IllegalArgumentException.class, () -> LayerManager.ExtendCheck.advanceOnSaturation(-1));
85      }
86  
87      @Test
88      public void testBuilder() {
89          LayerManager.Builder underTest = LayerManager.builder();
90          NullPointerException npe = assertThrows(NullPointerException.class, () -> underTest.build());
91          assertTrue(npe.getMessage().contains("Supplier must not be null"));
92          underTest.setSupplier(() -> null).setCleanup(null);
93          npe = assertThrows(NullPointerException.class, () -> underTest.build());
94          assertTrue(npe.getMessage().contains("Cleanup must not be null"));
95          underTest.setCleanup(x -> {
96          }).setExtendCheck(null);
97          npe = assertThrows(NullPointerException.class, () -> underTest.build());
98          assertTrue(npe.getMessage().contains("ExtendCheck must not be null"));
99  
100         npe = assertThrows(NullPointerException.class, () -> LayerManager.builder().setSupplier(() -> null).build());
101         assertTrue(npe.getMessage().contains("filterSupplier returned null."));
102 
103     }
104 
105     @Test
106     public void testClear() {
107         LayerManager underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape)).build();
108         underTest.getTarget().merge(TestingHashers.randomHasher());
109         underTest.next();
110         underTest.getTarget().merge(TestingHashers.randomHasher());
111         underTest.next();
112         underTest.getTarget().merge(TestingHashers.randomHasher());
113         assertEquals(3, underTest.getDepth());
114         underTest.clear();
115         assertEquals(1, underTest.getDepth());
116         assertEquals(0, underTest.getTarget().cardinality());
117     }
118 
119     @Test
120     public void testCopy() {
121         LayerManager underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape)).build();
122         underTest.getTarget().merge(TestingHashers.randomHasher());
123         underTest.next();
124         underTest.getTarget().merge(TestingHashers.randomHasher());
125         underTest.next();
126         underTest.getTarget().merge(TestingHashers.randomHasher());
127         assertEquals(3, underTest.getDepth());
128 
129         LayerManager copy = underTest.copy();
130         assertNotSame(underTest, copy);
131         // object equals not implemented
132         assertNotEquals(underTest, copy);
133 
134         assertEquals(underTest.getDepth(), copy.getDepth());
135         assertTrue(
136                 underTest.forEachBloomFilterPair(copy, (x, y) -> Arrays.equals(x.asBitMapArray(), y.asBitMapArray())));
137     }
138 
139     @Test
140     public void testForEachBloomFilter() {
141         LayerManager underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape))
142                 .setExtendCheck(LayerManager.ExtendCheck.advanceOnPopulated()).build();
143 
144         List<BloomFilter> lst = new ArrayList<>();
145         for (int i = 0; i < 10; i++) {
146             BloomFilter bf = new SimpleBloomFilter(shape);
147             bf.merge(TestingHashers.randomHasher());
148             lst.add(bf);
149             underTest.getTarget().merge(bf);
150         }
151         List<BloomFilter> lst2 = new ArrayList<>();
152         underTest.forEachBloomFilter(lst2::add);
153         assertEquals(10, lst.size());
154         assertEquals(10, lst2.size());
155         for (int i = 0; i < lst.size(); i++) {
156             assertArrayEquals(lst.get(i).asBitMapArray(), lst2.get(i).asBitMapArray());
157         }
158     }
159 
160     @Test
161     public void testGet() {
162         SimpleBloomFilter f = new SimpleBloomFilter(shape);
163         LayerManager underTest = LayerManager.builder().setSupplier(() -> f).build();
164         assertEquals(1, underTest.getDepth());
165         assertSame(f, underTest.get(0));
166         assertThrows(NoSuchElementException.class, () -> underTest.get(-1));
167         assertThrows(NoSuchElementException.class, () -> underTest.get(1));
168     }
169 
170     private LayerManager.Builder testingBuilder() {
171         return LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape));
172     }
173 
174     @Test
175     public void testNeverAdvance() {
176         Predicate<LayerManager> underTest = LayerManager.ExtendCheck.neverAdvance();
177         LayerManager layerManager = testingBuilder().build();
178         assertFalse(underTest.test(layerManager));
179         for (int i = 0; i < 10; i++) {
180             layerManager.getTarget().merge(TestingHashers.randomHasher());
181             assertFalse(underTest.test(layerManager));
182         }
183     }
184 
185     @Test
186     public void testNextAndGetDepth() {
187         LayerManager underTest = LayerManager.builder().setSupplier(() -> new SimpleBloomFilter(shape)).build();
188         assertEquals(1, underTest.getDepth());
189         underTest.getTarget().merge(TestingHashers.randomHasher());
190         assertEquals(1, underTest.getDepth());
191         underTest.next();
192         assertEquals(2, underTest.getDepth());
193     }
194 
195     @Test
196     public void testNoCleanup() {
197         Consumer<LinkedList<BloomFilter>> underTest = LayerManager.Cleanup.noCleanup();
198         LinkedList<BloomFilter> list = new LinkedList<>();
199         for (int i = 0; i < 20; i++) {
200             assertEquals(i, list.size());
201             list.add(new SimpleBloomFilter(shape));
202             underTest.accept(list);
203         }
204     }
205 
206     @ParameterizedTest
207     @ValueSource(ints = {5, 100, 2, 1})
208     public void testOnMaxSize(int maxSize) {
209         Consumer<LinkedList<BloomFilter>> underTest = LayerManager.Cleanup.onMaxSize(maxSize);
210         LinkedList<BloomFilter> list = new LinkedList<>();
211         for (int i = 0; i < maxSize; i++) {
212             assertEquals(i, list.size());
213             list.add(new SimpleBloomFilter(shape));
214             underTest.accept(list);
215         }
216         assertEquals(maxSize, list.size());
217 
218         for (int i = 0; i < maxSize; i++) {
219             list.add(new SimpleBloomFilter(shape));
220             underTest.accept(list);
221             assertEquals(maxSize, list.size());
222         }
223     }
224 
225     @Test
226     public void testOnMaxSizeIllegalValues() {
227         assertThrows(IllegalArgumentException.class, () -> LayerManager.Cleanup.onMaxSize(0));
228         assertThrows(IllegalArgumentException.class, () -> LayerManager.Cleanup.onMaxSize(-1));
229     }
230 
231     @Test
232     public void testRemoveEmptyTarget() {
233         Consumer<LinkedList<BloomFilter>> underTest = LayerManager.Cleanup.removeEmptyTarget();
234         LinkedList<BloomFilter> list = new LinkedList<>();
235 
236         // removes an empty filter
237         BloomFilter bf = new SimpleBloomFilter(shape);
238         list.add(bf);
239         assertEquals(bf, list.get(0));
240         underTest.accept(list);
241         assertTrue(list.isEmpty());
242 
243         // does not remove a populated filter.
244         bf.merge(IndexProducer.fromIndexArray(1));
245         list.add(bf);
246         assertEquals(bf, list.get(0));
247         underTest.accept(list);
248         assertEquals(bf, list.get(0));
249 
250         // does not remove an empty filter followed by a populated filter.
251         list.clear();
252         list.add(new SimpleBloomFilter(shape));
253         list.add(bf);
254         assertEquals(2, list.size());
255         underTest.accept(list);
256         assertEquals(2, list.size());
257 
258         // does not remove multiple empty filters at the end of the list, just the last
259         // one.
260         list.clear();
261         list.add(bf);
262         list.add(new SimpleBloomFilter(shape));
263         list.add(new SimpleBloomFilter(shape));
264         assertEquals(3, list.size());
265         underTest.accept(list);
266         assertEquals(2, list.size());
267         assertEquals(bf, list.get(0));
268 
269     }
270 
271     @Test
272     public void testTarget() {
273         boolean[] extendCheckCalled = { false };
274         boolean[] cleanupCalled = { false };
275         int[] supplierCount = { 0 };
276         LayerManager underTest = LayerManager.builder().setSupplier(() -> {
277             supplierCount[0]++;
278             return new SimpleBloomFilter(shape);
279         }).setExtendCheck(lm -> {
280             extendCheckCalled[0] = true;
281             return true;
282         }).setCleanup(ll -> {
283             cleanupCalled[0] = true;
284         }).build();
285         assertFalse(extendCheckCalled[0]);
286         assertFalse(cleanupCalled[0]);
287         assertEquals(1, supplierCount[0]);
288         underTest.getTarget();
289         assertTrue(extendCheckCalled[0]);
290         assertTrue(cleanupCalled[0]);
291         assertEquals(2, supplierCount[0]);
292     }
293 
294 }