parent_cycle_test.go
1package main
2
3import (
4 "strings"
5 "testing"
6 "time"
7)
8
9func TestCreatesParentCycle(t *testing.T) {
10 issues := []BugIssue{
11 {FullID: "grandparent"},
12 {FullID: "parent", ParentID: "grandparent"},
13 {FullID: "child", ParentID: "parent"},
14 {FullID: "unrelated"},
15 }
16
17 tests := []struct {
18 name string
19 bug string
20 parent string
21 want bool
22 }{
23 {"direct cycle", "parent", "child", true},
24 {"indirect cycle", "grandparent", "child", true},
25 {"self link", "child", "child", true},
26 {"unrelated link", "unrelated", "child", false},
27 {"sibling link", "child", "unrelated", false},
28 }
29
30 for _, tt := range tests {
31 t.Run(tt.name, func(t *testing.T) {
32 if got := createsParentCycle(issues, tt.bug, tt.parent); got != tt.want {
33 t.Errorf("createsParentCycle(%q, %q) = %v, want %v", tt.bug, tt.parent, got, tt.want)
34 }
35 })
36 }
37}
38
39// TestBuildIssueTree_CycleNodesShownOnce ensures issues in a dependency
40// cycle (possible only via manual metadata tampering, since the CLI
41// refuses to create cycles) are still displayed exactly once instead
42// of silently vanishing from `bug ls`.
43func TestBuildIssueTree_CycleNodesShownOnce(t *testing.T) {
44 now := time.Now()
45 issues := []BugIssue{
46 {FullID: "aaa", ShortID: "aaa", Title: "A", CreatedAt: now.Add(-3 * time.Hour), ParentID: "bbb"},
47 {FullID: "bbb", ShortID: "bbb", Title: "B", CreatedAt: now.Add(-2 * time.Hour), ParentID: "aaa"},
48 {FullID: "root", ShortID: "root", Title: "Root", CreatedAt: now.Add(-1 * time.Hour)},
49 }
50
51 roots := buildIssueTree(issues)
52 out := captureTreeOutput(t, roots)
53
54 for _, id := range []string{"aaa", "bbb", "root"} {
55 if got := strings.Count(out, id); got != 1 {
56 t.Errorf("ID %q appears %d times, want exactly once\noutput:\n%s", id, got, out)
57 }
58 }
59}