internal/control/termsafe_test.go

v1.43.0
gitbay/internal/control/termsafe_test.go history · blame · raw

89 lines · 2682 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
12const evil = "x\x1b]52;c;ZXZpbA==\x07y\x1b[2Jz"
13
14func TestTermSafe(t *testing.T) {
15	cases := map[string]string{
16		"plain\ttext\n":   "plain\ttext\n",
17		"a\x1bb":          "a�b",
18		"a\x00c\x7fd":     "a�c�d",
19		"a\r\nb\r\n":      "a\nb\n",
20		"a\rb":            "ab",
21		"a\u0085b\u009bc": "a�b�c",
22		"ümlaut":          "ümlaut",
23	}
24	for in, want := range cases {
25		if got := termSafe(in); got != want {
26			t.Errorf("termSafe(%q) = %q, want %q", in, got, want)
27		}
28	}
29}
30
31func noControls(t *testing.T, what, out string) {
32	t.Helper()
33	s := stripSGR(out)
34	if strings.ContainsAny(s, "\x1b\x07") {
35		t.Errorf("%s: control bytes reach the terminal: %q", what, s)
36	}
37}
38
39func TestTableRowControlBytes(t *testing.T) {
40	var plain, term bytes.Buffer
41	for _, c := range []struct {
42		ctx *Ctx
43		w   *bytes.Buffer
44	}{{&Ctx{}, &plain}, {&Ctx{Term: Term{Cols: 80, Color: true}}, &term}} {
45		tb := c.ctx.table(c.w, "#", "STATE", "TITLE")
46		tb.row(cRef("#1"), cState("open"), cFlex(evil))
47		tb.flush()
48	}
49	noControls(t, "table", term.String())
50	if want := "#1\topen\t" + evil + "\n"; plain.String() != want {
51		t.Errorf("plain changed: %q", plain.String())
52	}
53}
54
55func TestIssueShowControlBytes(t *testing.T) {
56	show := func(term Term) string {
57		st, repo, uid := newQueueTestRepo(t)
58		if _, err := st.CreateIssue(repo.ID, uid, evil, "body "+evil, "md"); err != nil {
59			t.Fatal(err)
60		}
61		c, errOut := pruneCtx(st, t.TempDir(), store.User{ID: uid, Username: "alice"})
62		c.Term = term
63		if code := Dispatch(c, []string{"issue", "show", repo.Path(), "1"}); code != protocol.ExitOK {
64			t.Fatalf("exit %d: %s", code, errOut)
65		}
66		return c.Stdout.(*bytes.Buffer).String()
67	}
68	noControls(t, "issue show", show(Term{Cols: 80, Color: true}))
69	if out := show(Term{}); !strings.Contains(out, "#1  "+evil+"  open\n") {
70		t.Errorf("plain title changed:\n%q", out)
71	}
72}
73
74// A body written in a browser arrives with CRLF line endings.
75func TestIssueShowCRLFBody(t *testing.T) {
76	st, repo, uid := newQueueTestRepo(t)
77	if _, err := st.CreateIssue(repo.ID, uid, "t", "first line\r\nsecond line\r\n", "md"); err != nil {
78		t.Fatal(err)
79	}
80	c, errOut := pruneCtx(st, t.TempDir(), store.User{ID: uid, Username: "alice"})
81	c.Term = Term{Cols: 80}
82	if code := Dispatch(c, []string{"issue", "show", repo.Path(), "1"}); code != protocol.ExitOK {
83		t.Fatalf("exit %d: %s", code, errOut)
84	}
85	out := c.Stdout.(*bytes.Buffer).String()
86	if strings.ContainsAny(out, "\r�") || !strings.Contains(out, "first line second line") {
87		t.Errorf("CRLF body at a terminal:\n%q", out)
88	}
89}