internal/control/view_test.go
128 lines · 4050 bytes
1package control
2
3import (
4 "bytes"
5 "strings"
6 "testing"
7
8 "gitbay.org/gitbay/internal/protocol"
9 "gitbay.org/gitbay/internal/store"
10)
11
12func showIssue(t *testing.T, term Term) string {
13 t.Helper()
14 st, repo, uid := newQueueTestRepo(t)
15 n, err := st.CreateIssue(repo.ID, uid, "A title", "Body with a [link](/x/y).", "md")
16 if err != nil {
17 t.Fatal(err)
18 }
19 issue, err := st.IssueByNumber(repo.ID, n)
20 if err != nil {
21 t.Fatal(err)
22 }
23 if err := st.AddIssueSystemComment(issue.ID, uid, "referenced in commit [abc1234567](/o/r/commit/abc) by [alice](/alice)"); err != nil {
24 t.Fatal(err)
25 }
26 c, errOut := pruneCtx(st, t.TempDir(), store.User{ID: uid, Username: "alice"})
27 c.Cfg.Server.SiteURL = "https://forge.test"
28 c.Term = term
29 if code := Dispatch(c, []string{"issue", "show", repo.Path(), "1"}); code != protocol.ExitOK {
30 t.Fatalf("exit %d: %s", code, errOut)
31 }
32 return c.Stdout.(*bytes.Buffer).String()
33}
34
35func TestIssueShowPlain(t *testing.T) {
36 out := showIssue(t, Term{})
37 for _, want := range []string{
38 "#1 A title open\n",
39 " author alice, ",
40 " url https://forge.test/",
41 "Body with a link (https://forge.test/x/y).",
42 " · referenced in commit abc1234567 by alice ",
43 } {
44 if !strings.Contains(out, want) {
45 t.Errorf("missing %q in:\n%s", want, out)
46 }
47 }
48 if strings.Contains(out, "\x1b") || strings.Contains(out, "](") {
49 t.Errorf("markup or SGR in plain view:\n%s", out)
50 }
51}
52
53func TestIssueShowTerminal(t *testing.T) {
54 out := showIssue(t, Term{Cols: 60, Color: true})
55 if !strings.Contains(out, sgrGreen+"open"+sgrReset) {
56 t.Errorf("state not coloured:\n%s", out)
57 }
58 if !strings.Contains(out, " UTC") {
59 t.Errorf("no web-format timestamp:\n%s", out)
60 }
61 for _, line := range strings.Split(stripSGR(out), "\n") {
62 if cells(line) > 60 {
63 t.Errorf("line over 60 cells: %q", line)
64 }
65 }
66}
67
68// TestIssueShowNarrowWraps: a long title and long labels must not push
69// any line past the terminal width, and no content is lost to it.
70func TestIssueShowNarrowWraps(t *testing.T) {
71 st, repo, uid := newQueueTestRepo(t)
72 title := strings.TrimSpace(strings.Repeat("a very long issue title that keeps going on and on ", 3))[:90]
73 n, err := st.CreateIssue(repo.ID, uid, title, "body", "md")
74 if err != nil {
75 t.Fatal(err)
76 }
77 for _, name := range []string{"needs-review-before-merge", "blocked-on-release", "requires-design-signoff"} {
78 if err := st.SetLabel(repo, name, "888888"); err != nil {
79 t.Fatal(err)
80 }
81 if err := st.SetIssueLabel(repo, issueIDFor(t, st, repo.ID, n), name, true); err != nil {
82 t.Fatal(err)
83 }
84 }
85 // No SiteURL set: the url field stays a short path so it does not
86 // itself force an unbreakable line over width, which is not what
87 // this test is about (title/labels/author wrapping is).
88 c, errOut := pruneCtx(st, t.TempDir(), store.User{ID: uid, Username: "alice"})
89 c.Term = Term{Cols: 40, Color: true}
90 if code := Dispatch(c, []string{"issue", "show", repo.Path(), "1"}); code != protocol.ExitOK {
91 t.Fatalf("exit %d: %s", code, errOut)
92 }
93 out := c.Stdout.(*bytes.Buffer).String()
94
95 var titleLines []string
96 inTitle := false
97 for _, line := range strings.Split(stripSGR(out), "\n") {
98 if cells(line) > 40 {
99 t.Errorf("line over 40 cells: %q", line)
100 }
101 switch {
102 case strings.HasPrefix(line, "#1 "):
103 inTitle = true
104 titleLines = append(titleLines, strings.TrimPrefix(line, "#1 "))
105 case inTitle && strings.HasPrefix(line, " "):
106 titleLines = append(titleLines, strings.TrimSpace(line))
107 default:
108 inTitle = false
109 }
110 }
111 got := strings.Join(strings.Fields(strings.Join(titleLines, " ")), " ")
112 want := strings.Join(strings.Fields(title+" open"), " ")
113 if got != want {
114 t.Errorf("title text lost across wrap: got %q, want %q", got, want)
115 }
116 if n := strings.Count(stripSGR(out), "open"); n != 1 {
117 t.Errorf("state word appears %d times, want 1:\n%s", n, out)
118 }
119}
120
121func issueIDFor(t *testing.T, st *store.Store, repoID, n int64) int64 {
122 t.Helper()
123 issue, err := st.IssueByNumber(repoID, n)
124 if err != nil {
125 t.Fatal(err)
126 }
127 return issue.ID
128}