main diff_render_test.go
Eric Bower  ·  2026-09-14
  1package main
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"github.com/alecthomas/chroma/v2/styles"
  8	git "github.com/gogs/git-module"
  9)
 10
 11func TestFormatDiffHunkGo(t *testing.T) {
 12	section := &git.DiffSection{
 13		Lines: []*git.DiffLine{
 14			{Type: git.DiffLineSection, Content: "@@ -1,5 +1,6 @@"},
 15			{Type: git.DiffLinePlain, Content: " package main", LeftLine: 1, RightLine: 1},
 16			{Type: git.DiffLinePlain, Content: " ", LeftLine: 2, RightLine: 2},
 17			{Type: git.DiffLineDelete, Content: "-func OldFunction() int {", LeftLine: 3},
 18			{Type: git.DiffLineAdd, Content: "+func NewFunction() string {", RightLine: 3},
 19			{Type: git.DiffLineAdd, Content: "+\t// added comment", RightLine: 4},
 20			{Type: git.DiffLinePlain, Content: " \treturn 42", LeftLine: 4, RightLine: 5},
 21			{Type: git.DiffLinePlain, Content: " }", LeftLine: 5, RightLine: 6},
 22		},
 23	}
 24
 25	theme := styles.Get("dracula")
 26	anchor := "diff-main.go-hunk-0"
 27	htmlOut, err := FormatDiffHunk(theme, "main.go", section, anchor)
 28	if err != nil {
 29		t.Fatalf("FormatDiffHunk: %v", err)
 30	}
 31
 32	// Verify table structure
 33	if !strings.Contains(htmlOut, "diff-table") {
 34		t.Errorf("expected diff-table class in output")
 35	}
 36	if !strings.Contains(htmlOut, "diff-line-hunk") {
 37		t.Errorf("expected diff-line-hunk class in output")
 38	}
 39
 40	// Verify line number and diff overlays
 41	if !strings.Contains(htmlOut, "diff-line-add") {
 42		t.Errorf("expected diff-line-add class in output")
 43	}
 44	if !strings.Contains(htmlOut, "diff-line-delete") {
 45		t.Errorf("expected diff-line-delete class in output")
 46	}
 47	if !strings.Contains(htmlOut, "diff-line-context") {
 48		t.Errorf("expected diff-line-context class in output")
 49	}
 50
 51	// Verify gutter markers
 52	if !strings.Contains(htmlOut, "<td class=\"diff-gutter\">+</td>") {
 53		t.Errorf("expected '+' in gutter")
 54	}
 55	if !strings.Contains(htmlOut, "<td class=\"diff-gutter\">-</td>") {
 56		t.Errorf("expected '-' in gutter")
 57	}
 58
 59	// Verify anchor links in line numbers
 60	if !strings.Contains(htmlOut, `id="diff-main.go-hunk-0-L3"`) {
 61		t.Errorf("expected deleted line anchor id in output, got:\n%s", htmlOut)
 62	}
 63	if !strings.Contains(htmlOut, `href="#diff-main.go-hunk-0-L3"`) {
 64		t.Errorf("expected deleted line anchor href in output, got:\n%s", htmlOut)
 65	}
 66	if !strings.Contains(htmlOut, `id="diff-main.go-hunk-0-R3"`) {
 67		t.Errorf("expected added line anchor id in output, got:\n%s", htmlOut)
 68	}
 69	if !strings.Contains(htmlOut, `href="#diff-main.go-hunk-0-R3"`) {
 70		t.Errorf("expected added line anchor href in output, got:\n%s", htmlOut)
 71	}
 72
 73	// Verify syntax highlighting (Chroma classes for Go keywords / comments)
 74	if !strings.Contains(htmlOut, "class=\"kd\"") && !strings.Contains(htmlOut, "class=\"k\"") {
 75		t.Errorf("expected keyword chroma class (kd or k) for 'func' or 'package', got:\n%s", htmlOut)
 76	}
 77	if !strings.Contains(htmlOut, "class=\"c1\"") && !strings.Contains(htmlOut, "class=\"c\"") {
 78		t.Errorf("expected comment chroma class (c1 or c) for '// added comment', got:\n%s", htmlOut)
 79	}
 80}
 81
 82func TestFormatDiffHunkZig(t *testing.T) {
 83	section := &git.DiffSection{
 84		Lines: []*git.DiffLine{
 85			{Type: git.DiffLineSection, Content: "@@ -1,4 +1,5 @@"},
 86			{Type: git.DiffLinePlain, Content: " const std = @import(\"std\");", LeftLine: 1, RightLine: 1},
 87			{Type: git.DiffLinePlain, Content: " ", LeftLine: 2, RightLine: 2},
 88			{Type: git.DiffLineDelete, Content: "-pub fn main() void {", LeftLine: 3},
 89			{Type: git.DiffLineAdd, Content: "+pub fn main() !void {", RightLine: 3},
 90			{Type: git.DiffLineAdd, Content: "+    // zig comment", RightLine: 4},
 91			{Type: git.DiffLinePlain, Content: " }", LeftLine: 4, RightLine: 5},
 92		},
 93	}
 94
 95	htmlOut, err := FormatDiffHunk(nil, "src/main.zig", section, "diff-main.zig-hunk-0")
 96	if err != nil {
 97		t.Fatalf("FormatDiffHunk: %v", err)
 98	}
 99
100	// Verify Zig syntax highlighting tokens
101	if !strings.Contains(htmlOut, "class=\"k\"") && !strings.Contains(htmlOut, "class=\"kd\"") {
102		t.Errorf("expected keyword class for 'pub' or 'fn' or 'const', got:\n%s", htmlOut)
103	}
104	if !strings.Contains(htmlOut, "diff-line-add") {
105		t.Errorf("expected diff-line-add in zig diff")
106	}
107	if !strings.Contains(htmlOut, `href="#diff-main.zig-hunk-0-R3"`) {
108		t.Errorf("expected anchor link in zig diff, got:\n%s", htmlOut)
109	}
110}
111
112func TestFormatDiffHunkFallback(t *testing.T) {
113	section := &git.DiffSection{
114		Lines: []*git.DiffLine{
115			{Type: git.DiffLineSection, Content: "@@ -1,2 +1,2 @@"},
116			{Type: git.DiffLineDelete, Content: "-foo", LeftLine: 1},
117			{Type: git.DiffLineAdd, Content: "+bar", RightLine: 1},
118		},
119	}
120
121	// Unknown extension should not error and still render diff table correctly
122	htmlOut, err := FormatDiffHunk(nil, "unknown.xyz", section, "")
123	if err != nil {
124		t.Fatalf("FormatDiffHunk: %v", err)
125	}
126
127	if !strings.Contains(htmlOut, "diff-table") {
128		t.Errorf("expected diff-table class in output")
129	}
130	if !strings.Contains(htmlOut, "diff-line-add") {
131		t.Errorf("expected diff-line-add in unknown file diff")
132	}
133}
134
135func TestFormatDiffFile(t *testing.T) {
136	file := &git.DiffFile{
137		Name: "test.go",
138		Sections: []*git.DiffSection{
139			{
140				Lines: []*git.DiffLine{
141					{Type: git.DiffLineSection, Content: "@@ -1,2 +1,2 @@"},
142					{Type: git.DiffLineDelete, Content: "-package old", LeftLine: 1},
143					{Type: git.DiffLineAdd, Content: "+package new", RightLine: 1},
144				},
145			},
146		},
147	}
148
149	htmlOut, err := FormatDiffFile(nil, file)
150	if err != nil {
151		t.Fatalf("FormatDiffFile: %v", err)
152	}
153
154	if !strings.Contains(htmlOut, "diff-test.go-hunk-0") {
155		t.Errorf("expected hunk anchor in file diff")
156	}
157	if !strings.Contains(htmlOut, "diff-line-add") {
158		t.Errorf("expected diff-line-add")
159	}
160}