list_bench_test.go

  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}