mirror of https://github.com/golang/go.git
127 lines
3.0 KiB
Go
127 lines
3.0 KiB
Go
// Copyright 2023 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package trace
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"slices"
|
|
)
|
|
|
|
func TestHeap(t *testing.T) {
|
|
var heap []*batchCursor
|
|
|
|
// Insert a bunch of values into the heap.
|
|
checkHeap(t, heap)
|
|
heap = heapInsert(heap, makeBatchCursor(5))
|
|
checkHeap(t, heap)
|
|
for i := int64(-20); i < 20; i++ {
|
|
heap = heapInsert(heap, makeBatchCursor(i))
|
|
checkHeap(t, heap)
|
|
}
|
|
|
|
// Update an element in the middle to be the new minimum.
|
|
for i := range heap {
|
|
if heap[i].ev.time == 5 {
|
|
heap[i].ev.time = -21
|
|
heapUpdate(heap, i)
|
|
break
|
|
}
|
|
}
|
|
checkHeap(t, heap)
|
|
if heap[0].ev.time != -21 {
|
|
t.Fatalf("heap update failed, expected %d as heap min: %s", -21, heapDebugString(heap))
|
|
}
|
|
|
|
// Update the minimum element to be smaller. There should be no change.
|
|
heap[0].ev.time = -22
|
|
heapUpdate(heap, 0)
|
|
checkHeap(t, heap)
|
|
if heap[0].ev.time != -22 {
|
|
t.Fatalf("heap update failed, expected %d as heap min: %s", -22, heapDebugString(heap))
|
|
}
|
|
|
|
// Update the last element to be larger. There should be no change.
|
|
heap[len(heap)-1].ev.time = 21
|
|
heapUpdate(heap, len(heap)-1)
|
|
checkHeap(t, heap)
|
|
if heap[len(heap)-1].ev.time != 21 {
|
|
t.Fatalf("heap update failed, expected %d as heap min: %s", 21, heapDebugString(heap))
|
|
}
|
|
|
|
// Update the last element to be smaller.
|
|
heap[len(heap)-1].ev.time = 7
|
|
heapUpdate(heap, len(heap)-1)
|
|
checkHeap(t, heap)
|
|
if heap[len(heap)-1].ev.time == 21 {
|
|
t.Fatalf("heap update failed, unexpected %d as heap min: %s", 21, heapDebugString(heap))
|
|
}
|
|
|
|
// Remove an element in the middle.
|
|
for i := range heap {
|
|
if heap[i].ev.time == 5 {
|
|
heap = heapRemove(heap, i)
|
|
break
|
|
}
|
|
}
|
|
checkHeap(t, heap)
|
|
for i := range heap {
|
|
if heap[i].ev.time == 5 {
|
|
t.Fatalf("failed to remove heap elem with time %d: %s", 5, heapDebugString(heap))
|
|
}
|
|
}
|
|
|
|
// Remove tail.
|
|
heap = heapRemove(heap, len(heap)-1)
|
|
checkHeap(t, heap)
|
|
|
|
// Remove from the head, and make sure the result is sorted.
|
|
l := len(heap)
|
|
var removed []*batchCursor
|
|
for i := 0; i < l; i++ {
|
|
removed = append(removed, heap[0])
|
|
heap = heapRemove(heap, 0)
|
|
checkHeap(t, heap)
|
|
}
|
|
if !slices.IsSortedFunc(removed, (*batchCursor).compare) {
|
|
t.Fatalf("heap elements not removed in sorted order, got: %s", heapDebugString(removed))
|
|
}
|
|
}
|
|
|
|
func makeBatchCursor(v int64) *batchCursor {
|
|
return &batchCursor{ev: baseEvent{time: Time(v)}}
|
|
}
|
|
|
|
func heapDebugString(heap []*batchCursor) string {
|
|
var sb strings.Builder
|
|
fmt.Fprintf(&sb, "[")
|
|
for i := range heap {
|
|
if i != 0 {
|
|
fmt.Fprintf(&sb, ", ")
|
|
}
|
|
fmt.Fprintf(&sb, "%d", heap[i].ev.time)
|
|
}
|
|
fmt.Fprintf(&sb, "]")
|
|
return sb.String()
|
|
}
|
|
|
|
func checkHeap(t *testing.T, heap []*batchCursor) {
|
|
t.Helper()
|
|
|
|
for i := range heap {
|
|
if i == 0 {
|
|
continue
|
|
}
|
|
if heap[(i-1)/2].compare(heap[i]) > 0 {
|
|
t.Errorf("heap invariant not maintained between index %d and parent %d: %s", i, i/2, heapDebugString(heap))
|
|
}
|
|
}
|
|
if t.Failed() {
|
|
t.FailNow()
|
|
}
|
|
}
|