package git import ( "testing" "github.com/bluekeyes/go-gitdiff/gitdiff" "olexsmir.xyz/x/is" ) func TestRepo_Diff(t *testing.T) { t.Run("single file addition", func(t *testing.T) { r := newTestRepo(t) r.commitFile("README.md", "# Test", "Initial commit") r.commitFile("hello.txt", "hello world\n", "Add hello file") diff, err := r.open().Diff() is.Err(t, err, nil) is.Equal(t, diff.Stat.FilesChanged, 1) is.Equal(t, diff.Stat.Insertions, 1) is.Equal(t, diff.Stat.Deletions, 0) is.Equal(t, len(diff.Diff), 1) is.Equal(t, diff.Diff[0].Name.New, "hello.txt") is.Equal(t, diff.Diff[0].IsNew, true) }) t.Run("file modification", func(t *testing.T) { r := newTestRepo(t) r.commitFile("README.md", "# Original\n", "Initial commit") r.commitFile("README.md", "# Modified\n\nNew content here.\n", "Update README") diff, err := r.open().Diff() is.Err(t, err, nil) is.Equal(t, diff.Stat.FilesChanged, 1) is.Equal(t, diff.Diff[0].Name.New, "README.md") is.Equal(t, diff.Diff[0].IsNew, false) is.Equal(t, diff.Diff[0].IsDelete, false) if diff.Stat.Insertions == 0 { t.Error("expected insertions > 0") } if diff.Stat.Deletions == 0 { t.Error("expected deletions > 0") } }) t.Run("file deletion", func(t *testing.T) { r := newTestRepo(t) r.commitFile("todelete.txt", "temp content\n", "Add temp file") r.deleteFile("todelete.txt", "Delete temp file") diff, err := r.open().Diff() is.Err(t, err, nil) is.Equal(t, diff.Stat.FilesChanged, 1) is.Equal(t, diff.Stat.Deletions, 1) is.Equal(t, diff.Diff[0].IsDelete, true) }) t.Run("multiple files changed", func(t *testing.T) { r := newTestRepo(t) r.commitFile("file1.txt", "content 1\n", "Add file1") r.commitFile("file2.txt", "content 2\n", "Add file2") r.commitFile("file3.txt", "content 3\n", "Add file3") diff, err := r.open().Diff() is.Err(t, err, nil) is.Equal(t, diff.Stat.FilesChanged, 1) is.Equal(t, diff.Stat.Insertions, 1) }) t.Run("has parent hashes", func(t *testing.T) { r := newTestRepo(t) r.commitFile("first.txt", "first\n", "First commit") r.commitFile("second.txt", "second file\n", "Add second file") diff, err := r.open().Diff() is.Err(t, err, nil) is.Equal(t, len(diff.Parents), 1) if len(diff.Parents[0]) == 0 { t.Error("expected parent hash to be non-empty") } }) t.Run("initial commit has no parents", func(t *testing.T) { r := newTestRepo(t) r.commitFile("initial.txt", "initial\n", "Initial commit") commits, err := r.open().Commits("") is.Err(t, err, nil) if len(commits) == 0 { t.Fatal("expected at least one commit") } initial := r.open(commits[len(commits)-1].Hash) diff, err := initial.Diff() is.Equal(t, len(diff.Parents), 0) is.Err(t, err, nil) }) t.Run("text fragments have line info", func(t *testing.T) { r := newTestRepo(t) r.commitFile("README.md", "original\n", "Initial commit") r.commitFile("README.md", "line 1\nline 2\nline 3\n", "Multi-line change") diff, err := r.open().Diff() is.Err(t, err, nil) if len(diff.Diff) == 0 { t.Fatal("expected at least one diff") } if len(diff.Diff[0].TextFragments) == 0 { t.Fatal("expected at least one text fragment") } frag := diff.Diff[0].TextFragments[0] if len(frag.Lines) == 0 { t.Fatal("expected at least one line") } // Check that lines have operations hasAdd := false for _, line := range frag.Lines { if line.Op == gitdiff.OpAdd { hasAdd = true } } if !hasAdd { t.Error("expected at least one added line") } }) t.Run("commit info is populated", func(t *testing.T) { r := newTestRepo(t) r.commitFile("info.txt", "test\n", "Test commit message") diff, err := r.open().Diff() is.Err(t, err, nil) is.Equal(t, diff.Commit.Message, "Test commit message") is.Equal(t, diff.Commit.AuthorName, "Test User") is.Equal(t, diff.Commit.AuthorEmail, "test@test.local") if len(diff.Commit.Hash) == 0 { t.Error("expected commit hash to be non-empty") } }) } func TestTextFragment(t *testing.T) { frag := TextFragment{ Header: "@@ -1,3 +1,4 @@", OldPosition: 1, NewPosition: 1, Lines: []gitdiff.Line{ {Op: gitdiff.OpContext, Line: "context line"}, {Op: gitdiff.OpAdd, Line: "added line"}, }, } is.Equal(t, frag.Header, "@@ -1,3 +1,4 @@") is.Equal(t, frag.OldPosition, int64(1)) is.Equal(t, frag.NewPosition, int64(1)) is.Equal(t, len(frag.Lines), 2) }