diff_test.go

  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}