Go · 3118 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package highlight
4
5 import (
6 "strings"
7 "testing"
8 )
9
10 func TestRenderLinesPreservesLineCount(t *testing.T) {
11 src := "package main\n\nfunc main() {\n\tprintln(\"hi\")\n}\n"
12 lines := RenderLines("main.go", src)
13 // strings.Split on the trailing newline produces a final empty
14 // element; RenderLines mirrors that so the row table has a row
15 // for the final newline (consistent with how vim / GitHub render
16 // trailing-newline files).
17 want := len(strings.Split(src, "\n"))
18 if len(lines) != want {
19 t.Fatalf("RenderLines produced %d lines; want %d", len(lines), want)
20 }
21 }
22
23 func TestRenderLinesNoLexerFallback(t *testing.T) {
24 src := "first line\nsecond line\nthird"
25 lines := RenderLines("unknown.weirdext", src)
26 if len(lines) != 3 {
27 t.Fatalf("plain fallback produced %d lines; want 3", len(lines))
28 }
29 for i, want := range []string{"first line", "second line", "third"} {
30 if string(lines[i]) != want {
31 t.Errorf("line %d = %q; want %q", i+1, string(lines[i]), want)
32 }
33 }
34 }
35
36 func TestRenderLinesEscapesPlainText(t *testing.T) {
37 lines := RenderLines("unknown.weirdext", "a < b & c > d")
38 if len(lines) != 1 {
39 t.Fatalf("got %d lines; want 1", len(lines))
40 }
41 got := string(lines[0])
42 for _, want := range []string{"&lt;", "&amp;", "&gt;"} {
43 if !strings.Contains(got, want) {
44 t.Errorf("plain output %q missing escape %q", got, want)
45 }
46 }
47 }
48
49 func TestRenderLinesBridgesMultiLineToken(t *testing.T) {
50 // Python triple-quoted string spans 3 lines; chroma emits a single
51 // <span class="s2">…</span> for the whole literal. The splitter
52 // must close + reopen the span at each line boundary so each row
53 // is independently well-formed.
54 src := "x = '''line one\nline two\nline three'''\n"
55 lines := RenderLines("a.py", src)
56 if len(lines) < 3 {
57 t.Fatalf("got %d lines; want at least 3", len(lines))
58 }
59 // Lines 1, 2, 3 each touch the multi-line string literal; each
60 // should both open and close a span tag.
61 for _, idx := range []int{0, 1, 2} {
62 l := string(lines[idx])
63 opens := strings.Count(l, "<span")
64 closes := strings.Count(l, "</span>")
65 if opens != closes {
66 t.Errorf("line %d: %d <span vs %d </span> — not well-formed: %q",
67 idx+1, opens, closes, l)
68 }
69 }
70 }
71
72 func TestSplitChromaLinesEmptyInput(t *testing.T) {
73 lines := splitChromaLines("")
74 if len(lines) != 1 || lines[0] != "" {
75 t.Fatalf("splitChromaLines(\"\") = %v; want [\"\"]", lines)
76 }
77 }
78
79 func TestSplitChromaLinesNoSpans(t *testing.T) {
80 lines := splitChromaLines("a\nb\nc")
81 if len(lines) != 3 {
82 t.Fatalf("got %d lines; want 3", len(lines))
83 }
84 want := []string{"a", "b", "c"}
85 for i, w := range want {
86 if string(lines[i]) != w {
87 t.Errorf("[%d] = %q; want %q", i, string(lines[i]), w)
88 }
89 }
90 }
91
92 func TestLanguageGuess(t *testing.T) {
93 cases := []struct{ filename, want string }{
94 {"main.go", "Go"},
95 {"app.py", "Python"},
96 {"index.html", "HTML"},
97 {"unknown.weirdext", "Text"},
98 }
99 for _, tc := range cases {
100 if got := LanguageGuess(tc.filename); got != tc.want {
101 t.Errorf("LanguageGuess(%q) = %q; want %q", tc.filename, got, tc.want)
102 }
103 }
104 }
105