a few more unit tests

main
jolheiser 2025-06-04 15:22:28 -05:00
parent b8ca3fc4b8
commit 86aa09929f
No known key found for this signature in database
3 changed files with 356 additions and 0 deletions

View File

@ -3,8 +3,10 @@ package git_test
import ( import (
"path/filepath" "path/filepath"
"testing" "testing"
"time"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
"go.jolheiser.com/ugit/internal/git" "go.jolheiser.com/ugit/internal/git"
) )
@ -43,3 +45,232 @@ func TestRepo(t *testing.T) {
assert.NoError(t, err, "should not error when getting existing repo") assert.NoError(t, err, "should not error when getting existing repo")
assert.False(t, repo.Meta.Private, "repo should be public after saving meta") assert.False(t, repo.Meta.Private, "repo should be public after saving meta")
} }
func TestPathExists(t *testing.T) {
tmp := t.TempDir()
exists, err := git.PathExists(tmp)
assert.NoError(t, err)
assert.True(t, exists)
doesNotExist := filepath.Join(tmp, "does-not-exist")
exists, err = git.PathExists(doesNotExist)
assert.NoError(t, err)
assert.False(t, exists)
}
func TestRepoMetaUpdate(t *testing.T) {
original := git.RepoMeta{
Description: "Original description",
Private: true,
Tags: git.TagSet{"tag1": struct{}{}, "tag2": struct{}{}},
}
update := git.RepoMeta{
Description: "Updated description",
Private: false,
Tags: git.TagSet{"tag3": struct{}{}},
}
err := original.Update(update)
assert.NoError(t, err)
assert.Equal(t, "Updated description", original.Description)
assert.False(t, original.Private)
assert.Equal(t, []string{"tag1", "tag2", "tag3"}, original.Tags.Slice())
}
func TestFileInfoName(t *testing.T) {
testCases := []struct {
path string
expected string
}{
{path: "file.txt", expected: "file.txt"},
{path: "dir/file.txt", expected: "file.txt"},
{path: "nested/path/to/file.go", expected: "file.go"},
{path: "README.md", expected: "README.md"},
}
for _, tc := range testCases {
t.Run(tc.path, func(t *testing.T) {
fi := git.FileInfo{Path: tc.path}
assert.Equal(t, tc.expected, fi.Name())
})
}
}
func TestCommitSummaryAndDetails(t *testing.T) {
testCases := []struct {
message string
expectedSummary string
expectedDetails string
}{
{
message: "Simple commit message",
expectedSummary: "Simple commit message",
expectedDetails: "",
},
{
message: "Add feature X\n\nThis commit adds feature X\nWith multiple details\nAcross multiple lines",
expectedSummary: "Add feature X",
expectedDetails: "\nThis commit adds feature X\nWith multiple details\nAcross multiple lines",
},
{
message: "Fix bug\n\nDetailed explanation",
expectedSummary: "Fix bug",
expectedDetails: "\nDetailed explanation",
},
}
for _, tc := range testCases {
t.Run(tc.message, func(t *testing.T) {
commit := git.Commit{
SHA: "abcdef1234567890",
Message: tc.message,
Signature: "",
Author: "Test User",
Email: "test@example.com",
When: time.Now(),
}
assert.Equal(t, tc.expectedSummary, commit.Summary())
assert.Equal(t, tc.expectedDetails, commit.Details())
})
}
}
func TestCommitShort(t *testing.T) {
commit := git.Commit{
SHA: "abcdef1234567890abcdef1234567890",
}
assert.Equal(t, "abcdef12", commit.Short())
}
func TestCommitFilePath(t *testing.T) {
testCases := []struct {
name string
fromPath string
toPath string
expected string
}{
{
name: "to path preferred",
fromPath: "old/path.txt",
toPath: "new/path.txt",
expected: "new/path.txt",
},
{
name: "fallback to from path",
fromPath: "deleted/file.txt",
toPath: "",
expected: "deleted/file.txt",
},
{
name: "both paths empty",
fromPath: "",
toPath: "",
expected: "",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cf := git.CommitFile{
From: git.CommitFileEntry{Path: tc.fromPath},
To: git.CommitFileEntry{Path: tc.toPath},
}
assert.Equal(t, tc.expected, cf.Path())
})
}
}
func TestRepoName(t *testing.T) {
tmp := t.TempDir()
repoName := "testrepo"
err := git.EnsureRepo(tmp, repoName+".git")
assert.NoError(t, err)
repo, err := git.NewRepo(tmp, repoName)
assert.NoError(t, err)
assert.Equal(t, repoName, repo.Name())
repoName2 := "test-repo-with-hyphens"
err = git.EnsureRepo(tmp, repoName2+".git")
assert.NoError(t, err)
repo2, err := git.NewRepo(tmp, repoName2)
assert.NoError(t, err)
assert.Equal(t, repoName2, repo2.Name())
}
func TestHandlePushOptions(t *testing.T) {
tmp := t.TempDir()
err := git.EnsureRepo(tmp, "test.git")
assert.NoError(t, err)
repo, err := git.NewRepo(tmp, "test")
assert.NoError(t, err)
opts := []*packp.Option{
{Key: "description", Value: "New description"},
}
err = git.HandlePushOptions(repo, opts)
assert.NoError(t, err)
assert.Equal(t, "New description", repo.Meta.Description)
opts = []*packp.Option{
{Key: "private", Value: "false"},
}
err = git.HandlePushOptions(repo, opts)
assert.NoError(t, err)
assert.False(t, repo.Meta.Private)
repo.Meta.Private = true
opts = []*packp.Option{
{Key: "private", Value: "invalid"},
}
err = git.HandlePushOptions(repo, opts)
assert.NoError(t, err)
assert.True(t, repo.Meta.Private)
opts = []*packp.Option{
{Key: "tags", Value: "tag1,tag2"},
}
err = git.HandlePushOptions(repo, opts)
assert.NoError(t, err)
opts = []*packp.Option{
{Key: "description", Value: "Combined update"},
{Key: "private", Value: "true"},
}
err = git.HandlePushOptions(repo, opts)
assert.NoError(t, err)
assert.Equal(t, "Combined update", repo.Meta.Description)
assert.True(t, repo.Meta.Private)
}
func TestRepoPath(t *testing.T) {
tmp := t.TempDir()
err := git.EnsureRepo(tmp, "test.git")
assert.NoError(t, err)
repo, err := git.NewRepo(tmp, "test")
assert.NoError(t, err)
expected := filepath.Join(tmp, "test.git")
assert.Equal(t, expected, repo.Path())
}
func TestEnsureJSONFile(t *testing.T) {
tmp := t.TempDir()
err := git.EnsureRepo(tmp, "test.git")
assert.NoError(t, err)
repo, err := git.NewRepo(tmp, "test")
assert.NoError(t, err)
assert.True(t, repo.Meta.Private, "default repo should be private")
assert.Equal(t, "", repo.Meta.Description, "default description should be empty")
assert.Equal(t, 0, len(repo.Meta.Tags), "default tags should be empty")
}

