diff options
| author | 2026-02-20 19:06:13 +0800 | |
|---|---|---|
| committer | 2026-02-20 19:07:14 +0800 | |
| commit | aa513c069c1418734aea894dc944e27c6a78a3bb (patch) | |
| tree | 687f0a11bb550fa088fd82a98ceb8979bbc35f69 /refs_test.go | |
| parent | Comment on prior reverts removing the pack writing API (diff) | |
| signature | No signature | |
Delete everything, I'm redesigning this.
I'll stop using a flat package and make things much more modular.
And also experiment with streaming APIs so large blobs don't OOM us.
Diffstat (limited to 'refs_test.go')
| -rw-r--r-- | refs_test.go | 520 |
1 files changed, 0 insertions, 520 deletions
diff --git a/refs_test.go b/refs_test.go deleted file mode 100644 index 2d4a1532..00000000 --- a/refs_test.go +++ /dev/null @@ -1,520 +0,0 @@ -package furgit - -import ( - "os" - "path/filepath" - "strings" - "testing" -) - -func TestResolveRef(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - err := os.WriteFile(filepath.Join(workDir, "test.txt"), []byte("content"), 0o644) - if err != nil { - t.Fatalf("Failed to write test.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "test") - commitHash := gitCmd(t, repoPath, "rev-parse", "HEAD") - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commitHash) - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - hashObj, _ := repo.ParseHash(commitHash) - resolved, err := repo.ResolveRef("refs/heads/main") - if err != nil { - t.Fatalf("ResolveRef failed: %v", err) - } - - if resolved.Kind != RefKindDetached { - t.Fatalf("expected detached ref, got %v", resolved.Kind) - } - if resolved.Hash != hashObj { - t.Errorf("resolved hash: got %s, want %s", resolved.Hash, hashObj) - } - - gitRevParse := gitCmd(t, repoPath, "rev-parse", "refs/heads/main") - if resolved.Hash.String() != gitRevParse { - t.Errorf("furgit resolved %s, git resolved %s", resolved.Hash, gitRevParse) - } - - _, err = repo.ResolveRef("refs/heads/nonexistent") - if err == nil { - t.Error("expected error for nonexistent ref") - } -} - -func TestResolveHEAD(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - err := os.WriteFile(filepath.Join(workDir, "test.txt"), []byte("content"), 0o644) - if err != nil { - t.Fatalf("failed to write test.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "test") - commitHash := gitCmd(t, repoPath, "rev-parse", "HEAD") - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commitHash) - gitCmd(t, repoPath, "symbolic-ref", "HEAD", "refs/heads/main") - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - ref, err := repo.ResolveRef("HEAD") - if err != nil { - t.Fatalf("ResolveRef(HEAD) failed: %v", err) - } - - if ref.Kind != RefKindSymbolic { - t.Fatalf("HEAD kind: got %v, want %v", ref.Kind, RefKindSymbolic) - } - - if ref.Ref != "refs/heads/main" { - t.Errorf("HEAD symbolic ref: got %q, want %q", ref.Ref, "refs/heads/main") - } - - gitSymRef := gitCmd(t, repoPath, "symbolic-ref", "HEAD") - if ref.Ref != gitSymRef { - t.Errorf("furgit resolved %v, git resolved %s", ref.Ref, gitSymRef) - } -} - -func TestPackedRefs(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - err := os.WriteFile(filepath.Join(workDir, "test.txt"), []byte("content1"), 0o644) - if err != nil { - t.Fatalf("failed to write test.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "commit1") - commit1Hash := gitCmd(t, repoPath, "rev-parse", "HEAD") - - err = os.WriteFile(filepath.Join(workDir, "test2.txt"), []byte("content2"), 0o644) - if err != nil { - t.Fatalf("failed to write test2.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "commit2") - commit2Hash := gitCmd(t, repoPath, "rev-parse", "HEAD") - - gitCmd(t, repoPath, "update-ref", "refs/heads/branch1", commit1Hash) - gitCmd(t, repoPath, "update-ref", "refs/heads/branch2", commit2Hash) - gitCmd(t, repoPath, "update-ref", "refs/tags/v1.0", commit1Hash) - - gitCmd(t, repoPath, "pack-refs", "--all") - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - hash1, _ := repo.ParseHash(commit1Hash) - hash2, _ := repo.ParseHash(commit2Hash) - - resolved1, err := repo.ResolveRef("refs/heads/branch1") - if err != nil { - t.Fatalf("ResolveRef branch1 failed: %v", err) - } - if resolved1.Kind != RefKindDetached || resolved1.Hash != hash1 { - t.Errorf("branch1: got %s, want %s", resolved1.Hash, hash1) - } - - gitResolved1 := gitCmd(t, repoPath, "rev-parse", "refs/heads/branch1") - if resolved1.Hash.String() != gitResolved1 { - t.Errorf("furgit resolved %s, git resolved %s", resolved1.Hash, gitResolved1) - } - - resolved2, err := repo.ResolveRef("refs/heads/branch2") - if err != nil { - t.Fatalf("ResolveRef branch2 failed: %v", err) - } - if resolved2.Kind != RefKindDetached || resolved2.Hash != hash2 { - t.Errorf("branch2: got %s, want %s", resolved2.Hash, hash2) - } - - resolvedTag, err := repo.ResolveRef("refs/tags/v1.0") - if err != nil { - t.Fatalf("ResolveRef tag failed: %v", err) - } - if resolvedTag.Kind != RefKindDetached || resolvedTag.Hash != hash1 { - t.Errorf("tag: got %s, want %s", resolvedTag.Hash, hash1) - } -} - -func TestResolveRefFully(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - // Create an initial commit - err := os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("content"), 0o644) - if err != nil { - t.Fatalf("failed to write file.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "init") - commit := gitCmd(t, repoPath, "rev-parse", "HEAD") - - // Create two layers of symbolic refs - gitCmd(t, repoPath, "symbolic-ref", "refs/heads/level1", "refs/heads/level2") - gitCmd(t, repoPath, "symbolic-ref", "refs/heads/level2", "refs/heads/main") - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commit) - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - commitHash, err := repo.ParseHash(commit) - if err != nil { - t.Fatalf("ParseHash failed: %v", err) - } - - resolved, err := repo.ResolveRefFully("refs/heads/level1") - if err != nil { - t.Fatalf("ResolveRefFully failed: %v", err) - } - - if resolved.Hash != commitHash { - t.Errorf("ResolveRefFully: got hash %s, want %s", resolved.Hash, commitHash) - } -} - -func TestResolveRefFullySymbolicCycle(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - gitCmd(t, repoPath, "symbolic-ref", "refs/heads/A", "refs/heads/B") - gitCmd(t, repoPath, "symbolic-ref", "refs/heads/B", "refs/heads/A") - - _, err = repo.ResolveRefFully("refs/heads/A") - if err == nil { - t.Fatalf("ResolveRefFully should fail on a symbolic cycle") - } - - if !strings.Contains(err.Error(), "cycle") { - t.Fatalf("unexpected error for symbolic cycle: %v", err) - } -} - -func TestResolveRefHashInput(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - err := os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("content"), 0o644) - if err != nil { - t.Fatalf("failed to write file.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "init") - - commitHash := gitCmd(t, repoPath, "rev-parse", "HEAD") - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - hashObj, err := repo.ParseHash(commitHash) - if err != nil { - t.Fatalf("ParseHash failed: %v", err) - } - - ref, err := repo.ResolveRef(commitHash) - if err != nil { - t.Fatalf("ResolveRef(hash) failed: %v", err) - } - if ref.Kind != RefKindDetached { - t.Fatalf("expected RefKindDetached, got %v", ref.Kind) - } - if ref.Hash != hashObj { - t.Fatalf("hash mismatch: got %s, want %s", ref.Hash, hashObj) - } - - hashRef, err := repo.ResolveRefFully(commitHash) - if err != nil { - t.Fatalf("ResolveRefFully(hash) failed: %v", err) - } - if hashRef.Hash != hashObj { - t.Fatalf("hash mismatch: got %s, want %s", hashRef.Hash, hashObj) - } - - _, err = repo.ResolveRef("this_is_not_a_hash") - if err == nil { - t.Fatalf("expected error for invalid hash input") - } -} - -func TestListRefsLooseOverridesPacked(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - gitCmd(t, repoPath, "symbolic-ref", "HEAD", "refs/heads/main") - - err := os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("one"), 0o644) - if err != nil { - t.Fatalf("failed to write file.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "c1") - commit1 := gitCmd(t, repoPath, "rev-parse", "HEAD") - - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commit1) - gitCmd(t, repoPath, "update-ref", "refs/heads/feature", commit1) - gitCmd(t, repoPath, "pack-refs", "--all", "--prune") - - err = os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("two"), 0o644) - if err != nil { - t.Fatalf("failed to write file.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "c2") - commit2 := gitCmd(t, repoPath, "rev-parse", "HEAD") - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commit2) - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - hash1, _ := repo.ParseHash(commit1) - hash2, _ := repo.ParseHash(commit2) - - refs, err := repo.ListRefs("refs/heads/*") - if err != nil { - t.Fatalf("ListRefs failed: %v", err) - } - - if len(refs) != 2 { - t.Fatalf("expected 2 refs, got %d", len(refs)) - } - - got := make(map[string]Ref, len(refs)) - for _, r := range refs { - if _, exists := got[r.Name]; exists { - t.Fatalf("duplicate ref %q in results", r.Name) - } - got[r.Name] = r - } - - mainRef, ok := got["refs/heads/main"] - if !ok { - t.Fatalf("missing refs/heads/main in results") - } - if mainRef.Kind != RefKindDetached || mainRef.Hash != hash2 { - t.Fatalf("refs/heads/main hash: got %s (kind %v), want %s", mainRef.Hash, mainRef.Kind, hash2) - } - - featureRef, ok := got["refs/heads/feature"] - if !ok { - t.Fatalf("missing refs/heads/feature in results") - } - if featureRef.Kind != RefKindDetached || featureRef.Hash != hash1 { - t.Fatalf("refs/heads/feature hash: got %s (kind %v), want %s", featureRef.Hash, featureRef.Kind, hash1) - } -} - -func TestListRefsPatternFiltering(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - gitCmd(t, repoPath, "symbolic-ref", "HEAD", "refs/heads/main") - - err := os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("one"), 0o644) - if err != nil { - t.Fatalf("failed to write file.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "c1") - commit1 := gitCmd(t, repoPath, "rev-parse", "HEAD") - - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commit1) - gitCmd(t, repoPath, "update-ref", "refs/heads/feature", commit1) - gitCmd(t, repoPath, "pack-refs", "--all", "--prune") - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - hash1, _ := repo.ParseHash(commit1) - - refs, err := repo.ListRefs("refs/heads/fea*") - if err != nil { - t.Fatalf("ListRefs failed: %v", err) - } - if len(refs) != 1 { - t.Fatalf("expected 1 ref, got %d", len(refs)) - } - if refs[0].Name != "refs/heads/feature" { - t.Fatalf("unexpected ref name: got %q, want %q", refs[0].Name, "refs/heads/feature") - } - if refs[0].Kind != RefKindDetached || refs[0].Hash != hash1 { - t.Fatalf("refs/heads/feature hash: got %s (kind %v), want %s", refs[0].Hash, refs[0].Kind, hash1) - } -} - -func TestListRefsPackedPatterns(t *testing.T) { - repoPath, cleanup := setupTestRepo(t) - defer cleanup() - - workDir, cleanupWork := setupWorkDir(t) - defer cleanupWork() - - gitCmd(t, repoPath, "symbolic-ref", "HEAD", "refs/heads/main") - - err := os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("one"), 0o644) - if err != nil { - t.Fatalf("failed to write file.txt: %v", err) - } - gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".") - gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "c1") - commit := gitCmd(t, repoPath, "rev-parse", "HEAD") - - gitCmd(t, repoPath, "update-ref", "refs/heads/main", commit) - gitCmd(t, repoPath, "update-ref", "refs/heads/feature/one", commit) - gitCmd(t, repoPath, "update-ref", "refs/notes/review", commit) - gitCmd(t, repoPath, "update-ref", "refs/tags/v1", commit) - gitCmd(t, repoPath, "pack-refs", "--all", "--prune") - - repo, err := OpenRepository(repoPath) - if err != nil { - t.Fatalf("OpenRepository failed: %v", err) - } - defer func() { _ = repo.Close() }() - - tests := []struct { - pattern string - want []string - }{ - { - pattern: "refs/heads/*", - want: []string{"refs/heads/main"}, - }, - { - pattern: "refs/heads/*/*", - want: []string{"refs/heads/feature/one"}, - }, - { - pattern: "refs/*/feature/one", - want: []string{"refs/heads/feature/one"}, - }, - { - pattern: "refs/heads/feat?re/one", - want: []string{"refs/heads/feature/one"}, - }, - { - pattern: "refs/tags/v[0-9]", - want: []string{"refs/tags/v1"}, - }, - { - pattern: "refs/*/*", - want: []string{"refs/heads/main", "refs/notes/review", "refs/tags/v1"}, - }, - } - - for _, tt := range tests { - t.Run(tt.pattern, func(t *testing.T) { - refs, err := repo.ListRefs(tt.pattern) - if err != nil { - t.Fatalf("ListRefs(%q) failed: %v", tt.pattern, err) - } - - got := make(map[string]struct{}, len(refs)) - for _, r := range refs { - got[r.Name] = struct{}{} - } - - want := make(map[string]struct{}, len(tt.want)) - for _, w := range tt.want { - want[w] = struct{}{} - } - - if len(got) != len(want) { - t.Fatalf("ListRefs(%q) returned %d refs, want %d", tt.pattern, len(got), len(want)) - } - for name := range got { - if _, ok := want[name]; !ok { - t.Fatalf("ListRefs(%q) unexpected ref %q", tt.pattern, name) - } - } - }) - } -} - -func TestRefShort(t *testing.T) { - t.Run("unambiguous", func(t *testing.T) { - ref := Ref{Name: "refs/heads/main"} - short := ref.Short([]Ref{ref}, false) - if short != "main" { - t.Fatalf("expected short name %q, got %q", "main", short) - } - }) - - t.Run("ambiguous", func(t *testing.T) { - ref := Ref{Name: "refs/heads/main"} - tags := Ref{Name: "refs/tags/main"} - short := ref.Short([]Ref{ref, tags}, false) - if short != "heads/main" { - t.Fatalf("expected ambiguous ref to shorten to %q, got %q", "heads/main", short) - } - }) - - t.Run("strict", func(t *testing.T) { - ref := Ref{Name: "refs/heads/main"} - remoteHead := Ref{Name: "refs/remotes/main/HEAD"} - - shortNonStrict := ref.Short([]Ref{ref, remoteHead}, false) - if shortNonStrict != "main" { - t.Fatalf("expected non-strict short name %q, got %q", "main", shortNonStrict) - } - - shortStrict := ref.Short([]Ref{ref, remoteHead}, true) - if shortStrict != "heads/main" { - t.Fatalf("expected strict ambiguity to shorten to %q, got %q", "heads/main", shortStrict) - } - }) -} |
