Skip to content

Commit

Permalink
heap tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sgreben committed Sep 19, 2024
1 parent 945f34f commit dd5ffda
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 3 deletions.
6 changes: 3 additions & 3 deletions heap/heap.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Min struct {
func NewMin(k int) *Min {
return &Min{
K: k,
Items: make([]Item, k),
Items: make([]Item, 0, k),
Index: make(map[string]int, k),
}
}
Expand All @@ -31,7 +31,7 @@ var _ heap.Interface = &Min{}

func (me Min) SizeBytes() int {
structSize := sizeofMinStruct
bucketsSize := len(me.Items)*sizeofItem + me.StoredKeysBytes
bucketsSize := cap(me.Items)*sizeofItem + me.StoredKeysBytes
indexSize := sizeof.StringIntMap + (sizeof.Int+sizeof.String)*len(me.Index)
return structSize + bucketsSize + indexSize
}
Expand Down Expand Up @@ -127,7 +127,7 @@ func (me *Min) Update(item string, fingerprint uint32, count uint32) bool {
me.StoredKeysBytes += len(item)

if !me.Full() { // heap not full: add to heap
me.Push(Item{
heap.Push(me, Item{
Count: count,
Fingerprint: fingerprint,
Item: item,
Expand Down
180 changes: 180 additions & 0 deletions heap/heap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package heap_test

import (
"testing"
"unsafe"

"github.com/keilerkonzept/topk/heap"
sketchheap "github.com/keilerkonzept/topk/heap"
"github.com/keilerkonzept/topk/internal/sizeof"
)

func TestMinHeap_LessSwap(t *testing.T) {
h := sketchheap.NewMin(5)

h.Items = []sketchheap.Item{
{Item: "a", Count: 5, Fingerprint: 1},
{Item: "b", Count: 2, Fingerprint: 2},
{Item: "c", Count: 3, Fingerprint: 3},
}

// Check Less function
if !h.Less(1, 0) {
t.Errorf("expected Less(1, 0) to be true")
}
if h.Less(0, 1) {
t.Errorf("expected Less(0, 1) to be false")
}

// Check Swap function
h.Swap(0, 1)
if h.Items[0].Item != "b" || h.Items[1].Item != "a" {
t.Errorf("expected Swap to switch elements 'a' and 'b'")
}
}

func TestMinHeap_Full(t *testing.T) {
h := sketchheap.NewMin(2)

h.Update("a", 1, 2)
if h.Full() {
t.Errorf("expected heap to not be full")
}

h.Update("b", 2, 2)
if !h.Full() {
t.Errorf("expected heap to be full")
}
}

func TestMinHeap_Update(t *testing.T) {
h := sketchheap.NewMin(2)

// Insert new item
h.Update("a", 1, 10)
if h.Items[0].Item != "a" {
t.Errorf("expected 'a' to be in the heap")
}

// Insert more items
h.Update("b", 2, 5)
h.Update("c", 3, 8)
h.Update("d", 3, 1)

// "b" should be removed as it has the lowest count and heap is full
if h.Contains("b") {
t.Errorf("expected 'b' to be removed from the heap")
}
// "d" should be not enter the heap as its below the Min()
if h.Contains("d") {
t.Errorf("expected 'd' to never enter the heap")
}

// Update an existing item
h.Update("c", 3, 15)
if h.Items[0].Item != "a" || h.Items[1].Item != "c" {
t.Errorf("expected 'a' and 'c' to be in the heap after update")
}
}

func TestMinHeap_Min(t *testing.T) {
h := sketchheap.NewMin(2)

// Empty heap
if h.Min() != 0 {
t.Errorf("expected Min to return 0 for empty heap")
}

// Push some items and check minimum
h.Update("a", 1, 10)
h.Update("b", 2, 5)
h.Update("c", 2, 3)

if h.Min() != 5 {
t.Errorf("expected Min to return 5, got %d", h.Min())
}
}

func TestMinHeap_Reinit(t *testing.T) {
h := sketchheap.NewMin(3)

h.Push(sketchheap.Item{Item: "a", Count: 0, Fingerprint: 1})
h.Push(sketchheap.Item{Item: "b", Count: 2, Fingerprint: 2})
h.Push(sketchheap.Item{Item: "c", Count: 3, Fingerprint: 3})

// Reinit should remove items with 0 count
h.Reinit()
if h.Len() != 2 {
t.Errorf("expected Len after Reinit to be 2, got %d", h.Len())
}
if h.Contains("a") {
t.Errorf("expected 'a' to be removed from the heap")
}
}

func TestMinHeap_Find(t *testing.T) {
h := sketchheap.NewMin(3)
h.Update("a", 1, 10)

// Find existing item
idx := h.Find("a")
if idx != 0 {
t.Errorf("expected 'a' to be at index 0, got %d", idx)
}

// Find non-existing item
idx = h.Find("b")
if idx != -1 {
t.Errorf("expected 'b' to not be found, got %d", idx)
}
}

func TestMinHeap_Get(t *testing.T) {
h := sketchheap.NewMin(3)
h.Update("a", 1, 10)

// Get existing item
item := h.Get("a")
if item == nil || item.Item != "a" {
t.Errorf("expected to get item 'a', got '%v'", item)
}

// Get non-existing item
item = h.Get("b")
if item != nil {
t.Errorf("expected to get nil for non-existing item, got '%v'", item)
}
}

func TestMinHeap_SizeBytes(t *testing.T) {
h := heap.NewMin(3)

const (
sizeofMinStruct = int(unsafe.Sizeof(sketchheap.Min{}))
sizeofItem = int(unsafe.Sizeof(sketchheap.Item{}))
)

// Initial size should only account for the struct and empty containers
expectedSize := sizeofMinStruct + 3*sizeofItem + sizeof.StringIntMap
if h.SizeBytes() != expectedSize {
t.Errorf("expected SizeBytes to be %d, got %d", expectedSize, h.SizeBytes())
}

h.Update("a", 1, 5)
expectedSize += len("a") + sizeof.String + sizeof.Int // Size of new item in heap
if h.SizeBytes() != expectedSize {
t.Errorf("expected SizeBytes to be %d, got %d", expectedSize, h.SizeBytes())
}

h.Update("b", 2, 10)
expectedSize += len("b") + sizeof.String + sizeof.Int
if h.SizeBytes() != expectedSize {
t.Errorf("expected SizeBytes to be %d, got %d", expectedSize, h.SizeBytes())
}

h.Update("long_string_item", 3, 15)
expectedSize += len("long_string_item") + sizeof.String + sizeof.Int
if h.SizeBytes() != expectedSize {
t.Errorf("expected SizeBytes to be %d, got %d", expectedSize, h.SizeBytes())
}
}

0 comments on commit dd5ffda

Please sign in to comment.