176 lines
4.7 KiB
Go
176 lines
4.7 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"charm.land/lipgloss/v2"
|
|
"superwork-tui/internal/issue"
|
|
)
|
|
|
|
func makeDoneIssues(n int) []issue.Issue {
|
|
issues := make([]issue.Issue, n)
|
|
for i := range issues {
|
|
issues[i] = issue.Issue{Number: i + 1, Title: fmt.Sprintf("Issue %d", i+1), Column: issue.ColumnDone}
|
|
}
|
|
return issues
|
|
}
|
|
|
|
func makeInProgressIssues(n int) []issue.Issue {
|
|
issues := make([]issue.Issue, n)
|
|
for i := range issues {
|
|
issues[i] = issue.Issue{Number: i + 1, Title: fmt.Sprintf("Issue %d", i+1), Column: issue.ColumnInProgress}
|
|
}
|
|
return issues
|
|
}
|
|
|
|
func makeTodoIssues(n int) []issue.Issue {
|
|
issues := make([]issue.Issue, n)
|
|
for i := range issues {
|
|
issues[i] = issue.Issue{Number: i + 1, Title: fmt.Sprintf("Issue %d", i+1), Column: issue.ColumnTodo}
|
|
}
|
|
return issues
|
|
}
|
|
|
|
// TestRenderColumn_HeightBound: 30 done issues with boxH=20 must render exactly 20 lines (outer) and show ▼.
|
|
func TestRenderColumn_HeightBound(t *testing.T) {
|
|
doneIssues := makeDoneIssues(30)
|
|
all := make([]issue.Issue, len(doneIssues))
|
|
copy(all, doneIssues)
|
|
var buckets [4][]issue.Issue
|
|
buckets[3] = doneIssues
|
|
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: all,
|
|
buckets: buckets,
|
|
width: 120,
|
|
height: 40,
|
|
colIdx: 0,
|
|
rowIdx: 0,
|
|
}
|
|
|
|
const boxH = 20
|
|
result := m.renderColumn(3, 30, boxH)
|
|
h := lipgloss.Height(result)
|
|
// outer box = inner(boxH-2) + 2 border rows = boxH
|
|
if h != boxH {
|
|
t.Errorf("renderColumn height = %d, want %d", h, boxH)
|
|
}
|
|
if !strings.Contains(result, "▼") {
|
|
t.Errorf("renderColumn missing ▼ indicator when cards overflow; got:\n%s", result)
|
|
}
|
|
}
|
|
|
|
// TestRenderColumn_ScrollIntoView: 20 in-progress issues, selected at rowIdx=15.
|
|
// boxH=10 → cardsH=7, so card at idx=15 requires scrolling. Expect ▲ and card visible.
|
|
func TestRenderColumn_ScrollIntoView(t *testing.T) {
|
|
inpIssues := makeInProgressIssues(20)
|
|
var buckets [4][]issue.Issue
|
|
buckets[1] = inpIssues
|
|
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: inpIssues,
|
|
buckets: buckets,
|
|
width: 120,
|
|
height: 40,
|
|
colIdx: 1,
|
|
rowIdx: 15,
|
|
}
|
|
|
|
const boxH = 10 // cardsH = 10-3 = 7; card at idx=15 needs scroll
|
|
result := m.renderColumn(1, 30, boxH)
|
|
want := fmt.Sprintf("Issue %d", 16) // rowIdx=15 → Number=16
|
|
if !strings.Contains(result, want) {
|
|
t.Errorf("renderColumn missing selected card %q after scroll; got:\n%s", want, result)
|
|
}
|
|
if !strings.Contains(result, "▲") {
|
|
t.Errorf("renderColumn missing ▲ indicator when scrolled down; got:\n%s", result)
|
|
}
|
|
}
|
|
|
|
// TestBoardView_HeightBound: board with height=30 and 30 done issues — column portion height = height-2.
|
|
func TestBoardView_HeightBound(t *testing.T) {
|
|
doneIssues := makeDoneIssues(30)
|
|
var buckets [4][]issue.Issue
|
|
buckets[3] = doneIssues
|
|
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: doneIssues,
|
|
buckets: buckets,
|
|
width: 120,
|
|
height: 30,
|
|
colIdx: 0,
|
|
rowIdx: 0,
|
|
}
|
|
|
|
v := m.boardView()
|
|
// Extract board portion (everything before the final help line).
|
|
lines := strings.Split(v, "\n")
|
|
// Help line is the last non-empty line. Board = height-2 outer rows.
|
|
// Total view lines ≤ m.height (board rows + 1 help row).
|
|
h := lipgloss.Height(v)
|
|
if h > m.height {
|
|
t.Errorf("boardView total height = %d, want ≤ %d", h, m.height)
|
|
}
|
|
_ = lines
|
|
}
|
|
|
|
// TestRenderColumn_EmptyColEqualHeight: empty col 0 and 5-issue col 1 must both render at boxH.
|
|
func TestRenderColumn_EmptyColEqualHeight(t *testing.T) {
|
|
inpIssues := makeInProgressIssues(5)
|
|
var buckets [4][]issue.Issue
|
|
buckets[1] = inpIssues
|
|
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: inpIssues,
|
|
buckets: buckets,
|
|
width: 120,
|
|
height: 40,
|
|
colIdx: 1,
|
|
rowIdx: 0,
|
|
}
|
|
|
|
const boxH = 20
|
|
emptyCol := m.renderColumn(0, 30, boxH)
|
|
filledCol := m.renderColumn(1, 30, boxH)
|
|
hEmpty := lipgloss.Height(emptyCol)
|
|
hFilled := lipgloss.Height(filledCol)
|
|
if hEmpty != boxH {
|
|
t.Errorf("empty col height=%d, want %d", hEmpty, boxH)
|
|
}
|
|
if hFilled != boxH {
|
|
t.Errorf("filled col height=%d, want %d", hFilled, boxH)
|
|
}
|
|
}
|
|
|
|
// TestRenderColumn_TodoScrollIntoView: 15 todo issues, selected at rowIdx=12 → card visible + ▲ shown.
|
|
func TestRenderColumn_TodoScrollIntoView(t *testing.T) {
|
|
todoIssues := makeTodoIssues(15)
|
|
var buckets [4][]issue.Issue
|
|
buckets[0] = todoIssues
|
|
|
|
m := Model{
|
|
state: stateLoaded,
|
|
issues: todoIssues,
|
|
buckets: buckets,
|
|
width: 120,
|
|
height: 40,
|
|
colIdx: 0,
|
|
rowIdx: 12,
|
|
}
|
|
|
|
result := m.renderColumn(0, 30, 15)
|
|
want := fmt.Sprintf("Issue %d", 13) // rowIdx=12 → index 12 → Number=13
|
|
if !strings.Contains(result, want) {
|
|
t.Errorf("todo renderColumn missing selected card %q after scroll; got:\n%s", want, result)
|
|
}
|
|
if !strings.Contains(result, "▲") {
|
|
t.Errorf("todo renderColumn missing ▲ indicator when scrolled down; got:\n%s", result)
|
|
}
|
|
}
|