internal/control/termsafe_test.go
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}