1package diff
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/require"
7)
8
9func TestGenerateDiff(t *testing.T) {
10 t.Parallel()
11
12 before := "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World!\")\n\tfmt.Println(\"Line 2\")\n}\n"
13 after := "package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, Go!\")\n\tfmt.Println(\"Line 2\")\n}\n"
14
15 t.Run("LF_before_LF_after", func(t *testing.T) {
16 t.Parallel()
17
18 diff, additions, removals := GenerateDiff(before, after, "main.go")
19
20 require.Equal(t, 1, additions)
21 require.Equal(t, 1, removals)
22 require.Contains(t, diff, "-\tfmt.Println(\"Hello, World!\")")
23 require.Contains(t, diff, "+\tfmt.Println(\"Hello, Go!\")")
24 })
25
26 t.Run("CRLF_before_LF_after", func(t *testing.T) {
27 t.Parallel()
28
29 crlfBefore := "package main\r\n\r\nimport \"fmt\"\r\n\r\nfunc main() {\r\n\tfmt.Println(\"Hello, World!\")\r\n\tfmt.Println(\"Line 2\")\r\n}\r\n"
30 diff, additions, removals := GenerateDiff(crlfBefore, after, "main.go")
31
32 require.Equal(t, 1, additions, "CRLF before should not inflate counts")
33 require.Equal(t, 1, removals, "CRLF before should not inflate counts")
34 require.Contains(t, diff, "-\tfmt.Println(\"Hello, World!\")")
35 require.Contains(t, diff, "+\tfmt.Println(\"Hello, Go!\")")
36 })
37
38 t.Run("LF_before_CRLF_after", func(t *testing.T) {
39 t.Parallel()
40
41 crlfAfter := "package main\r\n\r\nimport \"fmt\"\r\n\r\nfunc main() {\r\n\tfmt.Println(\"Hello, Go!\")\r\n\tfmt.Println(\"Line 2\")\r\n}\r\n"
42 diff, additions, removals := GenerateDiff(before, crlfAfter, "main.go")
43
44 require.Equal(t, 1, additions, "CRLF after should not inflate counts")
45 require.Equal(t, 1, removals, "CRLF after should not inflate counts")
46 require.Contains(t, diff, "-\tfmt.Println(\"Hello, World!\")")
47 require.Contains(t, diff, "+\tfmt.Println(\"Hello, Go!\")")
48 })
49
50 t.Run("CRLF_before_CRLF_after", func(t *testing.T) {
51 t.Parallel()
52
53 crlfBefore := "package main\r\n\r\nimport \"fmt\"\r\n\r\nfunc main() {\r\n\tfmt.Println(\"Hello, World!\")\r\n\tfmt.Println(\"Line 2\")\r\n}\r\n"
54 crlfAfter := "package main\r\n\r\nimport \"fmt\"\r\n\r\nfunc main() {\r\n\tfmt.Println(\"Hello, Go!\")\r\n\tfmt.Println(\"Line 2\")\r\n}\r\n"
55 diff, additions, removals := GenerateDiff(crlfBefore, crlfAfter, "main.go")
56
57 require.Equal(t, 1, additions)
58 require.Equal(t, 1, removals)
59 require.Contains(t, diff, "-\tfmt.Println(\"Hello, World!\")")
60 require.Contains(t, diff, "+\tfmt.Println(\"Hello, Go!\")")
61 })
62
63 t.Run("mixed_line_endings", func(t *testing.T) {
64 t.Parallel()
65
66 mixedBefore := "line1\r\nline2\nline3\r\nline4\n"
67 mixedAfter := "line1\nline2\nchanged\nline4\n"
68 diff, additions, removals := GenerateDiff(mixedBefore, mixedAfter, "test.txt")
69
70 require.Equal(t, 1, additions)
71 require.Equal(t, 1, removals)
72 require.Contains(t, diff, "-line3")
73 require.Contains(t, diff, "+changed")
74 })
75
76 t.Run("identical_content_different_endings", func(t *testing.T) {
77 t.Parallel()
78
79 lfContent := "line1\nline2\nline3\n"
80 crlfContent := "line1\r\nline2\r\nline3\r\n"
81 diff, additions, removals := GenerateDiff(lfContent, crlfContent, "test.txt")
82
83 require.Equal(t, 0, additions, "identical content with different line endings should produce no diff")
84 require.Equal(t, 0, removals, "identical content with different line endings should produce no diff")
85 require.Empty(t, diff)
86 })
87
88 t.Run("tabs_are_not_normalized", func(t *testing.T) {
89 t.Parallel()
90
91 tabContent := "\tfoo\n"
92 spaceContent := " foo\n"
93 diff, additions, removals := GenerateDiff(tabContent, spaceContent, "test.txt")
94
95 require.Equal(t, 1, additions, "tab vs space should be a real diff")
96 require.Equal(t, 1, removals, "tab vs space should be a real diff")
97 require.NotEmpty(t, diff)
98 })
99
100 t.Run("empty_before", func(t *testing.T) {
101 t.Parallel()
102
103 diff, additions, removals := GenerateDiff("", "line1\nline2\n", "new.txt")
104
105 require.Equal(t, 2, additions)
106 require.Equal(t, 0, removals)
107 require.Contains(t, diff, "+line1")
108 require.Contains(t, diff, "+line2")
109 })
110
111 t.Run("empty_after", func(t *testing.T) {
112 t.Parallel()
113
114 diff, additions, removals := GenerateDiff("line1\nline2\n", "", "deleted.txt")
115
116 require.Equal(t, 0, additions)
117 require.Equal(t, 2, removals)
118 require.Contains(t, diff, "-line1")
119 require.Contains(t, diff, "-line2")
120 })
121
122 t.Run("leading_slash_trimmed", func(t *testing.T) {
123 t.Parallel()
124
125 diff, _, _ := GenerateDiff("a\n", "b\n", "/src/main.go")
126
127 require.Contains(t, diff, "a/src/main.go")
128 require.Contains(t, diff, "b/src/main.go")
129 require.NotContains(t, diff, "a//src/main.go")
130 })
131}