View File

@ -57,6 +57,9 @@ func NewRepo(dir, name string) (*Repo, error) {
if err := json.NewDecoder(fi).Decode(&r.Meta); err != nil { if err := json.NewDecoder(fi).Decode(&r.Meta); err != nil {
return nil, err return nil, err
} }
if r.Meta.Tags == nil {
r.Meta.Tags = make(TagSet)
}
return r, nil return r, nil
} }

View File

@ -0,0 +1,122 @@
package httperr_test
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/alecthomas/assert/v2"
"go.jolheiser.com/ugit/internal/http/httperr"
)
func successHandler(w http.ResponseWriter, r *http.Request) error {
w.WriteHeader(http.StatusOK)
return nil
}
func errorHandler(w http.ResponseWriter, r *http.Request) error {
return errors.New("test error")
}
func statusErrorHandler(status int) func(w http.ResponseWriter, r *http.Request) error {
return func(w http.ResponseWriter, r *http.Request) error {
return httperr.Status(errors.New("test error"), status)
}
}
func TestHandler_Success(t *testing.T) {
handler := httperr.Handler(successHandler)
req := httptest.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusOK, recorder.Code)
}
func TestHandler_Error(t *testing.T) {
handler := httperr.Handler(errorHandler)
req := httptest.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusInternalServerError, recorder.Code)
}
func TestHandler_StatusError(t *testing.T) {
testCases := []struct {
name string
status int
expectedStatus int
}{
{
name: "not found",
status: http.StatusNotFound,
expectedStatus: http.StatusNotFound,
},
{
name: "bad request",
status: http.StatusBadRequest,
expectedStatus: http.StatusBadRequest,
},
{
name: "unauthorized",
status: http.StatusUnauthorized,
expectedStatus: http.StatusUnauthorized,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
handler := httperr.Handler(statusErrorHandler(tc.status))
req := httptest.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, req)
assert.Equal(t, tc.expectedStatus, recorder.Code)
})
}
}
type unwrapper interface {
Unwrap() error
}
func TestError(t *testing.T) {
originalErr := errors.New("original error")
httpErr := httperr.Error(originalErr)
assert.Equal(t, originalErr.Error(), httpErr.Error())
unwrapper, ok := any(httpErr).(unwrapper)
assert.True(t, ok)
assert.Equal(t, originalErr, unwrapper.Unwrap())
}
func TestStatus(t *testing.T) {
originalErr := errors.New("original error")
httpErr := httperr.Status(originalErr, http.StatusNotFound)
assert.Equal(t, originalErr.Error(), httpErr.Error())
unwrapper, ok := any(httpErr).(unwrapper)
assert.True(t, ok)
assert.Equal(t, originalErr, unwrapper.Unwrap())
handler := httperr.Handler(func(w http.ResponseWriter, r *http.Request) error {
return httpErr
})
req := httptest.NewRequest("GET", "/", nil)
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, req)
assert.Equal(t, http.StatusNotFound, recorder.Code)
}