422 lines
9.7 KiB
Go
422 lines
9.7 KiB
Go
package services
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing/object"
|
|
)
|
|
|
|
// initTestRepo creates a temp git repo with two commits on main branch.
|
|
// Returns the repo path and the two commit hashes (first, second).
|
|
func initTestRepo(t *testing.T) (string, string, string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
|
|
repo, err := git.PlainInit(dir, false)
|
|
if err != nil {
|
|
t.Fatalf("PlainInit: %v", err)
|
|
}
|
|
|
|
w, err := repo.Worktree()
|
|
if err != nil {
|
|
t.Fatalf("Worktree: %v", err)
|
|
}
|
|
|
|
// Commit 1: create file
|
|
filePath := filepath.Join(dir, "hello.txt")
|
|
if err := os.WriteFile(filePath, []byte("hello world\n"), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
w.Add("hello.txt")
|
|
|
|
hash1, err := w.Commit("initial commit", &git.CommitOptions{
|
|
Author: &object.Signature{
|
|
Name: "Test",
|
|
Email: "test@example.com",
|
|
When: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Commit 1: %v", err)
|
|
}
|
|
|
|
// Commit 2: modify file
|
|
if err := os.WriteFile(filePath, []byte("hello world\nmodified\n"), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
w.Add("hello.txt")
|
|
|
|
hash2, err := w.Commit("second commit", &git.CommitOptions{
|
|
Author: &object.Signature{
|
|
Name: "Test",
|
|
Email: "test@example.com",
|
|
When: time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Commit 2: %v", err)
|
|
}
|
|
|
|
return dir, hash1.String(), hash2.String()
|
|
}
|
|
|
|
func TestOpenRepo(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo() error: %v", err)
|
|
}
|
|
if repo == nil {
|
|
t.Fatal("OpenRepo() returned nil repo")
|
|
}
|
|
}
|
|
|
|
func TestOpenRepo_InvalidPath(t *testing.T) {
|
|
_, err := OpenRepo("/nonexistent/path/12345")
|
|
if err == nil {
|
|
t.Error("OpenRepo() expected error for invalid path")
|
|
}
|
|
}
|
|
|
|
func TestGetRefs(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
refs, err := GetRefs(repo)
|
|
if err != nil {
|
|
t.Fatalf("GetRefs() error: %v", err)
|
|
}
|
|
|
|
// Should have at least one branch (main or master depending on git config)
|
|
found := false
|
|
for _, r := range refs {
|
|
if (r.Name == "main" || r.Name == "master") && !r.IsTag {
|
|
found = true
|
|
if r.Hash == "" {
|
|
t.Error("branch ref has empty hash")
|
|
}
|
|
if !r.IsHead {
|
|
t.Error("default branch should be HEAD")
|
|
}
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("expected default branch in refs, got %v", refs)
|
|
}
|
|
}
|
|
|
|
func TestGetGraph(t *testing.T) {
|
|
dir, hash1, hash2 := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
graph, err := GetGraph(repo, 100)
|
|
if err != nil {
|
|
t.Fatalf("GetGraph() error: %v", err)
|
|
}
|
|
|
|
if len(graph.Commits) != 2 {
|
|
t.Fatalf("commits count = %d, want 2", len(graph.Commits))
|
|
}
|
|
|
|
// The first commit in the graph should be the latest (hash2)
|
|
if graph.Commits[0].Hash != hash2 {
|
|
t.Errorf("commits[0].Hash = %q, want %q", graph.Commits[0].Hash, hash2)
|
|
}
|
|
if graph.Commits[0].Message != "second commit" {
|
|
t.Errorf("commits[0].Message = %q, want %q", graph.Commits[0].Message, "second commit")
|
|
}
|
|
|
|
// Second should be hash1
|
|
if graph.Commits[1].Hash != hash1 {
|
|
t.Errorf("commits[1].Hash = %q, want %q", graph.Commits[1].Hash, hash1)
|
|
}
|
|
|
|
// Should have one edge (hash2 -> hash1)
|
|
if len(graph.Edges) != 1 {
|
|
t.Fatalf("edges count = %d, want 1", len(graph.Edges))
|
|
}
|
|
if graph.Edges[0].Source != hash2 || graph.Edges[0].Target != hash1 {
|
|
t.Errorf("edge = {%s -> %s}, want {%s -> %s}",
|
|
graph.Edges[0].Source, graph.Edges[0].Target, hash2, hash1)
|
|
}
|
|
|
|
// Should have at least one ref
|
|
if len(graph.Refs) < 1 {
|
|
t.Error("expected at least 1 ref in graph")
|
|
}
|
|
}
|
|
|
|
func TestGetGraph_MaxCommits(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
graph, err := GetGraph(repo, 1) // limit to 1 commit
|
|
if err != nil {
|
|
t.Fatalf("GetGraph() error: %v", err)
|
|
}
|
|
|
|
if len(graph.Commits) != 1 {
|
|
t.Errorf("commits count = %d, want 1", len(graph.Commits))
|
|
}
|
|
}
|
|
|
|
func TestGetDiff(t *testing.T) {
|
|
dir, hash1, hash2 := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
diff, err := GetDiff(repo, hash1, hash2)
|
|
if err != nil {
|
|
t.Fatalf("GetDiff() error: %v", err)
|
|
}
|
|
|
|
if diff == "" {
|
|
t.Error("expected non-empty diff")
|
|
}
|
|
// The diff should contain the added line
|
|
if !contains(diff, "modified") {
|
|
t.Errorf("diff should contain 'modified', got: %s", diff)
|
|
}
|
|
}
|
|
|
|
func TestGetDiffFiles(t *testing.T) {
|
|
dir, hash1, hash2 := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
files, err := GetDiffFiles(repo, hash1, hash2)
|
|
if err != nil {
|
|
t.Fatalf("GetDiffFiles() error: %v", err)
|
|
}
|
|
|
|
if len(files) != 1 {
|
|
t.Fatalf("files count = %d, want 1", len(files))
|
|
}
|
|
if files[0].Filename != "hello.txt" {
|
|
t.Errorf("filename = %q, want %q", files[0].Filename, "hello.txt")
|
|
}
|
|
if files[0].Patch == "" {
|
|
t.Error("expected non-empty patch")
|
|
}
|
|
}
|
|
|
|
func TestGetCommitLog(t *testing.T) {
|
|
dir, hash1, hash2 := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
commits, err := GetCommitLog(repo, "HEAD", 100)
|
|
if err != nil {
|
|
t.Fatalf("GetCommitLog() error: %v", err)
|
|
}
|
|
|
|
if len(commits) != 2 {
|
|
t.Fatalf("commits count = %d, want 2", len(commits))
|
|
}
|
|
|
|
// First commit should be the latest
|
|
if commits[0].Hash != hash2 {
|
|
t.Errorf("commits[0].Hash = %q, want %q", commits[0].Hash, hash2)
|
|
}
|
|
if commits[0].Author != "Test" {
|
|
t.Errorf("commits[0].Author = %q, want %q", commits[0].Author, "Test")
|
|
}
|
|
if commits[0].Email != "test@example.com" {
|
|
t.Errorf("commits[0].Email = %q, want %q", commits[0].Email, "test@example.com")
|
|
}
|
|
|
|
if commits[1].Hash != hash1 {
|
|
t.Errorf("commits[1].Hash = %q, want %q", commits[1].Hash, hash1)
|
|
}
|
|
}
|
|
|
|
func TestGetCommitLog_Limit(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
repo, err := OpenRepo(dir)
|
|
if err != nil {
|
|
t.Fatalf("OpenRepo: %v", err)
|
|
}
|
|
|
|
commits, err := GetCommitLog(repo, "HEAD", 1)
|
|
if err != nil {
|
|
t.Fatalf("GetCommitLog() error: %v", err)
|
|
}
|
|
|
|
if len(commits) != 1 {
|
|
t.Errorf("commits count = %d, want 1", len(commits))
|
|
}
|
|
}
|
|
|
|
func TestGetDefaultBranch(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
|
|
branch, err := GetDefaultBranch(dir)
|
|
if err != nil {
|
|
t.Fatalf("GetDefaultBranch() error: %v", err)
|
|
}
|
|
|
|
if branch != "main" && branch != "master" {
|
|
t.Errorf("GetDefaultBranch() = %q, want %q or %q", branch, "main", "master")
|
|
}
|
|
}
|
|
|
|
func TestGetDefaultBranch_InvalidPath(t *testing.T) {
|
|
_, err := GetDefaultBranch("/nonexistent/path/12345")
|
|
if err == nil {
|
|
t.Error("expected error for invalid path")
|
|
}
|
|
}
|
|
|
|
func TestGetRepoBranches(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
|
|
branches, err := GetRepoBranches(dir)
|
|
if err != nil {
|
|
t.Fatalf("GetRepoBranches() error: %v", err)
|
|
}
|
|
|
|
found := false
|
|
for _, b := range branches {
|
|
if b == "main" || b == "master" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("expected default branch in branches, got %v", branches)
|
|
}
|
|
}
|
|
|
|
func TestGetRepoTags(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
|
|
tags, err := GetRepoTags(dir)
|
|
if err != nil {
|
|
t.Fatalf("GetRepoTags() error: %v", err)
|
|
}
|
|
|
|
// No tags were created, should be empty
|
|
if len(tags) != 0 {
|
|
t.Errorf("expected 0 tags, got %v", tags)
|
|
}
|
|
}
|
|
|
|
func TestDirSize(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create files with known sizes
|
|
os.WriteFile(filepath.Join(tmpDir, "a.txt"), make([]byte, 100), 0o644)
|
|
os.WriteFile(filepath.Join(tmpDir, "b.txt"), make([]byte, 200), 0o644)
|
|
|
|
size := dirSize(tmpDir)
|
|
if size < 300 {
|
|
t.Errorf("dirSize() = %d, want >= 300", size)
|
|
}
|
|
}
|
|
|
|
func TestDirSize_Empty(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
size := dirSize(tmpDir)
|
|
if size != 0 {
|
|
t.Errorf("dirSize() = %d, want 0", size)
|
|
}
|
|
}
|
|
|
|
func TestDirSize_Nonexistent(t *testing.T) {
|
|
size := dirSize("/nonexistent/path/12345")
|
|
if size != 0 {
|
|
t.Errorf("dirSize() = %d, want 0", size)
|
|
}
|
|
}
|
|
|
|
func TestDirSize_NestedFiles(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
subDir := filepath.Join(tmpDir, "sub")
|
|
os.MkdirAll(subDir, 0o755)
|
|
os.WriteFile(filepath.Join(tmpDir, "root.txt"), make([]byte, 50), 0o644)
|
|
os.WriteFile(filepath.Join(subDir, "nested.txt"), make([]byte, 75), 0o644)
|
|
|
|
size := dirSize(tmpDir)
|
|
if size < 125 {
|
|
t.Errorf("dirSize() = %d, want >= 125", size)
|
|
}
|
|
}
|
|
|
|
func TestCompareCommits(t *testing.T) {
|
|
dir, hash1, hash2 := initTestRepo(t)
|
|
|
|
diff, err := CompareCommits(dir, hash1, hash2)
|
|
if err != nil {
|
|
t.Fatalf("CompareCommits() error: %v", err)
|
|
}
|
|
if diff == "" {
|
|
t.Error("expected non-empty diff")
|
|
}
|
|
}
|
|
|
|
func TestCompareCommitsFiles(t *testing.T) {
|
|
dir, hash1, hash2 := initTestRepo(t)
|
|
|
|
files, err := CompareCommitsFiles(dir, hash1, hash2)
|
|
if err != nil {
|
|
t.Fatalf("CompareCommitsFiles() error: %v", err)
|
|
}
|
|
if len(files) != 1 {
|
|
t.Fatalf("files count = %d, want 1", len(files))
|
|
}
|
|
if files[0].Filename != "hello.txt" {
|
|
t.Errorf("filename = %q, want %q", files[0].Filename, "hello.txt")
|
|
}
|
|
}
|
|
|
|
func TestGetBranchCommits(t *testing.T) {
|
|
dir, _, _ := initTestRepo(t)
|
|
|
|
// Use the actual default branch name (main or master depending on git config)
|
|
branch, err := GetDefaultBranch(dir)
|
|
if err != nil {
|
|
t.Fatalf("GetDefaultBranch: %v", err)
|
|
}
|
|
|
|
commits, err := GetBranchCommits(dir, branch, 100)
|
|
if err != nil {
|
|
t.Fatalf("GetBranchCommits() error: %v", err)
|
|
}
|
|
if len(commits) != 2 {
|
|
t.Errorf("commits count = %d, want 2", len(commits))
|
|
}
|
|
}
|
|
|
|
// contains is a simple helper to check substring presence.
|
|
func contains(s, substr string) bool {
|
|
return len(s) >= len(substr) && searchString(s, substr)
|
|
}
|
|
|
|
func searchString(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|