Files
tasksquire/internal/taskwarrior/tree_test.go
Martin Pander 418bcd96a8 Tear down everything
Fix config
2026-02-26 22:47:12 +01:00

346 lines
8.3 KiB
Go

package taskwarrior
import (
"testing"
)
func TestBuildTaskTree_EmptyList(t *testing.T) {
tasks := Tasks{}
tree := BuildTaskTree(tasks)
if tree == nil {
t.Fatal("Expected tree to be non-nil")
}
if len(tree.Nodes) != 0 {
t.Errorf("Expected 0 nodes, got %d", len(tree.Nodes))
}
if len(tree.Roots) != 0 {
t.Errorf("Expected 0 roots, got %d", len(tree.Roots))
}
if len(tree.FlatList) != 0 {
t.Errorf("Expected 0 items in flat list, got %d", len(tree.FlatList))
}
}
func TestBuildTaskTree_NoParents(t *testing.T) {
tasks := Tasks{
{Uuid: "task1", Description: "Task 1", Status: "pending"},
{Uuid: "task2", Description: "Task 2", Status: "pending"},
{Uuid: "task3", Description: "Task 3", Status: "completed"},
}
tree := BuildTaskTree(tasks)
if len(tree.Nodes) != 3 {
t.Errorf("Expected 3 nodes, got %d", len(tree.Nodes))
}
if len(tree.Roots) != 3 {
t.Errorf("Expected 3 roots (all tasks have no parent), got %d", len(tree.Roots))
}
if len(tree.FlatList) != 3 {
t.Errorf("Expected 3 items in flat list, got %d", len(tree.FlatList))
}
// All tasks should have depth 0
for i, node := range tree.FlatList {
if node.Depth != 0 {
t.Errorf("Task %d expected depth 0, got %d", i, node.Depth)
}
if node.HasChildren() {
t.Errorf("Task %d should not have children", i)
}
}
}
func TestBuildTaskTree_SimpleParentChild(t *testing.T) {
tasks := Tasks{
{Uuid: "parent1", Description: "Parent Task", Status: "pending"},
{
Uuid: "child1",
Description: "Child Task 1",
Status: "pending",
Udas: map[string]any{"parenttask": "parent1"},
},
{
Uuid: "child2",
Description: "Child Task 2",
Status: "completed",
Udas: map[string]any{"parenttask": "parent1"},
},
}
tree := BuildTaskTree(tasks)
if len(tree.Nodes) != 3 {
t.Fatalf("Expected 3 nodes, got %d", len(tree.Nodes))
}
if len(tree.Roots) != 1 {
t.Fatalf("Expected 1 root, got %d", len(tree.Roots))
}
// Check root is the parent
root := tree.Roots[0]
if root.Task.Uuid != "parent1" {
t.Errorf("Expected root to be parent1, got %s", root.Task.Uuid)
}
// Check parent has 2 children
if len(root.Children) != 2 {
t.Fatalf("Expected parent to have 2 children, got %d", len(root.Children))
}
// Check children status
completed, total := root.GetChildrenStatus()
if total != 2 {
t.Errorf("Expected total children = 2, got %d", total)
}
if completed != 1 {
t.Errorf("Expected completed children = 1, got %d", completed)
}
// Check flat list order (parent first, then children)
if len(tree.FlatList) != 3 {
t.Fatalf("Expected 3 items in flat list, got %d", len(tree.FlatList))
}
if tree.FlatList[0].Task.Uuid != "parent1" {
t.Errorf("Expected first item to be parent, got %s", tree.FlatList[0].Task.Uuid)
}
if tree.FlatList[0].Depth != 0 {
t.Errorf("Expected parent depth = 0, got %d", tree.FlatList[0].Depth)
}
// Children should be at depth 1
for i := 1; i < 3; i++ {
if tree.FlatList[i].Depth != 1 {
t.Errorf("Expected child %d depth = 1, got %d", i, tree.FlatList[i].Depth)
}
if tree.FlatList[i].Parent == nil {
t.Errorf("Child %d should have a parent", i)
} else if tree.FlatList[i].Parent.Task.Uuid != "parent1" {
t.Errorf("Child %d parent should be parent1, got %s", i, tree.FlatList[i].Parent.Task.Uuid)
}
}
}
func TestBuildTaskTree_MultiLevel(t *testing.T) {
tasks := Tasks{
{Uuid: "grandparent", Description: "Grandparent", Status: "pending"},
{
Uuid: "parent1",
Description: "Parent 1",
Status: "pending",
Udas: map[string]any{"parenttask": "grandparent"},
},
{
Uuid: "parent2",
Description: "Parent 2",
Status: "pending",
Udas: map[string]any{"parenttask": "grandparent"},
},
{
Uuid: "child1",
Description: "Child 1",
Status: "pending",
Udas: map[string]any{"parenttask": "parent1"},
},
{
Uuid: "grandchild1",
Description: "Grandchild 1",
Status: "completed",
Udas: map[string]any{"parenttask": "child1"},
},
}
tree := BuildTaskTree(tasks)
if len(tree.Nodes) != 5 {
t.Fatalf("Expected 5 nodes, got %d", len(tree.Nodes))
}
if len(tree.Roots) != 1 {
t.Fatalf("Expected 1 root, got %d", len(tree.Roots))
}
// Find nodes by UUID
grandparentNode := tree.Nodes["grandparent"]
parent1Node := tree.Nodes["parent1"]
child1Node := tree.Nodes["child1"]
grandchildNode := tree.Nodes["grandchild1"]
// Check depths
if grandparentNode.Depth != 0 {
t.Errorf("Expected grandparent depth = 0, got %d", grandparentNode.Depth)
}
if parent1Node.Depth != 1 {
t.Errorf("Expected parent1 depth = 1, got %d", parent1Node.Depth)
}
if child1Node.Depth != 2 {
t.Errorf("Expected child1 depth = 2, got %d", child1Node.Depth)
}
if grandchildNode.Depth != 3 {
t.Errorf("Expected grandchild depth = 3, got %d", grandchildNode.Depth)
}
// Check parent-child relationships
if len(grandparentNode.Children) != 2 {
t.Errorf("Expected grandparent to have 2 children, got %d", len(grandparentNode.Children))
}
if len(parent1Node.Children) != 1 {
t.Errorf("Expected parent1 to have 1 child, got %d", len(parent1Node.Children))
}
if len(child1Node.Children) != 1 {
t.Errorf("Expected child1 to have 1 child, got %d", len(child1Node.Children))
}
if grandchildNode.HasChildren() {
t.Error("Expected grandchild to have no children")
}
// Check flat list maintains tree order
if len(tree.FlatList) != 5 {
t.Fatalf("Expected 5 items in flat list, got %d", len(tree.FlatList))
}
// Grandparent should be first
if tree.FlatList[0].Task.Uuid != "grandparent" {
t.Errorf("Expected first item to be grandparent, got %s", tree.FlatList[0].Task.Uuid)
}
}
func TestBuildTaskTree_OrphanedTask(t *testing.T) {
tasks := Tasks{
{Uuid: "task1", Description: "Normal Task", Status: "pending"},
{
Uuid: "orphan",
Description: "Orphaned Task",
Status: "pending",
Udas: map[string]any{"parenttask": "nonexistent"},
},
}
tree := BuildTaskTree(tasks)
if len(tree.Nodes) != 2 {
t.Fatalf("Expected 2 nodes, got %d", len(tree.Nodes))
}
// Orphaned task should be treated as root
if len(tree.Roots) != 2 {
t.Errorf("Expected 2 roots (orphan should be treated as root), got %d", len(tree.Roots))
}
// Both should have depth 0
for _, node := range tree.FlatList {
if node.Depth != 0 {
t.Errorf("Expected all tasks to have depth 0, got %d for %s", node.Depth, node.Task.Description)
}
}
}
func TestTaskNode_GetChildrenStatus(t *testing.T) {
tests := []struct {
name string
children []*TaskNode
wantComp int
wantTotal int
}{
{
name: "no children",
children: []*TaskNode{},
wantComp: 0,
wantTotal: 0,
},
{
name: "all pending",
children: []*TaskNode{
{Task: &Task{Status: "pending"}},
{Task: &Task{Status: "pending"}},
},
wantComp: 0,
wantTotal: 2,
},
{
name: "all completed",
children: []*TaskNode{
{Task: &Task{Status: "completed"}},
{Task: &Task{Status: "completed"}},
{Task: &Task{Status: "completed"}},
},
wantComp: 3,
wantTotal: 3,
},
{
name: "mixed status",
children: []*TaskNode{
{Task: &Task{Status: "completed"}},
{Task: &Task{Status: "pending"}},
{Task: &Task{Status: "completed"}},
{Task: &Task{Status: "pending"}},
{Task: &Task{Status: "completed"}},
},
wantComp: 3,
wantTotal: 5,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
node := &TaskNode{
Task: &Task{},
Children: tt.children,
}
gotComp, gotTotal := node.GetChildrenStatus()
if gotComp != tt.wantComp {
t.Errorf("GetChildrenStatus() completed = %d, want %d", gotComp, tt.wantComp)
}
if gotTotal != tt.wantTotal {
t.Errorf("GetChildrenStatus() total = %d, want %d", gotTotal, tt.wantTotal)
}
})
}
}
func TestTaskNode_HasChildren(t *testing.T) {
tests := []struct {
name string
children []*TaskNode
want bool
}{
{
name: "no children",
children: []*TaskNode{},
want: false,
},
{
name: "has children",
children: []*TaskNode{{Task: &Task{}}},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
node := &TaskNode{
Task: &Task{},
Children: tt.children,
}
if got := node.HasChildren(); got != tt.want {
t.Errorf("HasChildren() = %v, want %v", got, tt.want)
}
})
}
}