Skip to content

Commit

Permalink
Merge pull request #436 from bearrito/chore/test-coverage
Browse files Browse the repository at this point in the history
Chore/test coverage
  • Loading branch information
lemire authored Jun 25, 2024
2 parents a15b8ab + 3625fd1 commit 072549f
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 4 deletions.
2 changes: 1 addition & 1 deletion bitmapcontainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ func (bc *bitmapContainer) orArray(value2 *arrayContainer) container {
}

func (bc *bitmapContainer) orArrayCardinality(value2 *arrayContainer) int {
answer := 0
answer := bc.getCardinality()
c := value2.getCardinality()
for k := 0; k < c; k++ {
// branchless:
Expand Down
47 changes: 47 additions & 0 deletions bitmapcontainer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,3 +485,50 @@ func TestBitmapcontainerNextHasMany(t *testing.T) {
assert.Equal(t, 256, result)
})
}

func TestBitmapcontainerOrArrayCardinality(t *testing.T) {
t.Run("Empty Bitmap and Empty Array", func(t *testing.T) {
array := newArrayContainer()
bc := newBitmapContainer()
result := bc.orArrayCardinality(array)

assert.Equal(t, 0, result)
})

t.Run("Populated Bitmap with Empty Array", func(t *testing.T) {
bc := newBitmapContainer()
bc.iaddRange(0, 1024)
array := newArrayContainer()

result := bc.orArrayCardinality(array)

assert.Equal(t, 1024, result)
})

t.Run("Populated Bitmap with Empty Run Container", func(t *testing.T) {
bc := newBitmapContainer()
bc.iaddRange(0, 1024)

runC := newRunContainer16()

result := runC.orBitmapContainerCardinality(bc)

assert.Equal(t, 1024, result)

other := newBitmapContainerFromRun(runC)
result = bc.orBitmapCardinality(other)

assert.Equal(t, 1024, result)
})

t.Run("Populated Bitmap with Empty Bitmap", func(t *testing.T) {
bc := newBitmapContainer()
bc.iaddRange(0, 1024)

other := newBitmapContainer()

result := bc.orBitmapCardinality(other)

assert.Equal(t, 1024, result)
})
}
7 changes: 4 additions & 3 deletions roaring64/parallel64.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ func (c parChunk) size() int {
return c.ra.size()
}

