346 lines
8.3 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|