Skip to content

Commit

Permalink
add fuzz test for truncation of orNot, avoid method references to kee…
Browse files Browse the repository at this point in the history
…p fuzz tests compiling unambiguously in Java 8
  • Loading branch information
richardstartin committed Apr 9, 2020
1 parent 918ae3e commit 54f30de
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 65 deletions.
35 changes: 14 additions & 21 deletions fuzz-tests/src/test/java/org/roaringbitmap/BufferFuzzer.java
Expand Up @@ -6,20 +6,13 @@
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
import org.roaringbitmap.buffer.MutableRoaringBitmap;

import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.*;
import java.util.stream.IntStream;

import static org.junit.Assert.assertTrue;
import static org.roaringbitmap.RandomisedTestData.ITERATIONS;
import static org.roaringbitmap.RandomisedTestData.randomBitmap;
import static org.roaringbitmap.Util.toUnsignedLong;

public class BufferFuzzer {
Expand All @@ -41,7 +34,7 @@ public static void verifyInvariance(String testName, int maxKeys, RangeBitmapPre
.mapToObj(i -> randomBitmap(maxKeys))
.forEach(bitmap -> {
long min = random.nextLong(1L << 32);
long max = random.nextLong(min,1L << 32);
long max = random.nextLong(min, 1L << 32);
try {
Assert.assertTrue(pred.test(min, max, bitmap));
} catch (Throwable t) {
Expand Down Expand Up @@ -244,16 +237,16 @@ public void selectContainsInvariance() {
public void firstSelect0Invariance() {
verifyInvariance("firstSelect0Invariance",
bitmap -> !bitmap.isEmpty(),
ImmutableRoaringBitmap::first,
bitmap -> bitmap.select(0));
b -> b.first(),
bitmap -> bitmap.select(0));
}

@Test
public void lastSelectCardinalityInvariance() {
verifyInvariance("lastSelectCardinalityInvariance",
bitmap -> !bitmap.isEmpty(),
ImmutableRoaringBitmap::last,
bitmap -> bitmap.select(bitmap.getCardinality() - 1));
bitmap -> bitmap.last(),
bitmap -> bitmap.select(bitmap.getCardinality() - 1));
}

@Test
Expand All @@ -273,21 +266,21 @@ public void containsRangeFirstLastInvariance() {
public void andCardinalityInvariance() {
verifyInvariance("andCardinalityInvariance", ITERATIONS, 1 << 9,
(l, r) -> MutableRoaringBitmap.and(l, r).getCardinality(),
MutableRoaringBitmap::andCardinality);
(l, r) -> MutableRoaringBitmap.andCardinality(l, r));
}

@Test
public void orCardinalityInvariance() {
verifyInvariance("orCardinalityInvariance", ITERATIONS, 1 << 9,
(l, r) -> MutableRoaringBitmap.or(l, r).getCardinality(),
MutableRoaringBitmap::orCardinality);
(l, r) -> MutableRoaringBitmap.orCardinality(l, r));
}

@Test
public void xorCardinalityInvariance() {
verifyInvariance("xorCardinalityInvariance", ITERATIONS, 1 << 9,
(l, r) -> MutableRoaringBitmap.xor(l, r).getCardinality(),
MutableRoaringBitmap::xorCardinality);
(l, r) -> MutableRoaringBitmap.xorCardinality(l, r));
}

@Test
Expand All @@ -301,7 +294,7 @@ public void containsContainsInvariance() {
@Test
public void containsAndInvariance() {
verifyInvariance("containsAndInvariance",
ImmutableRoaringBitmap::contains,
(l, r) -> l.contains(r),
(l, r) -> MutableRoaringBitmap.and(l, r).equals(r));
}

Expand All @@ -318,20 +311,20 @@ public void sizeOfUnionOfDisjointSetsEqualsSumOfSizes() {
verifyInvariance("sizeOfUnionOfDisjointSetsEqualsSumOfSizes",
(l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0,
(l, r) -> l.getCardinality() + r.getCardinality(),
MutableRoaringBitmap::orCardinality);
(l, r) -> MutableRoaringBitmap.orCardinality(l, r));
}

@Test
public void sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes() {
verifyInvariance("sizeOfDifferenceOfDisjointSetsEqualsSumOfSizes",
(l, r) -> MutableRoaringBitmap.andCardinality(l, r) == 0,
(l, r) -> l.getCardinality() + r.getCardinality(),
MutableRoaringBitmap::xorCardinality);
(l, r) -> MutableRoaringBitmap.xorCardinality(l, r));
}

@Test
public void equalsSymmetryInvariance() {
verifyInvariance("equalsSymmetryInvariance", ImmutableRoaringBitmap::equals, (l, r) -> r.equals(l));
verifyInvariance("equalsSymmetryInvariance", (l, r) -> l.equals(r), (l, r) -> r.equals(l));
}

@Test
Expand Down Expand Up @@ -476,7 +469,7 @@ public void intersectsContainsRemove() {

@Test
public void absentValuesConsistentWithBitSet() {
int[] offsets = new int[] {0, 1, -1, 10, -10, 100, -100};
int[] offsets = new int[]{0, 1, -1, 10, -10, 100, -100};

// Size limit to avoid out of memory errors; r.last() > 0 to avoid bitmaps with last > Integer.MAX_VALUE
verifyInvariance(r -> r.isEmpty() || (r.last() > 0 && r.last() < 1 << 30), bitmap -> {
Expand Down
104 changes: 60 additions & 44 deletions fuzz-tests/src/test/java/org/roaringbitmap/Fuzzer.java
Expand Up @@ -50,14 +50,13 @@ public static <T> void verifyInvariance(String testName,
}



public static void verifyInvariance(String testName, int maxKeys, RangeBitmapPredicate pred) {
IntStream.range(0, ITERATIONS)
.parallel()
.mapToObj(i -> randomBitmap(maxKeys))
.forEach(bitmap -> {
long min = ThreadLocalRandom.current().nextLong(1L << 32);
long max = ThreadLocalRandom.current().nextLong(min,1L << 32);
long max = ThreadLocalRandom.current().nextLong(min, 1L << 32);
try {
assertTrue(pred.test(min, max, bitmap));
} catch (Throwable e) {
Expand Down Expand Up @@ -104,7 +103,8 @@ public static <T> void verifyInvariance(String testName,
} catch (Throwable e) {
Reporter.report(testName, ImmutableMap.of(), e, bitmap);
throw e;
}});
}
});
}

public static <T> void verifyInvariance(String testName,
Expand Down Expand Up @@ -236,36 +236,36 @@ public void selectContainsInvariance() {
@Test
public void firstSelect0Invariance() {
verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(),
RoaringBitmap::first,
l -> l.first(),
bitmap -> bitmap.select(0));
}

@Test
public void lastSelectCardinalityInvariance() {
verifyInvariance("rankSelectInvariance", bitmap -> !bitmap.isEmpty(),
RoaringBitmap::last,
l -> l.last(),
bitmap -> bitmap.select(bitmap.getCardinality() - 1));
}

@Test
public void andCardinalityInvariance() {
verifyInvariance("andCardinalityInvariance", ITERATIONS, 1 << 9,
(l, r) -> RoaringBitmap.and(l, r).getCardinality(),
RoaringBitmap::andCardinality);
(l, r) -> RoaringBitmap.andCardinality(l, r));
}

@Test
public void orCardinalityInvariance() {
verifyInvariance("orCardinalityInvariance", ITERATIONS, 1 << 9,
(l, r) -> RoaringBitmap.or(l, r).getCardinality(),
RoaringBitmap::orCardinality);
(l, r) -> RoaringBitmap.orCardinality(l, r));
}

@Test
public void xorCardinalityInvariance() {
verifyInvariance("xorCardinalityInvariance", ITERATIONS, 1 << 9,
(l, r) -> RoaringBitmap.xor(l, r).getCardinality(),
RoaringBitmap::xorCardinality);
(l, r) -> RoaringBitmap.xorCardinality(l, r));
}

@Test
Expand All @@ -277,7 +277,7 @@ public void containsContainsInvariance() {

@Test
public void containsAndInvariance() {
verifyInvariance("containsAndInvariance", RoaringBitmap::contains, (l, r) -> RoaringBitmap.and(l, r).equals(r));
verifyInvariance("containsAndInvariance", (l, r) -> l.contains(r), (l, r) -> RoaringBitmap.and(l, r).equals(r));
}


Expand All @@ -289,7 +289,7 @@ public void limitCardinalityEqualsSelf() {
@Test
public void limitCardinalityXorCardinalityInvariance() {
verifyInvariance("limitCardinalityXorCardinalityInvariance", rb -> true,
RoaringBitmap::getCardinality,
l -> l.getCardinality(),
rb -> rb.getCardinality() / 2
+ RoaringBitmap.xorCardinality(rb, rb.limit(rb.getCardinality() / 2)));
}
Expand All @@ -298,7 +298,7 @@ public void limitCardinalityXorCardinalityInvariance() {
public void containsRangeFirstLastInvariance() {
verifyInvariance("containsRangeFirstLastInvariance", true,
rb -> RoaringBitmap.add(rb.clone(), toUnsignedLong(rb.first()), toUnsignedLong(rb.last()))
.contains(toUnsignedLong(rb.first()), toUnsignedLong(rb.last())));
.contains(toUnsignedLong(rb.first()), toUnsignedLong(rb.last())));
}

@Test
Expand Down Expand Up @@ -367,9 +367,9 @@ public void xorInvariance() {
public void rangeCardinalityVsMaterialisedRange() {
verifyInvariance("rangeCardinalityVsMaterialisedRange", 1 << 9,
(min, max, bitmap) -> {
RoaringBitmap range = new RoaringBitmap();
range.add(min, max);
return bitmap.rangeCardinality(min, max) == RoaringBitmap.andCardinality(range, bitmap);
RoaringBitmap range = new RoaringBitmap();
range.add(min, max);
return bitmap.rangeCardinality(min, max) == RoaringBitmap.andCardinality(range, bitmap);
});
}

Expand Down Expand Up @@ -444,7 +444,7 @@ public void dontContainAfterRemoval() {
}
l.remove(next);
if (l.contains(next)) {
return false;
return false;
}
if (first != next && l.contains(first, toUnsignedLong(next))) {
return false;
Expand All @@ -455,36 +455,52 @@ public void dontContainAfterRemoval() {
});
}

@Test
public void intersectsContainsRemove() {
verifyInvariance("intersectsContainsRemove",
(l, r) -> RoaringBitmap.andCardinality(l, r) > 0,
1 << 12,
(l, r) -> {
RoaringBitmap and = RoaringBitmap.and(l, r);
if (!(l.contains(and) && r.contains(and))) {
return false;
}
long first = and.first() & 0xFFFFFFFFL;
long last = and.last() & 0xFFFFFFFFL;
IntIterator it = and.getBatchIterator().asIntIterator(new int[16]);
l.remove(first, last + 1);
while (it.hasNext()) {
long next = toUnsignedLong(it.next());
if (l.intersects(first, next) || (first != next && !r.intersects(first, next))) {
return false;
}
if (l.contains(first, next)) {
return false;
}
}
return !l.contains(and);
});
}
@Test
public void intersectsContainsRemove() {
verifyInvariance("intersectsContainsRemove",
(l, r) -> RoaringBitmap.andCardinality(l, r) > 0,
1 << 12,
(l, r) -> {
RoaringBitmap and = RoaringBitmap.and(l, r);
if (!(l.contains(and) && r.contains(and))) {
return false;
}
long first = and.first() & 0xFFFFFFFFL;
long last = and.last() & 0xFFFFFFFFL;
IntIterator it = and.getBatchIterator().asIntIterator(new int[16]);
l.remove(first, last + 1);
while (it.hasNext()) {
long next = toUnsignedLong(it.next());
if (l.intersects(first, next) || (first != next && !r.intersects(first, next))) {
return false;
}
if (l.contains(first, next)) {
return false;
}
}
return !l.contains(and);
});
}

@Test
public void orNotDoesNotTruncate() {
verifyInvariance("orNotDoesNotTruncate",
(l, r) -> !l.isEmpty() && (r.isEmpty() || l.last() > r.last()),
1 << 12,
(l, r) -> {
int last = l.last();
if (last > 1) {
long rangeEnd = ThreadLocalRandom.current().nextLong(0, last - 1);
l.orNot(r, rangeEnd);
return l.contains(last);
}
return true;
});
}

@Test
public void orNot() {
verifyInvariance("orNot", ITERATIONS,1 << 9,
verifyInvariance("orNot", ITERATIONS, 1 << 9,
(RoaringBitmap l, RoaringBitmap r) -> {
RoaringBitmap x = l.clone();
long max = (x.last() & 0xFFFFFFFFL) + 1;
Expand All @@ -502,7 +518,7 @@ public void orNot() {

@Test
public void orNotStatic() {
verifyInvariance("orNot", ITERATIONS,1 << 9,
verifyInvariance("orNot", ITERATIONS, 1 << 9,
(RoaringBitmap l, RoaringBitmap r) -> {
RoaringBitmap x = l.clone();
long max = (x.last() & 0xFFFFFFFFL) + 1;
Expand All @@ -518,7 +534,7 @@ public void orNotStatic() {

@Test
public void absentValuesConsistentWithBitSet() {
int[] offsets = new int[] {0, 1, -1, 10, -10, 100, -100};
int[] offsets = new int[]{0, 1, -1, 10, -10, 100, -100};
// Size limit to avoid out of memory errors; r.last() > 0 to avoid bitmaps with last > Integer.MAX_VALUE
verifyInvariance(r -> r.isEmpty() || (r.last() > 0 && r.last() < 1 << 30), bitmap -> {
BitSet reference = new BitSet();
Expand Down

0 comments on commit 54f30de

Please sign in to comment.