// parNaiveStartAt returns the index of the first key that is inclusive between start and last
// Returns the size if there is no such key
func parNaiveStartAt(ra *roaringArray64, start uint32, last uint32) int {
for idx, key := range ra.keys {
if key >= start && key <= last {
Expand All @@ -170,7 +172,6 @@ func orOnRange(ra1, ra2 *roaringArray64, start, last uint32) *roaringArray64 {
key2 = ra2.getKeyAtIndex(idx2)

for key1 <= last && key2 <= last {

if key1 < key2 {
answer.appendCopy(*ra1, idx1)
idx1++
Expand All @@ -188,7 +189,7 @@ func orOnRange(ra1, ra2 *roaringArray64, start, last uint32) *roaringArray64 {
} else {
c1 := ra1.getContainerAtIndex(idx1)

//answer.appendContainer(key1, c1.lazyOR(ra2.getContainerAtIndex(idx2)), false)
// answer.appendContainer(key1, c1.lazyOR(ra2.getContainerAtIndex(idx2)), false)
answer.appendContainer(key1, roaring.Or(c1, ra2.getContainerAtIndex(idx2)), false)
idx1++
idx2++
Expand Down Expand Up @@ -261,7 +262,7 @@ func iorOnRange(ra1, ra2 *roaringArray64, start, last uint32) *roaringArray64 {
} else {
c1 := ra1.getWritableContainerAtIndex(idx1)

//ra1.containers[idx1] = c1.lazyIOR(ra2.getContainerAtIndex(idx2))
// ra1.containers[idx1] = c1.lazyIOR(ra2.getContainerAtIndex(idx2))
c1.Or(ra2.getContainerAtIndex(idx2))
ra1.setContainerAtIndex(idx1, c1)

Expand Down
23 changes: 23 additions & 0 deletions roaring64/roaring64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ func TestIssue266(t *testing.T) {
}
}

func TestParOr64(t *testing.T) {
t.Run("Test 1", func(t *testing.T) {
a := BitmapOf(0, 1, 2, 3, 4)
b := BitmapOf(5, 6, 7, 8, 9, 10)
c := BitmapOf(11, 12, 13, 14, 15)
d := ParOr(0, a, b, c)
expected := BitmapOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
assert.True(t, d.Equals(expected))
})

t.Run("Test 2", func(t *testing.T) {
a := BitmapOf(0, 1, 2, 3, 4)

offset1 := uint64(2 << 16)
b := BitmapOf(offset1, offset1+1, offset1+2, offset1+3, offset1+5)
offset2 := uint64(4 << 16)
c := BitmapOf(offset2, offset2+1, offset2+2, offset2+3, offset2+5)
d := ParOr(0, a, b, c)
expected := BitmapOf(0, 1, 2, 3, 4, offset1, offset1+1, offset1+2, offset1+3, offset1+5, offset2, offset2+1, offset2+2, offset2+3, offset2+5)
assert.True(t, d.Equals(expected))
})
}

func TestRoaringRangeEnd(t *testing.T) {
r := New()
r.Add(roaring.MaxUint32)
Expand Down
9 changes: 9 additions & 0 deletions roaring64/roaringarray64.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,15 @@ func (ra *roaringArray64) hasRunCompression() bool {
return false
}

/**
* Find the smallest integer index strictly larger than pos such that array[index].key&gt;=min. If none can
* be found, return size. Based on code by O. Kaser.
*
* @param min minimal value
* @param pos index to exceed
* @return the smallest index greater than pos such that array[index].key is at least as large as
* min, or size if it is not possible.
*/
func (ra *roaringArray64) advanceUntil(min uint32, pos int) int {
lower := pos + 1

Expand Down
130 changes: 130 additions & 0 deletions roaring64/roaringarray64_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package roaring64

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestRoaringArray64AdvanceUntil(t *testing.T) {
bitmap := New()
low := uint64(1) << 32
mid := uint64(2) << 32
high := uint64(3) << 32
bitmap.AddRange(uint64(low)-1, uint64(low)+2)
bitmap.AddRange(uint64(mid)-1, uint64(mid)+2)
bitmap.AddRange(uint64(high)-1, uint64(high)+2)

assert.Equal(t, 0, bitmap.highlowcontainer.advanceUntil(0, -1))
assert.Equal(t, 1, bitmap.highlowcontainer.advanceUntil(1, -1))
assert.Equal(t, 2, bitmap.highlowcontainer.advanceUntil(2, -1))
assert.Equal(t, 3, bitmap.highlowcontainer.advanceUntil(3, -1))
assert.Equal(t, 4, bitmap.highlowcontainer.advanceUntil(4, -1))

assert.Equal(t, 1, bitmap.highlowcontainer.advanceUntil(0, 0))
assert.Equal(t, 2, bitmap.highlowcontainer.advanceUntil(1, 1))
assert.Equal(t, 3, bitmap.highlowcontainer.advanceUntil(2, 2))
assert.Equal(t, 4, bitmap.highlowcontainer.advanceUntil(3, 3))
assert.Equal(t, 5, bitmap.highlowcontainer.advanceUntil(4, 4))
}

func TestCopies(t *testing.T) {
tests := []struct {
name string
cow1 bool
cow2 bool
}{
{"AppendCopiesAfterCoW", true, true},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
r1 := uint64(1) << 32
r2 := uint64(2) << 32
r3 := uint64(3) << 32
r4 := uint64(4) << 32

bitmap1 := New()
bitmap2 := New()
bitmap1.SetCopyOnWrite(test.cow1)
bitmap2.SetCopyOnWrite(test.cow2)

bitmap2.AddRange(uint64(r1)-1, uint64(r1)+2)
bitmap2.AddRange(uint64(r2)-1, uint64(r2)+2)
bitmap2.AddRange(uint64(r3)-1, uint64(r3)+2)
bitmap2.AddRange(uint64(r4)-1, uint64(r4)+2)

assert.False(t, bitmap1.Contains(uint64(r2)))
assert.False(t, bitmap1.Contains(uint64(r3)))
assert.Equal(t, 0, len(bitmap1.highlowcontainer.keys))
bitmap1.highlowcontainer.appendCopiesAfter(bitmap2.highlowcontainer, 0)
assert.Equal(t, 4, len(bitmap1.highlowcontainer.keys))
assert.True(t, bitmap1.Contains(uint64(r2)))
assert.True(t, bitmap1.Contains(uint64(r3)))

for idx1, c1 := range bitmap1.highlowcontainer.containers {
for idx2, c2 := range bitmap2.highlowcontainer.containers {
// idx+1 is required because appendCopiesAfter starts at key 1
if idx1+1 == idx2 {
if test.cow1 && test.cow2 {
assert.True(t, c1 == c2)
} else {
assert.False(t, c1 == c2)
}
}
}
}
})
}

tests = []struct {
name string
cow1 bool
cow2 bool
}{
{"AppendCopiesUntilCoW", true, true},
{"AppendCopiesUntilCoW", false, false},
{"AppendCopiesUntilMixedCoW", true, false},
{"AppendCopiesUntilMixedCoW", false, true},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
r1 := uint64(1) << 32
r2 := uint64(2) << 32
r3 := uint64(3) << 32
r4 := uint64(4) << 32
key := highbits(uint64(r4))

bitmap1 := New()
bitmap2 := New()
bitmap1.SetCopyOnWrite(test.cow1)
bitmap2.SetCopyOnWrite(test.cow2)

bitmap2.AddRange(uint64(r1)-1, uint64(r1)+2)
bitmap2.AddRange(uint64(r2)-1, uint64(r2)+2)
bitmap2.AddRange(uint64(r3)-1, uint64(r3)+2)
bitmap2.AddRange(uint64(r4)-1, uint64(r4)+2)

assert.False(t, bitmap1.Contains(uint64(r2)))
assert.False(t, bitmap1.Contains(uint64(r3)))
assert.Equal(t, 0, len(bitmap1.highlowcontainer.keys))
bitmap1.highlowcontainer.appendCopiesUntil(bitmap2.highlowcontainer, key)
assert.Equal(t, 4, len(bitmap1.highlowcontainer.keys))
assert.True(t, bitmap1.Contains(uint64(r2)))
assert.True(t, bitmap1.Contains(uint64(r3)))

for idx1, c1 := range bitmap1.highlowcontainer.containers {
for idx2, c2 := range bitmap2.highlowcontainer.containers {
if idx1 == idx2 {
if test.cow1 && test.cow2 {
assert.True(t, c1 == c2)
} else {
assert.False(t, c1 == c2)
}
}
}
}
})
}
}
36 changes: 36 additions & 0 deletions roaring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,42 @@ func TestFastCard(t *testing.T) {
assert.Equal(t, bm.GetCardinality(), bm2.OrCardinality(bm))
}

func TestFastCardUnequalKeys(t *testing.T) {
// These tests will excercise the interior code branches of OrCardinality

t.Run("Merge small into large", func(t *testing.T) {
bm := NewBitmap()
bm.AddRange(0, 1024)
bm2 := NewBitmap()
start := uint64(2 << 16)
bm2.AddRange(start, start+3)

assert.Equal(t, uint64(1027), bm2.OrCardinality(bm))
})
t.Run("Merge large into small", func(t *testing.T) {
bm := NewBitmap()
bm.AddRange(0, 1024)
bm2 := NewBitmap()
start := uint64(2 << 16)
bm2.AddRange(start, start+3)

assert.Equal(t, uint64(1027), bm.OrCardinality(bm2))
})

t.Run("Merge large into small same keyrange start", func(t *testing.T) {
bm := NewBitmap()
start := uint64(2 << 16)
bm.AddRange(0, 1024)
bm.AddRange(start, start+3)

bm2 := NewBitmap()
bm2.AddRange(0, 512)
bm2.AddRange(start, start+3)

assert.Equal(t, uint64(1027), bm.OrCardinality(bm2))
})
}

func TestIntersects1(t *testing.T) {
bm := NewBitmap()
bm.Add(1)
Expand Down
29 changes: 29 additions & 0 deletions roaringarray_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package roaring

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestRoaringArrayAdvanceUntil(t *testing.T) {
bitmap := New()
low := 1 << 16
mid := 2 << 16
high := 3 << 16
bitmap.AddRange(uint64(low)-1, uint64(low)+2)
bitmap.AddRange(uint64(mid)-1, uint64(mid)+2)
bitmap.AddRange(uint64(high)-1, uint64(high)+2)

assert.Equal(t, 0, bitmap.highlowcontainer.advanceUntil(0, -1))
assert.Equal(t, 1, bitmap.highlowcontainer.advanceUntil(1, -1))
assert.Equal(t, 2, bitmap.highlowcontainer.advanceUntil(2, -1))
assert.Equal(t, 3, bitmap.highlowcontainer.advanceUntil(3, -1))
assert.Equal(t, 4, bitmap.highlowcontainer.advanceUntil(4, -1))

assert.Equal(t, 1, bitmap.highlowcontainer.advanceUntil(0, 0))
assert.Equal(t, 2, bitmap.highlowcontainer.advanceUntil(1, 1))
assert.Equal(t, 3, bitmap.highlowcontainer.advanceUntil(2, 2))
assert.Equal(t, 4, bitmap.highlowcontainer.advanceUntil(3, 3))
assert.Equal(t, 5, bitmap.highlowcontainer.advanceUntil(4, 4))
}
Loading

0 comments on commit 072549f

Please sign in to comment.