tenseleyflow/shithub / 9a6efcb

Browse files

highlight: tests for RenderLines + multi-line span bridging

Authored by espadonne
SHA
9a6efcb776972a1542e3ab44ca71c7d8716ee801
Parents
30f2c74
Tree
ae80093

1 changed file

StatusFile+-
A internal/repos/highlight/chroma_test.go 104 0
internal/repos/highlight/chroma_test.goadded
@@ -0,0 +1,104 @@
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
+}