internal/control/mrscreen_test.go
132 lines · 4255 bytes
1package control
2
3import (
4 "strings"
5 "testing"
6 "time"
7
8 "gitbay.org/gitbay/internal/gitutil"
9 "gitbay.org/gitbay/internal/protocol"
10 "gitbay.org/gitbay/internal/store"
11)
12
13func TestMRShowPlainPinned(t *testing.T) {
14 st, repo, owner := twoMRTestRepo(t)
15 mr, err := st.MRByNumber(repo.ID, 1)
16 if err != nil {
17 t.Fatal(err)
18 }
19 if err := st.AddMRComment(mr.ID, owner.ID, "Looks right.", "md"); err != nil {
20 t.Fatal(err)
21 }
22 for _, ctx := range []string{"test", "build"} {
23 if err := st.SetCommitStatus(repo.ID, "abc111", ctx, "success", "", "", owner.ID); err != nil {
24 t.Fatal(err)
25 }
26 }
27 c, out, errOut := mrTestCtx(st, owner)
28 if code := Dispatch(c, []string{"mr", "show", repo.Path(), "1"}); code != protocol.ExitOK {
29 t.Fatalf("exit %d: %s", code, errOut)
30 }
31 pinPlain(t, "mr-show", out.String())
32}
33
34func mrShowFixture() MRShow {
35 d := MRShow{mrOut: mrOut{Number: 552, Title: "wire $PAGER through long views", State: "open",
36 Author: "cmc", Source: "cli-pager", TargetRef: "main", Body: "Pages long views.", BodyFormat: "md",
37 CreatedAt: "2026-10-01T11:40:00Z"}}
38 d.Commits = []CommitOut{{"8f3a1c2aaaaaaaa", "cli: page long output"}, {"2b77e90bbbbbbbb", "control: mark views"}}
39 d.Checks = []CheckOut{{Context: "test", State: "pending"}, {Context: "build", State: "success"}}
40 d.Gates = &GatesOut{ApprovalsRequired: 1, FastForward: false, Unmet: []string{"needs 1 approval", "behind main"}}
41 d.Comments = []commentOut{
42 {ID: 1, Author: "alice", Body: "Looks right.", BodyFormat: "md", CreatedAt: "2026-10-01T11:50:00Z", Kind: "comment"},
43 {ID: 2, Author: "cmc", Body: "marked ready", CreatedAt: "2026-10-01T11:51:00Z", Kind: "system"},
44 }
45 return d
46}
47
48func actionArgvs(s screen, group string) [][]string {
49 var out [][]string
50 for _, a := range s.actions {
51 if a.group == group {
52 out = append(out, a.argv)
53 }
54 }
55 return out
56}
57
58func sectionCounts(s screen) map[string]int {
59 m := map[string]int{}
60 for _, sec := range s.sections {
61 m[sec.title] = sec.n
62 }
63 return m
64}
65
66var screenRepo = store.Repo{OwnerName: "krz", Name: "gitbay", DefaultBranch: "main"}
67
68func TestMRShowScreenBehind(t *testing.T) {
69 c := screenCtx(100, false)
70 s := mrShowScreen(c, screenRepo, mrShowFixture(), []gitutil.NumStat{{Path: "cmd/gitbay/ssh.go", Added: 41, Deleted: 6, Status: "M"}})
71 if got := actionArgvs(s, "Unblock"); len(got) != 1 || got[0][1] != "rebase" {
72 t.Errorf("Unblock = %q, want mr rebase", got)
73 }
74 if got := actionArgvs(s, "Merge"); len(got) != 0 {
75 t.Errorf("Merge offered with unmet gates: %q", got)
76 }
77 if n := sectionCounts(s); n["Commits"] != 2 || n["Files"] != 1 || n["Discussion"] != 1 {
78 t.Errorf("sections = %v", n)
79 }
80 checkActions(t, s)
81}
82
83func TestMRShowScreenReady(t *testing.T) {
84 c := screenCtx(100, false)
85 d := mrShowFixture()
86 d.Gates = &GatesOut{FastForward: true}
87 s := mrShowScreen(c, screenRepo, d, nil)
88 if len(actionArgvs(s, "Unblock")) != 0 {
89 t.Error("Unblock offered when nothing blocks")
90 }
91 if got := actionArgvs(s, "Merge"); len(got) != 1 || got[0][1] != "merge" {
92 t.Errorf("Merge = %q", got)
93 }
94 checkActions(t, s)
95}
96
97func TestMRShowScreenMergedOffersOnlyReading(t *testing.T) {
98 c := screenCtx(100, false)
99 d := mrShowFixture()
100 d.State, d.Gates = "merged", nil
101 s := mrShowScreen(c, screenRepo, d, nil)
102 for _, a := range s.actions {
103 if a.group != "Read" {
104 t.Errorf("merged MR offers %q", a.argv)
105 }
106 }
107}
108
109func TestMRShowScreenRenders(t *testing.T) {
110 termNow = func() time.Time { return time.Date(2026, 10, 1, 12, 0, 0, 0, time.UTC) }
111 t.Cleanup(func() { termNow = time.Now })
112 c := screenCtx(100, false)
113 c.Term.Here = "krz/gitbay"
114 s := mrShowScreen(c, screenRepo, mrShowFixture(), []gitutil.NumStat{{Path: "cmd/gitbay/ssh.go", Added: 41, Deleted: 6, Status: "M"}})
115 out := renderString(c, s)
116 for _, want := range []string{
117 "Merge: !552 wire $PAGER through long views\n",
118 "Gates: ✗ needs 1 approval · ✗ behind main\n",
119 "Pages long views.\n",
120 "Files (1) +41 −6\n",
121 "alice 10m ago\n Looks right.\n",
122 "gitbay mr rebase 552",
123 "gitbay mr diff 552",
124 } {
125 if !strings.Contains(out, want) {
126 t.Errorf("missing %q in:\n%s", want, out)
127 }
128 }
129 if !strings.Contains(out, "Events (1)\n9m ago marked ready\n") {
130 t.Errorf("system event not under Events:\n%s", out)
131 }
132}