1package list
2
3import (
4 "fmt"
5 "testing"
6
7 tea "github.com/charmbracelet/bubbletea/v2"
8)
9
10// Mock item for benchmarking
11type benchItem struct {
12 id string
13 content string
14 height int
15 width int
16}
17
18func (b benchItem) ID() string {
19 return b.id
20}
21
22func (b benchItem) SetSize(width, height int) tea.Cmd {
23 b.width = width
24 b.height = height
25 return nil
26}
27
28func (b benchItem) GetSize() (int, int) {
29 return b.width, b.height
30}
31
32func (b benchItem) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
33 return b, nil
34}
35
36func (b benchItem) Init() tea.Cmd {
37 return nil
38}
39
40func (b benchItem) View() string {
41 return b.content
42}
43
44func (b benchItem) Height() int {
45 return b.height
46}
47
48// createBenchItems creates n items for benchmarking
49func createBenchItems(n int) []Item {
50 items := make([]Item, n)
51 for i := 0; i < n; i++ {
52 items[i] = benchItem{
53 id: fmt.Sprintf("item-%d", i),
54 content: fmt.Sprintf("This is item %d with some content that spans multiple lines\nLine 2\nLine 3", i),
55 height: 3,
56 }
57 }
58 return items
59}
60
61// BenchmarkListRender benchmarks the render performance with different list sizes
62func BenchmarkListRender(b *testing.B) {
63 sizes := []int{100, 500, 1000, 5000, 10000}
64
65 for _, size := range sizes {
66 b.Run(fmt.Sprintf("Items_%d", size), func(b *testing.B) {
67 items := createBenchItems(size)
68 list := New(items, WithDirectionForward()).(*list[Item])
69
70 // Set dimensions
71 list.SetSize(80, 30)
72
73 // Initialize to calculate positions
74 list.Init()
75
76 b.ResetTimer()
77 for i := 0; i < b.N; i++ {
78 list.render()
79 }
80 })
81 }
82}
83
84// BenchmarkListScroll benchmarks scrolling performance
85func BenchmarkListScroll(b *testing.B) {
86 sizes := []int{100, 500, 1000, 5000, 10000}
87
88 for _, size := range sizes {
89 b.Run(fmt.Sprintf("Items_%d", size), func(b *testing.B) {
90 items := createBenchItems(size)
91 list := New(items, WithDirectionForward())
92
93 // Set dimensions
94 list.SetSize(80, 30)
95
96 // Initialize
97 list.Init()
98
99 b.ResetTimer()
100 for i := 0; i < b.N; i++ {
101 // Scroll down and up
102 list.MoveDown(10)
103 list.MoveUp(10)
104 }
105 })
106 }
107}
108
109// BenchmarkListView benchmarks the View() method performance
110func BenchmarkListView(b *testing.B) {
111 sizes := []int{100, 500, 1000, 5000, 10000}
112
113 for _, size := range sizes {
114 b.Run(fmt.Sprintf("Items_%d", size), func(b *testing.B) {
115 items := createBenchItems(size)
116 list := New(items, WithDirectionForward()).(*list[Item])
117
118 // Set dimensions
119 list.SetSize(80, 30)
120
121 // Initialize and render once
122 list.Init()
123 list.render()
124
125 b.ResetTimer()
126 for i := 0; i < b.N; i++ {
127 _ = list.View()
128 }
129 })
130 }
131}
132
133// BenchmarkListMemory benchmarks memory allocation
134func BenchmarkListMemory(b *testing.B) {
135 sizes := []int{100, 500, 1000, 5000, 10000}
136
137 for _, size := range sizes {
138 b.Run(fmt.Sprintf("Items_%d", size), func(b *testing.B) {
139 b.ReportAllocs()
140
141 for i := 0; i < b.N; i++ {
142 items := createBenchItems(size)
143 list := New(items, WithDirectionForward()).(*list[Item])
144 list.SetSize(80, 30)
145 list.Init()
146 list.render()
147 _ = list.View()
148 }
149 })
150 }
151}
152
153// BenchmarkVirtualScrolling specifically tests virtual scrolling efficiency
154func BenchmarkVirtualScrolling(b *testing.B) {
155 // Test with a very large list to see virtual scrolling benefits
156 items := createBenchItems(10000)
157 list := New(items, WithDirectionForward()).(*list[Item])
158 list.SetSize(80, 30)
159 list.Init()
160
161 b.Run("RenderVisibleOnly", func(b *testing.B) {
162 b.ResetTimer()
163 for i := 0; i < b.N; i++ {
164 // This should only render ~10 items that fit in viewport
165 list.renderVirtualScrolling()
166 }
167 })
168
169 b.Run("ScrollThroughList", func(b *testing.B) {
170 b.ResetTimer()
171 for i := 0; i < b.N; i++ {
172 // Scroll through the entire list
173 for j := 0; j < 100; j++ {
174 list.MoveDown(100)
175 }
176 // Reset to top
177 list.GoToTop()
178 }
179 })
180}
181
182// BenchmarkCalculatePositions benchmarks position calculation
183func BenchmarkCalculatePositions(b *testing.B) {
184 sizes := []int{100, 500, 1000, 5000, 10000}
185
186 for _, size := range sizes {
187 b.Run(fmt.Sprintf("Items_%d", size), func(b *testing.B) {
188 items := createBenchItems(size)
189 list := New(items, WithDirectionForward()).(*list[Item])
190 list.SetSize(80, 30)
191
192 b.ResetTimer()
193 for i := 0; i < b.N; i++ {
194 list.calculateItemPositions()
195 }
196 })
197 }
198}