133 lines
4.7 KiB
Go
133 lines
4.7 KiB
Go
package tui
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"superwork-tui/internal/issue"
|
|
)
|
|
|
|
// ── isBlocked truth table ─────────────────────────────────────────────────────
|
|
|
|
func TestIsBlocked_NoPrerequisite(t *testing.T) {
|
|
it := issue.Issue{Number: 1, Column: issue.ColumnTodo, Prerequisite: 0}
|
|
if isBlocked(it, []issue.Issue{it}) {
|
|
t.Error("isBlocked = true, want false when Prerequisite == 0")
|
|
}
|
|
}
|
|
|
|
func TestIsBlocked_PrereqInDone(t *testing.T) {
|
|
prereq := issue.Issue{Number: 2, Column: issue.ColumnDone}
|
|
it := issue.Issue{Number: 1, Column: issue.ColumnTodo, Prerequisite: 2}
|
|
if isBlocked(it, []issue.Issue{it, prereq}) {
|
|
t.Error("isBlocked = true, want false when prerequisite is in ColumnDone")
|
|
}
|
|
}
|
|
|
|
func TestIsBlocked_PrereqNotInDone(t *testing.T) {
|
|
prereq := issue.Issue{Number: 2, Column: issue.ColumnTodo}
|
|
it := issue.Issue{Number: 1, Column: issue.ColumnTodo, Prerequisite: 2}
|
|
if !isBlocked(it, []issue.Issue{it, prereq}) {
|
|
t.Error("isBlocked = false, want true when prerequisite is in ColumnTodo")
|
|
}
|
|
}
|
|
|
|
func TestIsBlocked_PrereqInProgress(t *testing.T) {
|
|
prereq := issue.Issue{Number: 2, Column: issue.ColumnInProgress}
|
|
it := issue.Issue{Number: 1, Column: issue.ColumnTodo, Prerequisite: 2}
|
|
if !isBlocked(it, []issue.Issue{it, prereq}) {
|
|
t.Error("isBlocked = false, want true when prerequisite is in ColumnInProgress")
|
|
}
|
|
}
|
|
|
|
func TestIsBlocked_PrereqNotFound(t *testing.T) {
|
|
it := issue.Issue{Number: 1, Column: issue.ColumnTodo, Prerequisite: 99}
|
|
if !isBlocked(it, []issue.Issue{it}) {
|
|
t.Error("isBlocked = false, want true when prerequisite is not found")
|
|
}
|
|
}
|
|
|
|
// ── todoDepTree grouping ──────────────────────────────────────────────────────
|
|
|
|
func TestTodoDepTree_NoDeps(t *testing.T) {
|
|
todos := []issue.Issue{
|
|
{Number: 1, Column: issue.ColumnTodo},
|
|
{Number: 2, Column: issue.ColumnTodo},
|
|
{Number: 3, Column: issue.ColumnTodo},
|
|
}
|
|
entries := todoDepTree(todos)
|
|
if len(entries) != 3 {
|
|
t.Fatalf("len = %d, want 3", len(entries))
|
|
}
|
|
for i, e := range entries {
|
|
if e.indent {
|
|
t.Errorf("entries[%d].indent = true, want false (no deps)", i)
|
|
}
|
|
if e.iss.Number != todos[i].Number {
|
|
t.Errorf("entries[%d].iss.Number = %d, want %d", i, e.iss.Number, todos[i].Number)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTodoDepTree_BlockedChildAfterParent(t *testing.T) {
|
|
// #2 depends on #1; both in todo. #3 is independent.
|
|
todos := []issue.Issue{
|
|
{Number: 1, Column: issue.ColumnTodo, Prerequisite: 0},
|
|
{Number: 2, Column: issue.ColumnTodo, Prerequisite: 1},
|
|
{Number: 3, Column: issue.ColumnTodo, Prerequisite: 0},
|
|
}
|
|
entries := todoDepTree(todos)
|
|
if len(entries) != 3 {
|
|
t.Fatalf("len = %d, want 3", len(entries))
|
|
}
|
|
// Expected order: #1 (not indented), #2 (indented under #1), #3 (not indented)
|
|
if entries[0].iss.Number != 1 || entries[0].indent {
|
|
t.Errorf("entries[0] = {%d, indent=%v}, want {1, false}", entries[0].iss.Number, entries[0].indent)
|
|
}
|
|
if entries[1].iss.Number != 2 || !entries[1].indent {
|
|
t.Errorf("entries[1] = {%d, indent=%v}, want {2, true}", entries[1].iss.Number, entries[1].indent)
|
|
}
|
|
if entries[2].iss.Number != 3 || entries[2].indent {
|
|
t.Errorf("entries[2] = {%d, indent=%v}, want {3, false}", entries[2].iss.Number, entries[2].indent)
|
|
}
|
|
}
|
|
|
|
func TestTodoDepTree_ParentNotInTodo(t *testing.T) {
|
|
// #1 depends on #99 which is not in the todo list → #1 appears at top level.
|
|
todos := []issue.Issue{
|
|
{Number: 1, Column: issue.ColumnTodo, Prerequisite: 99},
|
|
{Number: 2, Column: issue.ColumnTodo, Prerequisite: 0},
|
|
}
|
|
entries := todoDepTree(todos)
|
|
if len(entries) != 2 {
|
|
t.Fatalf("len = %d, want 2", len(entries))
|
|
}
|
|
if entries[0].iss.Number != 1 || entries[0].indent {
|
|
t.Errorf("entries[0] = {%d, indent=%v}, want {1, false}", entries[0].iss.Number, entries[0].indent)
|
|
}
|
|
if entries[1].iss.Number != 2 || entries[1].indent {
|
|
t.Errorf("entries[1] = {%d, indent=%v}, want {2, false}", entries[1].iss.Number, entries[1].indent)
|
|
}
|
|
}
|
|
|
|
func TestTodoDepTree_AllEmitted(t *testing.T) {
|
|
// Ensure no duplicates and all issues appear exactly once.
|
|
todos := []issue.Issue{
|
|
{Number: 10, Column: issue.ColumnTodo, Prerequisite: 0},
|
|
{Number: 11, Column: issue.ColumnTodo, Prerequisite: 10},
|
|
{Number: 12, Column: issue.ColumnTodo, Prerequisite: 10},
|
|
}
|
|
entries := todoDepTree(todos)
|
|
if len(entries) != 3 {
|
|
t.Fatalf("len = %d, want 3", len(entries))
|
|
}
|
|
seen := make(map[int]int)
|
|
for _, e := range entries {
|
|
seen[e.iss.Number]++
|
|
}
|
|
for _, iss := range todos {
|
|
if seen[iss.Number] != 1 {
|
|
t.Errorf("issue #%d appeared %d times, want 1", iss.Number, seen[iss.Number])
|
|
}
|
|
}
|
|
}
|