Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*.so
*.dylib
sysmon
sysmon-*

# Test binary, built with `go test -c`
*.test
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (m model) View() string {
// Main stats bars with labels overlaid in a 2x2 grid
// Calculate bar width for 2 bars per line with spacing
spacingBetweenBars := 2
availableWidth := m.width - 2
availableWidth := m.width
barWidth := (availableWidth - spacingBetweenBars) / 2
if barWidth < 20 {
barWidth = 20
Expand Down Expand Up @@ -196,7 +196,7 @@ func (m model) View() string {
coresPerLine := 4
spacingBetweenBars = 2

availableWidth = m.width - 2
availableWidth = m.width
// Each bar needs space for label (5 chars) + percentage (6 chars) + some bar space
// Total overhead is just spacing between bars since label/percent are inside
coreBarWidth := (availableWidth - (coresPerLine-1)*spacingBetweenBars) / coresPerLine
Expand Down
127 changes: 127 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"strings"
"testing"
)

Expand Down Expand Up @@ -76,3 +77,129 @@ func TestTruncateLeft(t *testing.T) {
})
}
}

func TestProgressBarWidths(t *testing.T) {
tests := []struct {
name string
terminalWidth int
}{
{
name: "standard terminal width",
terminalWidth: 80,
},
{
name: "wide terminal",
terminalWidth: 120,
},
{
name: "medium terminal",
terminalWidth: 100,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a model with known dimensions and stats
m := model{
width: tt.terminalWidth,
height: 24,
stats: SystemStats{
CPUUsage: 50.0,
GPUUsage: 25.0,
MemoryUsage: 60.0,
GPUMemory: 30.0,
CPUCores: []float64{10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0},
Processes: []ProcessInfo{
{PID: 1234, CPU: 10.5, Memory: 5.2, Command: "/usr/bin/test"},
},
},
}

// Render the view
view := m.View()
lines := strings.Split(view, "\n")

// Find the maximum line length in the rendered output
maxLen := 0
for _, line := range lines {
// Strip ANSI color codes to get actual character length
stripped := stripAnsiCodes(line)
if len(stripped) > maxLen {
maxLen = len(stripped)
}
}

// The fix ensures we use m.width instead of m.width-2.
// The view should use close to the full width (allowing for integer division).
// We verify the max line length is within [terminalWidth-1, terminalWidth],
// which confirms we're not using the old width-2 margin.
if maxLen < tt.terminalWidth-1 {
t.Errorf("View does not use enough terminal width: max line length %d, expected %d or %d (terminal width: %d)",
maxLen, tt.terminalWidth-1, tt.terminalWidth, tt.terminalWidth)
}

// Note: We don't enforce maxLen <= tt.terminalWidth because minimum bar widths
// can cause the view to exceed terminal width in narrow terminals. This is
// existing behavior that ensures bars remain readable.
})
}
}
Comment thread
narthur marked this conversation as resolved.

// stripAnsiCodes removes ANSI escape codes to get the actual display length
func stripAnsiCodes(s string) string {
// Simple regex-free approach: skip escape sequences
var result strings.Builder
i := 0
for i < len(s) {
if s[i] == '\x1b' && i+1 < len(s) && s[i+1] == '[' {
// Skip ANSI escape sequence
i += 2
for i < len(s) && s[i] != 'm' {
i++
}
i++ // skip 'm'
} else {
result.WriteByte(s[i])
i++
}
}
return result.String()
}

func TestViewRendersCorrectly(t *testing.T) {
// Create a model with known dimensions and stats
m := model{
width: 80,
height: 24,
stats: SystemStats{
CPUUsage: 50.0,
GPUUsage: 25.0,
MemoryUsage: 60.0,
GPUMemory: 30.0,
CPUCores: []float64{10.0, 20.0, 30.0, 40.0},
Processes: []ProcessInfo{
{PID: 1234, CPU: 10.5, Memory: 5.2, Command: "/usr/bin/test"},
},
},
}

// Render the view
view := m.View()

// Split into lines
lines := strings.Split(view, "\n")

// Basic sanity checks
if len(lines) < 5 {
t.Errorf("Expected at least 5 lines in output, got %d", len(lines))
}

Comment thread
narthur marked this conversation as resolved.
// Verify the view contains expected content
viewContent := strings.ToLower(view)
expectedStrings := []string{"cpu usage", "memory", "gpu usage", "pid", "command"}
for _, expected := range expectedStrings {
if !strings.Contains(viewContent, expected) {
t.Errorf("Expected view to contain %q", expected)
}
}
}
Loading