internal/control/cursor_test.go

v1.43.1
gitbay/internal/control/cursor_test.go history · blame · raw

96 lines · 2763 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 TestShellWord(t *testing.T) {
13	tests := []struct {
14		input string
15		want  string
16	}{
17		{"plain", "plain"},
18		{"foo-bar", "foo-bar"},
19		{"123", "123"},
20		{"foo bar", "'foo bar'"},
21		{"it's", "'it'\\''s'"},
22		{"a'b'c", "'a'\\''b'\\''c'"},
23		{"", "''"},
24	}
25	for _, tt := range tests {
26		if got := shellWord(tt.input); got != tt.want {
27			t.Errorf("shellWord(%q) = %q, want %q", tt.input, got, tt.want)
28		}
29	}
30}
31
32func TestCursorRoundTrip(t *testing.T) {
33	cur := encodeCursor("issue", "42")
34	key, err := decodeCursor("issue", cur)
35	if err != nil || key != "42" {
36		t.Fatalf("decode = %q, %v", key, err)
37	}
38	if _, err := decodeCursor("mr", cur); err == nil {
39		t.Fatal("cursor accepted under the wrong kind")
40	}
41	if _, err := decodeCursor("issue", "not base64!"); err == nil {
42		t.Fatal("garbage cursor accepted")
43	}
44	if _, err := decodeCursor("issue", encodeCursor("issue", "")); err == nil {
45		t.Fatal("empty key accepted")
46	}
47}
48
49func TestTrimPage(t *testing.T) {
50	key := func(n int) string { return "k" }
51	// No probe row: page as-is, no next.
52	items, next := trimPage(page{limit: 3}, []int{1, 2, 3}, "issue", key)
53	if len(items) != 3 || next != "" {
54		t.Fatalf("full page: %v next=%q", items, next)
55	}
56	// Probe row present: trimmed, next minted.
57	items, next = trimPage(page{limit: 2}, []int{1, 2, 3}, "issue", key)
58	if len(items) != 2 || next == "" {
59		t.Fatalf("trimmed page: %v next=%q", items, next)
60	}
61	// Unpaged: untouched.
62	items, next = trimPage(page{}, []int{1, 2, 3}, "issue", key)
63	if len(items) != 3 || next != "" {
64		t.Fatalf("unpaged: %v next=%q", items, next)
65	}
66}
67
68func TestEmitPageHintsTheNextPageAtATerminal(t *testing.T) {
69	st, repo, uid := newQueueTestRepo(t)
70	for i := 0; i < 3; i++ {
71		if _, err := st.CreateBuild(repo.ID, "unit", "aaa", "main", `["true"]`, "", "", true); err != nil {
72			t.Fatal(err)
73		}
74	}
75	c, errOut := pruneCtx(st, t.TempDir(), store.User{ID: uid})
76	c.Term = Term{Cols: 100}
77	if code := Dispatch(c, []string{"build", "list", repo.Path(), "--limit", "2"}); code != protocol.ExitOK {
78		t.Fatalf("exit %d: %s", code, errOut)
79	}
80	if strings.Contains(c.Stdout.(*bytes.Buffer).String(), "next\t") {
81		t.Errorf("cursor row on stdout at a terminal")
82	}
83	stderr := errOut.String()
84	cmd, ok := strings.CutPrefix(stderr, "Next page  ")
85	if !ok {
86		t.Fatalf("stderr = %q, want a Next page line", stderr)
87	}
88	want := "gitbay build list " + repo.Path() + " --limit 2 --cursor "
89	if !strings.HasPrefix(cmd, want) {
90		t.Errorf("command = %q, want %q…", cmd, want)
91	}
92	// No empty word in the command.
93	if strings.Contains(cmd, "  ") {
94		t.Errorf("command contains double space: %q", cmd)
95	}
96}