1
2
3
4
5
6
7
8
9 package trace
10
11 import (
12 "fmt"
13 "strings"
14 "testing"
15
16 "slices"
17 )
18
19 func TestHeap(t *testing.T) {
20 var heap []*batchCursor
21
22
23 checkHeap(t, heap)
24 heap = heapInsert(heap, makeBatchCursor(5))
25 checkHeap(t, heap)
26 for i := int64(-20); i < 20; i++ {
27 heap = heapInsert(heap, makeBatchCursor(i))
28 checkHeap(t, heap)
29 }
30
31
32 for i := range heap {
33 if heap[i].ev.time == 5 {
34 heap[i].ev.time = -21
35 heapUpdate(heap, i)
36 break
37 }
38 }
39 checkHeap(t, heap)
40 if heap[0].ev.time != -21 {
41 t.Fatalf("heap update failed, expected %d as heap min: %s", -21, heapDebugString(heap))
42 }
43
44
45 heap[0].ev.time = -22
46 heapUpdate(heap, 0)
47 checkHeap(t, heap)
48 if heap[0].ev.time != -22 {
49 t.Fatalf("heap update failed, expected %d as heap min: %s", -22, heapDebugString(heap))
50 }
51
52
53 heap[len(heap)-1].ev.time = 21
54 heapUpdate(heap, len(heap)-1)
55 checkHeap(t, heap)
56 if heap[len(heap)-1].ev.time != 21 {
57 t.Fatalf("heap update failed, expected %d as heap min: %s", 21, heapDebugString(heap))
58 }
59
60
61 heap[len(heap)-1].ev.time = 7
62 heapUpdate(heap, len(heap)-1)
63 checkHeap(t, heap)
64 if heap[len(heap)-1].ev.time == 21 {
65 t.Fatalf("heap update failed, unexpected %d as heap min: %s", 21, heapDebugString(heap))
66 }
67
68
69 for i := range heap {
70 if heap[i].ev.time == 5 {
71 heap = heapRemove(heap, i)
72 break
73 }
74 }
75 checkHeap(t, heap)
76 for i := range heap {
77 if heap[i].ev.time == 5 {
78 t.Fatalf("failed to remove heap elem with time %d: %s", 5, heapDebugString(heap))
79 }
80 }
81
82
83 heap = heapRemove(heap, len(heap)-1)
84 checkHeap(t, heap)
85
86
87 l := len(heap)
88 var removed []*batchCursor
89 for i := 0; i < l; i++ {
90 removed = append(removed, heap[0])
91 heap = heapRemove(heap, 0)
92 checkHeap(t, heap)
93 }
94 if !slices.IsSortedFunc(removed, (*batchCursor).compare) {
95 t.Fatalf("heap elements not removed in sorted order, got: %s", heapDebugString(removed))
96 }
97 }
98
99 func makeBatchCursor(v int64) *batchCursor {
100 return &batchCursor{ev: baseEvent{time: Time(v)}}
101 }
102
103 func heapDebugString(heap []*batchCursor) string {
104 var sb strings.Builder
105 fmt.Fprintf(&sb, "[")
106 for i := range heap {
107 if i != 0 {
108 fmt.Fprintf(&sb, ", ")
109 }
110 fmt.Fprintf(&sb, "%d", heap[i].ev.time)
111 }
112 fmt.Fprintf(&sb, "]")
113 return sb.String()
114 }
115
116 func checkHeap(t *testing.T, heap []*batchCursor) {
117 t.Helper()
118
119 for i := range heap {
120 if i == 0 {
121 continue
122 }
123 if heap[(i-1)/2].compare(heap[i]) > 0 {
124 t.Errorf("heap invariant not maintained between index %d and parent %d: %s", i, i/2, heapDebugString(heap))
125 }
126 }
127 if t.Failed() {
128 t.FailNow()
129 }
130 }
131
View as plain text