gittuf/pkg/gitinterface/references_test.go
dawgdevv 3e835940ee pkg/gitinterface: Add and refactor tests for coverage
This commit adds tests for uncovered error paths and edge cases in
pkg/gitinterface, and refactors existing tests for clarity:

- Add error path tests for CheckAndSetReference, SetReference,
  DeleteReference, RefSpec, CanSign, VerifySignature,
  TagUsingSpecificKey, GetAllFilesInTree, EnsureIsCommit,
  GetTagTarget, ensureIsTag, and other helpers
- Inline error-case test functions into parent tests using t.Run
  subtests for better organization
- Extract inline byte slices into named variables for readability
- Simplify temp directory usage where subdirectories are unnecessary
- Remove redundant parser-level error tests
- Format files with gofmt

Signed-off-by: dawgdevv <nraj02415@gmail.com>
2026-04-30 02:47:33 +05:30

492 lines
14 KiB
Go

// Copyright The gittuf Authors
// SPDX-License-Identifier: Apache-2.0
package gitinterface
import (
"fmt"
"testing"
artifacts "github.com/gittuf/gittuf/internal/testartifacts"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetReference(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
refName := "refs/heads/main"
treeBuilder := NewTreeBuilder(repo)
// Write empty tree
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
commitID, err := repo.Commit(emptyTreeID, refName, "Initial commit\n", false)
require.Nil(t, err)
refTip, err := repo.GetReference(refName)
assert.Nil(t, err)
assert.Equal(t, commitID, refTip)
}
func TestSetReference(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
refName := "refs/heads/main"
treeBuilder := NewTreeBuilder(repo)
// Write empty tree
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
firstCommitID, err := repo.Commit(emptyTreeID, refName, "Initial commit\n", false)
require.Nil(t, err)
// Create second commit with tree
secondCommitID, err := repo.Commit(emptyTreeID, refName, "Add README\n", false)
require.Nil(t, err)
refTip, err := repo.GetReference(refName)
require.Nil(t, err)
require.Equal(t, secondCommitID, refTip)
t.Run("success", func(t *testing.T) {
err = repo.SetReference(refName, firstCommitID)
assert.Nil(t, err)
refTip, err = repo.GetReference(refName)
require.Nil(t, err)
assert.Equal(t, firstCommitID, refTip)
})
t.Run("invalid ref name", func(t *testing.T) {
err = repo.SetReference("invalid ref name", firstCommitID)
assert.ErrorContains(t, err, "unable to set Git reference")
})
}
func TestCheckAndSetReference(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
refName := "refs/heads/main"
treeBuilder := NewTreeBuilder(repo)
// Write empty tree
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
firstCommitID, err := repo.Commit(emptyTreeID, refName, "Initial commit\n", false)
require.Nil(t, err)
// Create second commit with tree
secondCommitID, err := repo.Commit(emptyTreeID, refName, "Add README\n", false)
require.Nil(t, err)
refTip, err := repo.GetReference(refName)
require.Nil(t, err)
require.Equal(t, secondCommitID, refTip)
t.Run("success", func(t *testing.T) {
err = repo.CheckAndSetReference(refName, firstCommitID, secondCommitID)
assert.Nil(t, err)
refTip, err = repo.GetReference(refName)
require.Nil(t, err)
assert.Equal(t, firstCommitID, refTip)
})
t.Run("error when old value mismatches", func(t *testing.T) {
err = repo.SetReference(refName, secondCommitID)
require.Nil(t, err)
err = repo.CheckAndSetReference(refName, firstCommitID, firstCommitID)
assert.ErrorContains(t, err, "unable to set Git reference")
})
}
func TestGetSymbolicReferenceTarget(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
refName := "refs/heads/main"
treeBuilder := NewTreeBuilder(repo)
// Write empty tree
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
_, err = repo.Commit(emptyTreeID, refName, "Initial commit\n", false)
require.Nil(t, err)
// HEAD must be set to the main branch -> this is handled by git init
head, err := repo.GetSymbolicReferenceTarget("HEAD")
assert.Nil(t, err)
assert.Equal(t, refName, head)
}
func TestSetSymbolicReference(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
refName := "refs/heads/not-main" // we want to ensure it's set to something other than the default main
treeBuilder := NewTreeBuilder(repo)
// Write empty tree
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
_, err = repo.Commit(emptyTreeID, refName, "Initial commit\n", false)
require.Nil(t, err)
head, err := repo.GetSymbolicReferenceTarget("HEAD")
require.Nil(t, err)
assert.Equal(t, "refs/heads/main", head)
err = repo.SetSymbolicReference("HEAD", refName)
assert.Nil(t, err)
head, err = repo.GetSymbolicReferenceTarget("HEAD")
require.Nil(t, err)
assert.Equal(t, refName, head) // not main anymore
}
func TestRepositoryRefSpec(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
shortRefName := "master"
qualifiedRefName := "refs/heads/master"
qualifiedRemoteRefName := "refs/remotes/origin/master"
treeBuilder := NewTreeBuilder(repo)
emptyTreeHash, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
commitID, err := repo.Commit(emptyTreeHash, qualifiedRefName, "Test Commit", false)
if err != nil {
t.Fatal(err)
}
refHash, err := repo.GetReference(qualifiedRefName)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, commitID, refHash, "unexpected value configuring test repo")
tests := map[string]struct {
repo *Repository
refName string
remoteName string
fastForwardOnly bool
expectedRefSpec string
expectedError error
}{
"standard branch, not fast forward only, no remote": {
refName: "refs/heads/main",
expectedRefSpec: "+refs/heads/main:refs/heads/main",
},
"standard branch, fast forward only, no remote": {
refName: "refs/heads/main",
fastForwardOnly: true,
expectedRefSpec: "refs/heads/main:refs/heads/main",
},
"standard branch, not fast forward only, remote": {
refName: "refs/heads/main",
remoteName: "origin",
expectedRefSpec: "+refs/heads/main:refs/remotes/origin/main",
},
"standard branch, fast forward only, remote": {
refName: "refs/heads/main",
remoteName: "origin",
fastForwardOnly: true,
expectedRefSpec: "refs/heads/main:refs/remotes/origin/main",
},
"non-standard branch, not fast forward only, no remote": {
refName: "refs/heads/foo/bar",
expectedRefSpec: "+refs/heads/foo/bar:refs/heads/foo/bar",
},
"non-standard branch, fast forward only, no remote": {
refName: "refs/heads/foo/bar",
fastForwardOnly: true,
expectedRefSpec: "refs/heads/foo/bar:refs/heads/foo/bar",
},
"non-standard branch, not fast forward only, remote": {
refName: "refs/heads/foo/bar",
remoteName: "origin",
expectedRefSpec: "+refs/heads/foo/bar:refs/remotes/origin/foo/bar",
},
"non-standard branch, fast forward only, remote": {
refName: "refs/heads/foo/bar",
remoteName: "origin",
fastForwardOnly: true,
expectedRefSpec: "refs/heads/foo/bar:refs/remotes/origin/foo/bar",
},
"short branch, not fast forward only, no remote": {
refName: shortRefName,
repo: repo,
expectedRefSpec: fmt.Sprintf("+%s:%s", qualifiedRefName, qualifiedRefName),
},
"short branch, fast forward only, no remote": {
refName: shortRefName,
repo: repo,
fastForwardOnly: true,
expectedRefSpec: fmt.Sprintf("%s:%s", qualifiedRefName, qualifiedRefName),
},
"short branch, not fast forward only, remote": {
refName: shortRefName,
repo: repo,
remoteName: "origin",
expectedRefSpec: fmt.Sprintf("+%s:%s", qualifiedRefName, qualifiedRemoteRefName),
},
"short branch, fast forward only, remote": {
refName: shortRefName,
repo: repo,
fastForwardOnly: true,
remoteName: "origin",
expectedRefSpec: fmt.Sprintf("%s:%s", qualifiedRefName, qualifiedRemoteRefName),
},
"custom namespace, not fast forward only, no remote": {
refName: "refs/foo/bar",
expectedRefSpec: "+refs/foo/bar:refs/foo/bar",
},
"custom namespace, fast forward only, no remote": {
refName: "refs/foo/bar",
fastForwardOnly: true,
expectedRefSpec: "refs/foo/bar:refs/foo/bar",
},
"custom namespace, not fast forward only, remote": {
refName: "refs/foo/bar",
remoteName: "origin",
expectedRefSpec: "+refs/foo/bar:refs/remotes/origin/foo/bar",
},
"custom namespace, fast forward only, remote": {
refName: "refs/foo/bar",
remoteName: "origin",
fastForwardOnly: true,
expectedRefSpec: "refs/foo/bar:refs/remotes/origin/foo/bar",
},
"tag, not fast forward only, no remote": {
refName: "refs/tags/v1.0.0",
fastForwardOnly: false,
expectedRefSpec: "refs/tags/v1.0.0:refs/tags/v1.0.0",
},
"tag, fast forward only, no remote": {
refName: "refs/tags/v1.0.0",
fastForwardOnly: true,
expectedRefSpec: "refs/tags/v1.0.0:refs/tags/v1.0.0",
},
"tag, not fast forward only, remote": {
refName: "refs/tags/v1.0.0",
remoteName: "origin",
fastForwardOnly: false,
expectedRefSpec: "refs/tags/v1.0.0:refs/tags/v1.0.0",
},
"tag, fast forward only, remote": {
refName: "refs/tags/v1.0.0",
remoteName: "origin",
fastForwardOnly: true,
expectedRefSpec: "refs/tags/v1.0.0:refs/tags/v1.0.0",
},
}
for name, test := range tests {
refSpec, err := test.repo.RefSpec(test.refName, test.remoteName, test.fastForwardOnly)
assert.ErrorIs(t, err, test.expectedError, fmt.Sprintf("unexpected error in test '%s'", name))
assert.Equal(t, test.expectedRefSpec, refSpec, fmt.Sprintf("unexpected refspec returned in test '%s'", name))
}
t.Run("nonexistent ref", func(t *testing.T) {
_, err := repo.RefSpec("nonexistent", "", false)
assert.ErrorIs(t, err, ErrReferenceNotFound)
})
}
func TestBranchReferenceName(t *testing.T) {
tests := map[string]struct {
branchName string
expectedReferenceName string
}{
"short name": {
branchName: "main",
expectedReferenceName: "refs/heads/main",
},
"reference name": {
branchName: "refs/heads/main",
expectedReferenceName: "refs/heads/main",
},
}
for name, test := range tests {
referenceName := BranchReferenceName(test.branchName)
assert.Equal(t, test.expectedReferenceName, referenceName, fmt.Sprintf("unexpected branch reference received in test '%s'", name))
}
}
func TestTagReferenceName(t *testing.T) {
tests := map[string]struct {
tagName string
expectedReferenceName string
}{
"short name": {
tagName: "v1",
expectedReferenceName: "refs/tags/v1",
},
"reference name": {
tagName: "refs/tags/v1",
expectedReferenceName: "refs/tags/v1",
},
}
for name, test := range tests {
referenceName := TagReferenceName(test.tagName)
assert.Equal(t, test.expectedReferenceName, referenceName, fmt.Sprintf("unexpected tag reference received in test '%s'", name))
}
}
func TestDeleteReference(t *testing.T) {
tempDir := t.TempDir()
repo := CreateTestGitRepository(t, tempDir, false)
refName := "refs/heads/main"
treeBuilder := NewTreeBuilder(repo)
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
if err != nil {
t.Fatal(err)
}
commitID, err := repo.Commit(emptyTreeID, refName, "Initial commit\n", false)
require.Nil(t, err)
refTip, err := repo.GetReference(refName)
require.Nil(t, err)
require.Equal(t, commitID, refTip)
t.Run("success", func(t *testing.T) {
err = repo.DeleteReference(refName)
assert.Nil(t, err)
_, err = repo.GetReference(refName)
assert.ErrorIs(t, err, ErrReferenceNotFound)
})
t.Run("invalid ref name", func(t *testing.T) {
err = repo.DeleteReference("invalid ref name")
assert.ErrorContains(t, err, "unable to delete Git reference")
})
}
func TestRemoteReferenceName(t *testing.T) {
tests := map[string]struct {
input string
expected string
}{
"adds prefix if missing": {
input: "origin/main",
expected: "refs/remotes/origin/main",
},
"keeps prefix if already present": {
input: "refs/remotes/origin/main",
expected: "refs/remotes/origin/main",
},
"empty input returns prefix only": {
input: "",
expected: "refs/remotes/",
},
"exact prefix is preserved": {
input: "refs/remotes/",
expected: "refs/remotes/",
},
}
for name, test := range tests {
referenceName := RemoteReferenceName(test.input)
assert.Equal(t, test.expected, referenceName, fmt.Sprintf("unexpected remote reference for input %s", name))
}
}
func TestAbsoluteReference(t *testing.T) {
tmpDir := t.TempDir()
repo := CreateTestGitRepository(t, tmpDir, false)
treeBuilder := NewTreeBuilder(repo)
emptyTreeID, err := treeBuilder.WriteTreeFromEntries(nil)
require.Nil(t, err)
commitID, err := repo.Commit(emptyTreeID, "refs/heads/main", "Initial commit\n", false)
require.Nil(t, err)
_, err = repo.TagUsingSpecificKey(commitID, "v1.0", "v1.0\n", artifacts.SSHED25519Private)
require.Nil(t, err)
err = repo.SetReference("refs/custom/myref", commitID)
require.Nil(t, err)
err = repo.SetReference("refs/remotes/origin/main", commitID)
require.Nil(t, err)
err = repo.SetSymbolicReference("refs/remotes/origin/HEAD", "refs/remotes/origin/main")
require.Nil(t, err)
t.Run("symbolic ref HEAD", func(t *testing.T) {
ref, err := repo.AbsoluteReference("HEAD")
assert.Nil(t, err)
assert.Equal(t, "refs/heads/main", ref)
})
t.Run("fully qualified branch", func(t *testing.T) {
ref, err := repo.AbsoluteReference("refs/heads/main")
assert.Nil(t, err)
assert.Equal(t, "refs/heads/main", ref)
})
t.Run("short branch name", func(t *testing.T) {
ref, err := repo.AbsoluteReference("main")
assert.Nil(t, err)
assert.Equal(t, "refs/heads/main", ref)
})
t.Run("tag name", func(t *testing.T) {
ref, err := repo.AbsoluteReference("v1.0")
assert.Nil(t, err)
assert.Equal(t, "refs/tags/v1.0", ref)
})
t.Run("custom ref", func(t *testing.T) {
ref, err := repo.AbsoluteReference("custom/myref")
assert.Nil(t, err)
assert.Equal(t, "refs/custom/myref", ref)
})
t.Run("remote tracking ref", func(t *testing.T) {
ref, err := repo.AbsoluteReference("origin/main")
assert.Nil(t, err)
assert.Equal(t, "refs/remotes/origin/main", ref)
})
t.Run("remote HEAD", func(t *testing.T) {
ref, err := repo.AbsoluteReference("origin")
assert.Nil(t, err)
assert.Equal(t, "refs/remotes/origin/HEAD", ref)
})
t.Run("non-existent ref", func(t *testing.T) {
_, err := repo.AbsoluteReference("nonexistent")
assert.ErrorIs(t, err, ErrReferenceNotFound)
})
}