ref: f49c95662bda1f2c337dbe872644afa1ca5cbbec
parent: dc110eaaf376c02fd957853330566a75b1511f3c
author: Runxi Yu <me@runxiyu.org>
date: Fri Feb 20 17:52:58 EST 2026
objectid: Rename from oid
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -7,7 +7,7 @@
"testing"
"codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func openConfig(t *testing.T, repo *testgit.TestRepo) *os.File {@@ -25,7 +25,7 @@
}
func TestConfigAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "core.bare", "true")
repo.Run(t, "config", "core.filemode", "false")
@@ -56,7 +56,7 @@
}
func TestConfigSubsectionAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "remote.origin.url", "https://example.org/repo.git")
repo.Run(t, "config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*")
@@ -79,7 +79,7 @@
}
func TestConfigMultiValueAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "--add", "remote.origin.fetch", "+refs/heads/main:refs/remotes/origin/main")
repo.Run(t, "config", "--add", "remote.origin.fetch", "+refs/heads/dev:refs/remotes/origin/dev")
@@ -112,7 +112,7 @@
}
func TestConfigCaseInsensitiveAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "Core.Bare", "true")
repo.Run(t, "config", "CORE.FileMode", "false")
@@ -141,7 +141,7 @@
}
func TestConfigBooleanAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "test.flag1", "true")
repo.Run(t, "config", "test.flag2", "false")
@@ -175,7 +175,7 @@
}
func TestConfigComplexValuesAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "test.spaced", "value with spaces")
repo.Run(t, "config", "test.special", "value=with=equals")
@@ -201,7 +201,7 @@
}
func TestConfigEntriesAgainstGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
repo.Run(t, "config", "core.bare", "true")
repo.Run(t, "config", "core.filemode", "false")
--- a/internal/testgit/algorithms.go
+++ b/internal/testgit/algorithms.go
@@ -3,19 +3,19 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// SupportedAlgorithms returns all object ID algorithms supported by furgit.
-func SupportedAlgorithms() []oid.Algorithm {- return []oid.Algorithm{- oid.AlgorithmSHA1,
- oid.AlgorithmSHA256,
+func SupportedAlgorithms() []objectid.Algorithm {+ return []objectid.Algorithm{+ objectid.AlgorithmSHA1,
+ objectid.AlgorithmSHA256,
}
}
// ForEachAlgorithm runs a subtest for every supported algorithm.
-func ForEachAlgorithm(t *testing.T, fn func(t *testing.T, algo oid.Algorithm)) {+func ForEachAlgorithm(t *testing.T, fn func(t *testing.T, algo objectid.Algorithm)) {t.Helper()
for _, algo := range SupportedAlgorithms() { t.Run(algo.String(), func(t *testing.T) {--- a/internal/testgit/repo.go
+++ b/internal/testgit/repo.go
@@ -1,10 +1,10 @@
package testgit
-import "codeberg.org/lindenii/furgit/oid"
+import "codeberg.org/lindenii/furgit/objectid"
// TestRepo is a temporary git repository harness for integration tests.
type TestRepo struct {dir string
- algo oid.Algorithm
+ algo objectid.Algorithm
env []string
}
--- a/internal/testgit/repo_cat_file.go
+++ b/internal/testgit/repo_cat_file.go
@@ -3,11 +3,11 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// CatFile returns raw output from git cat-file.
-func (repo *TestRepo) CatFile(tb testing.TB, mode string, id oid.ObjectID) []byte {+func (repo *TestRepo) CatFile(tb testing.TB, mode string, id objectid.ObjectID) []byte {tb.Helper()
return repo.RunBytes(tb, "cat-file", mode, id.String())
}
--- a/internal/testgit/repo_commit_tree.go
+++ b/internal/testgit/repo_commit_tree.go
@@ -3,11 +3,11 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// CommitTree creates a commit from a tree and message, optionally with parents.
-func (repo *TestRepo) CommitTree(tb testing.TB, tree oid.ObjectID, message string, parents ...oid.ObjectID) oid.ObjectID {+func (repo *TestRepo) CommitTree(tb testing.TB, tree objectid.ObjectID, message string, parents ...objectid.ObjectID) objectid.ObjectID {tb.Helper()
args := []string{"commit-tree", tree.String()} for _, p := range parents {@@ -15,7 +15,7 @@
}
args = append(args, "-m", message)
hex := repo.Run(tb, args...)
- id, err := oid.ParseHex(repo.algo, hex)
+ id, err := objectid.ParseHex(repo.algo, hex)
if err != nil { tb.Fatalf("parse commit-tree output %q: %v", hex, err)}
--- a/internal/testgit/repo_hash_object.go
+++ b/internal/testgit/repo_hash_object.go
@@ -3,14 +3,14 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// HashObject hashes and writes an object and returns its object ID.
-func (repo *TestRepo) HashObject(tb testing.TB, objType string, body []byte) oid.ObjectID {+func (repo *TestRepo) HashObject(tb testing.TB, objType string, body []byte) objectid.ObjectID {tb.Helper()
hex := repo.RunInput(tb, body, "hash-object", "-t", objType, "-w", "--stdin")
- id, err := oid.ParseHex(repo.algo, hex)
+ id, err := objectid.ParseHex(repo.algo, hex)
if err != nil { tb.Fatalf("parse git hash-object output %q: %v", hex, err)}
--- a/internal/testgit/repo_make_commit.go
+++ b/internal/testgit/repo_make_commit.go
@@ -3,11 +3,11 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// MakeCommit creates a commit over a single-file tree and returns (blobID, treeID, commitID).
-func (repo *TestRepo) MakeCommit(tb testing.TB, message string) (oid.ObjectID, oid.ObjectID, oid.ObjectID) {+func (repo *TestRepo) MakeCommit(tb testing.TB, message string) (objectid.ObjectID, objectid.ObjectID, objectid.ObjectID) {tb.Helper()
blobID, treeID := repo.MakeSingleFileTree(tb, "file.txt", []byte("commit-body\n"))commitID := repo.CommitTree(tb, treeID, message)
--- a/internal/testgit/repo_make_single_file_tree.go
+++ b/internal/testgit/repo_make_single_file_tree.go
@@ -4,11 +4,11 @@
"fmt"
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// MakeSingleFileTree writes one blob and one tree entry for it and returns (blobID, treeID).
-func (repo *TestRepo) MakeSingleFileTree(tb testing.TB, fileName string, fileContent []byte) (oid.ObjectID, oid.ObjectID) {+func (repo *TestRepo) MakeSingleFileTree(tb testing.TB, fileName string, fileContent []byte) (objectid.ObjectID, objectid.ObjectID) {tb.Helper()
blobID := repo.HashObject(tb, "blob", fileContent)
treeInput := fmt.Sprintf("100644 blob %s\t%s\n", blobID.String(), fileName)--- a/internal/testgit/repo_mktree.go
+++ b/internal/testgit/repo_mktree.go
@@ -3,14 +3,14 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// Mktree creates a tree from textual mktree input and returns its ID.
-func (repo *TestRepo) Mktree(tb testing.TB, input string) oid.ObjectID {+func (repo *TestRepo) Mktree(tb testing.TB, input string) objectid.ObjectID {tb.Helper()
hex := repo.RunInput(tb, []byte(input), "mktree")
- id, err := oid.ParseHex(repo.algo, hex)
+ id, err := objectid.ParseHex(repo.algo, hex)
if err != nil { tb.Fatalf("parse mktree output %q: %v", hex, err)}
--- a/internal/testgit/repo_new.go
+++ b/internal/testgit/repo_new.go
@@ -4,22 +4,22 @@
"os"
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// NewBareRepo creates a temporary bare repository initialized with the requested algorithm.
-func NewBareRepo(tb testing.TB, algo oid.Algorithm) *TestRepo {+func NewBareRepo(tb testing.TB, algo objectid.Algorithm) *TestRepo {tb.Helper()
return newRepo(tb, algo, true)
}
// NewWorkRepo creates a temporary non-bare repository initialized with the requested algorithm.
-func NewWorkRepo(tb testing.TB, algo oid.Algorithm) *TestRepo {+func NewWorkRepo(tb testing.TB, algo objectid.Algorithm) *TestRepo {tb.Helper()
return newRepo(tb, algo, false)
}
-func newRepo(tb testing.TB, algo oid.Algorithm, bare bool) *TestRepo {+func newRepo(tb testing.TB, algo objectid.Algorithm, bare bool) *TestRepo {tb.Helper()
if algo.Size() == 0 { tb.Fatalf("invalid algorithm: %v", algo)--- a/internal/testgit/repo_properties.go
+++ b/internal/testgit/repo_properties.go
@@ -1,6 +1,6 @@
package testgit
-import "codeberg.org/lindenii/furgit/oid"
+import "codeberg.org/lindenii/furgit/objectid"
// Dir returns the repository directory path.
func (repo *TestRepo) Dir() string {@@ -8,6 +8,6 @@
}
// Algorithm returns the object ID algorithm configured for this repository.
-func (repo *TestRepo) Algorithm() oid.Algorithm {+func (repo *TestRepo) Algorithm() objectid.Algorithm {return repo.algo
}
--- a/internal/testgit/repo_rev_parse.go
+++ b/internal/testgit/repo_rev_parse.go
@@ -3,14 +3,14 @@
import (
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// RevParse resolves rev expressions to object IDs.
-func (repo *TestRepo) RevParse(tb testing.TB, spec string) oid.ObjectID {+func (repo *TestRepo) RevParse(tb testing.TB, spec string) objectid.ObjectID {tb.Helper()
hex := repo.Run(tb, "rev-parse", spec)
- id, err := oid.ParseHex(repo.algo, hex)
+ id, err := objectid.ParseHex(repo.algo, hex)
if err != nil { tb.Fatalf("parse rev-parse output %q: %v", hex, err)}
--- a/internal/testgit/repo_tag_annotated.go
+++ b/internal/testgit/repo_tag_annotated.go
@@ -4,11 +4,11 @@
"fmt"
"testing"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// TagAnnotated creates an annotated tag object and returns the resulting tag object ID.
-func (repo *TestRepo) TagAnnotated(tb testing.TB, name string, target oid.ObjectID, message string) oid.ObjectID {+func (repo *TestRepo) TagAnnotated(tb testing.TB, name string, target objectid.ObjectID, message string) objectid.ObjectID {tb.Helper()
repo.Run(tb, "tag", "-a", name, target.String(), "-m", message)
return repo.RevParse(tb, fmt.Sprintf("refs/tags/%s", name))--- a/object/blob_parse_test.go
+++ b/object/blob_parse_test.go
@@ -6,11 +6,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestBlobParseFromGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
body := []byte("hello\nblob\n")blobID := repo.HashObject(t, "blob", body)
--- a/object/blob_serialize_test.go
+++ b/object/blob_serialize_test.go
@@ -5,11 +5,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestBlobSerialize(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
body := []byte("hello\nblob\n")wantID := repo.HashObject(t, "blob", body)
--- a/object/commit.go
+++ b/object/commit.go
@@ -2,13 +2,13 @@
import (
"codeberg.org/lindenii/furgit/objecttype"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// Commit represents a Git commit object.
type Commit struct {- Tree oid.ObjectID
- Parents []oid.ObjectID
+ Tree objectid.ObjectID
+ Parents []objectid.ObjectID
Author Ident
Committer Ident
Message []byte
--- a/object/commit_parse.go
+++ b/object/commit_parse.go
@@ -5,11 +5,11 @@
"errors"
"fmt"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// ParseCommit decodes a commit object body.
-func ParseCommit(body []byte, algo oid.Algorithm) (*Commit, error) {+func ParseCommit(body []byte, algo objectid.Algorithm) (*Commit, error) {c := new(Commit)
i := 0
for i < len(body) {@@ -30,13 +30,13 @@
switch string(key) {case "tree":
- id, err := oid.ParseHex(algo, string(value))
+ id, err := objectid.ParseHex(algo, string(value))
if err != nil { return nil, fmt.Errorf("object: commit: tree: %w", err)}
c.Tree = id
case "parent":
- id, err := oid.ParseHex(algo, string(value))
+ id, err := objectid.ParseHex(algo, string(value))
if err != nil { return nil, fmt.Errorf("object: commit: parent: %w", err)}
--- a/object/commit_parse_test.go
+++ b/object/commit_parse_test.go
@@ -6,11 +6,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestCommitParseFromGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
_, treeID, commitID := repo.MakeCommit(t, "subject\n\nbody")
--- a/object/commit_serialize_test.go
+++ b/object/commit_serialize_test.go
@@ -5,11 +5,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestCommitSerialize(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
_, _, commitID := repo.MakeCommit(t, "subject\n\nbody")
--- a/object/parse.go
+++ b/object/parse.go
@@ -5,11 +5,11 @@
"codeberg.org/lindenii/furgit/internal/objectheader"
"codeberg.org/lindenii/furgit/objecttype"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// ParseObjectWithoutHeader parses a typed object body.
-func ParseObjectWithoutHeader(ty objecttype.Type, body []byte, algo oid.Algorithm) (Object, error) {+func ParseObjectWithoutHeader(ty objecttype.Type, body []byte, algo objectid.Algorithm) (Object, error) { switch ty {case objecttype.TypeBlob:
return ParseBlob(body)
@@ -25,7 +25,7 @@
}
// ParseObjectWithHeader parses a loose object in "type size\\x00body" format.
-func ParseObjectWithHeader(raw []byte, algo oid.Algorithm) (Object, error) {+func ParseObjectWithHeader(raw []byte, algo objectid.Algorithm) (Object, error) {ty, size, headerLen, ok := objectheader.Parse(raw)
if !ok { return nil, fmt.Errorf("object: malformed object header")--- a/object/tag.go
+++ b/object/tag.go
@@ -2,12 +2,12 @@
import (
"codeberg.org/lindenii/furgit/objecttype"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// Tag represents a Git annotated tag object.
type Tag struct {- Target oid.ObjectID
+ Target objectid.ObjectID
TargetType objecttype.Type
Name []byte
Tagger *Ident
--- a/object/tag_parse.go
+++ b/object/tag_parse.go
@@ -6,11 +6,11 @@
"fmt"
"codeberg.org/lindenii/furgit/objecttype"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// ParseTag decodes a tag object body.
-func ParseTag(body []byte, algo oid.Algorithm) (*Tag, error) {+func ParseTag(body []byte, algo objectid.Algorithm) (*Tag, error) {t := new(Tag)
i := 0
var haveTarget, haveType bool
@@ -33,7 +33,7 @@
switch string(key) {case "object":
- id, err := oid.ParseHex(algo, string(value))
+ id, err := objectid.ParseHex(algo, string(value))
if err != nil { return nil, fmt.Errorf("object: tag: object: %w", err)}
--- a/object/tag_parse_test.go
+++ b/object/tag_parse_test.go
@@ -7,11 +7,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
"codeberg.org/lindenii/furgit/objecttype"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestTagParseFromGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
_, _, commitID := repo.MakeCommit(t, "subject\n\nbody")
tagID := repo.TagAnnotated(t, "v1", commitID, "tag message")
--- a/object/tag_serialize_test.go
+++ b/object/tag_serialize_test.go
@@ -5,11 +5,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestTagSerialize(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
_, _, commitID := repo.MakeCommit(t, "subject\n\nbody")
tagID := repo.TagAnnotated(t, "v1", commitID, "tag message")
--- a/object/tree.go
+++ b/object/tree.go
@@ -6,7 +6,7 @@
"sort"
"codeberg.org/lindenii/furgit/objecttype"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// FileMode represents the mode of a file in a Git tree.
@@ -24,7 +24,7 @@
type TreeEntry struct {Mode FileMode
Name []byte
- ID oid.ObjectID
+ ID objectid.ObjectID
}
// Tree represents a Git tree object.
--- a/object/tree_parse.go
+++ b/object/tree_parse.go
@@ -5,11 +5,11 @@
"fmt"
"strconv"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
// ParseTree decodes a tree object body.
-func ParseTree(body []byte, algo oid.Algorithm) (*Tree, error) {+func ParseTree(body []byte, algo objectid.Algorithm) (*Tree, error) {var entries []TreeEntry
i := 0
for i < len(body) {@@ -31,7 +31,7 @@
if idEnd > len(body) { return nil, fmt.Errorf("object: tree: truncated child object id")}
- id, err := oid.FromBytes(algo, body[i:idEnd])
+ id, err := objectid.FromBytes(algo, body[i:idEnd])
if err != nil {return nil, err
}
--- a/object/tree_parse_test.go
+++ b/object/tree_parse_test.go
@@ -6,11 +6,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestTreeParseFromGit(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
entries := adversarialRootEntries(t, repo)
inserted := &object.Tree{}--- a/object/tree_serialize_test.go
+++ b/object/tree_serialize_test.go
@@ -5,11 +5,11 @@
"codeberg.org/lindenii/furgit/internal/testgit"
"codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/oid"
+ "codeberg.org/lindenii/furgit/objectid"
)
func TestTreeSerialize(t *testing.T) {- testgit.ForEachAlgorithm(t, func(t *testing.T, algo oid.Algorithm) {+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {repo := testgit.NewBareRepo(t, algo)
entries := adversarialRootEntries(t, repo)
tree := &object.Tree{}--- /dev/null
+++ b/objectid/objectid.go
@@ -1,0 +1,186 @@
+// Package objectid provides object ID and algorithm primitives for Git objects.
+package objectid
+
+import (
+ "crypto/sha1"
+ "crypto/sha256"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "hash"
+)
+
+var (
+ // ErrInvalidAlgorithm indicates an unsupported object ID algorithm.
+ ErrInvalidAlgorithm = errors.New("objectid: invalid algorithm")+ // ErrInvalidObjectID indicates malformed object ID data.
+ ErrInvalidObjectID = errors.New("objectid: invalid object id")+)
+
+// maxObjectIDSize MUST be >= the largest supported algorithm size.
+const maxObjectIDSize = sha256.Size
+
+// Algorithm identifies the hash algorithm used for Git object IDs.
+type Algorithm uint8
+
+const (
+ AlgorithmUnknown Algorithm = iota
+ AlgorithmSHA1
+ AlgorithmSHA256
+)
+
+type algorithmDetails struct {+ name string
+ size int
+ sum func([]byte) ObjectID
+ new func() hash.Hash
+}
+
+var algorithmTable = [...]algorithmDetails{+ AlgorithmUnknown: {},+ AlgorithmSHA1: {+ name: "sha1",
+ size: sha1.Size,
+ sum: func(data []byte) ObjectID {+ sum := sha1.Sum(data)
+ var id ObjectID
+ copy(id.data[:], sum[:])
+ id.algo = AlgorithmSHA1
+ return id
+ },
+ new: func() hash.Hash {+ return sha1.New()
+ },
+ },
+ AlgorithmSHA256: {+ name: "sha256",
+ size: sha256.Size,
+ sum: func(data []byte) ObjectID {+ sum := sha256.Sum256(data)
+ var id ObjectID
+ copy(id.data[:], sum[:])
+ id.algo = AlgorithmSHA256
+ return id
+ },
+ new: func() hash.Hash {+ return sha256.New()
+ },
+ },
+}
+
+var algorithmByName = map[string]Algorithm{}+
+func init() {+ for algo, info := range algorithmTable {+ if info.name == "" {+ continue
+ }
+ algorithmByName[info.name] = Algorithm(algo)
+ }
+}
+
+func (algo Algorithm) info() algorithmDetails {+ return algorithmTable[algo]
+}
+
+// ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256").
+func ParseAlgorithm(s string) (Algorithm, bool) {+ algo, ok := algorithmByName[s]
+ return algo, ok
+}
+
+// Size returns the hash size in bytes.
+func (algo Algorithm) Size() int {+ return algo.info().size
+}
+
+// String returns the canonical algorithm name.
+func (algo Algorithm) String() string {+ inf := algo.info()
+ if inf.name == "" {+ return "unknown"
+ }
+ return inf.name
+}
+
+// HexLen returns the encoded hexadecimal length.
+func (algo Algorithm) HexLen() int {+ return algo.Size() * 2
+}
+
+// Sum computes an object ID from raw data using the selected algorithm.
+func (algo Algorithm) Sum(data []byte) ObjectID {+ return algo.info().sum(data)
+}
+
+// New returns a new hash.Hash for this algorithm.
+func (algo Algorithm) New() (hash.Hash, error) {+ newFn := algo.info().new
+ if newFn == nil {+ return nil, ErrInvalidAlgorithm
+ }
+ return newFn(), nil
+}
+
+// ObjectID represents a Git object ID.
+type ObjectID struct {+ algo Algorithm
+ data [maxObjectIDSize]byte
+}
+
+// Algorithm returns the object ID's hash algorithm.
+func (id ObjectID) Algorithm() Algorithm {+ return id.algo
+}
+
+// Size returns the object ID size in bytes.
+func (id ObjectID) Size() int {+ return id.algo.Size()
+}
+
+// String returns the canonical hex representation.
+func (id ObjectID) String() string {+ size := id.Size()
+ return hex.EncodeToString(id.data[:size])
+}
+
+// Bytes returns a copy of the object ID bytes.
+func (id ObjectID) Bytes() []byte {+ size := id.Size()
+ return append([]byte(nil), id.data[:size]...)
+}
+
+// ParseHex parses an object ID from hex for the specified algorithm.
+func ParseHex(algo Algorithm, s string) (ObjectID, error) {+ var id ObjectID
+ if algo.Size() == 0 {+ return id, ErrInvalidAlgorithm
+ }
+ if len(s)%2 != 0 {+ return id, fmt.Errorf("%w: odd hex length %d", ErrInvalidObjectID, len(s))+ }
+ if len(s) != algo.HexLen() {+ return id, fmt.Errorf("%w: got %d chars, expected %d", ErrInvalidObjectID, len(s), algo.HexLen())+ }
+ decoded, err := hex.DecodeString(s)
+ if err != nil {+ return id, fmt.Errorf("%w: decode: %v", ErrInvalidObjectID, err)+ }
+ copy(id.data[:], decoded)
+ id.algo = algo
+ return id, nil
+}
+
+// FromBytes builds an object ID from raw bytes for the specified algorithm.
+func FromBytes(algo Algorithm, b []byte) (ObjectID, error) {+ var id ObjectID
+ if algo.Size() == 0 {+ return id, ErrInvalidAlgorithm
+ }
+ if len(b) != algo.Size() {+ return id, fmt.Errorf("%w: got %d bytes, expected %d", ErrInvalidObjectID, len(b), algo.Size())+ }
+ copy(id.data[:], b)
+ id.algo = algo
+ return id, nil
+}
--- /dev/null
+++ b/objectid/objectid_test.go
@@ -1,0 +1,144 @@
+package objectid
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestParseAlgorithm(t *testing.T) {+ t.Parallel()
+
+ algo, ok := ParseAlgorithm("sha1")+ if !ok || algo != AlgorithmSHA1 {+ t.Fatalf("ParseAlgorithm(sha1) = (%v,%v)", algo, ok)+ }
+
+ algo, ok = ParseAlgorithm("sha256")+ if !ok || algo != AlgorithmSHA256 {+ t.Fatalf("ParseAlgorithm(sha256) = (%v,%v)", algo, ok)+ }
+
+ if _, ok := ParseAlgorithm("md5"); ok {+ t.Fatalf("ParseAlgorithm(md5) should fail")+ }
+}
+
+func TestParseHexRoundtrip(t *testing.T) {+ t.Parallel()
+
+ tests := []struct {+ name string
+ algo Algorithm
+ hex string
+ }{+ {+ name: "sha1",
+ algo: AlgorithmSHA1,
+ hex: "0123456789abcdef0123456789abcdef01234567",
+ },
+ {+ name: "sha256",
+ algo: AlgorithmSHA256,
+ hex: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+ },
+ }
+
+ for _, tt := range tests {+ t.Run(tt.name, func(t *testing.T) {+ id, err := ParseHex(tt.algo, tt.hex)
+ if err != nil {+ t.Fatalf("ParseHex failed: %v", err)+ }
+ if got := id.String(); got != tt.hex {+ t.Fatalf("String() = %q, want %q", got, tt.hex)+ }
+ if got := id.Size(); got != tt.algo.Size() {+ t.Fatalf("Size() = %d, want %d", got, tt.algo.Size())+ }
+
+ raw := id.Bytes()
+ if len(raw) != tt.algo.Size() {+ t.Fatalf("Bytes len = %d, want %d", len(raw), tt.algo.Size())+ }
+
+ id2, err := FromBytes(tt.algo, raw)
+ if err != nil {+ t.Fatalf("FromBytes failed: %v", err)+ }
+ if id2.String() != tt.hex {+ t.Fatalf("FromBytes roundtrip = %q, want %q", id2.String(), tt.hex)+ }
+ })
+ }
+}
+
+func TestParseHexErrors(t *testing.T) {+ t.Parallel()
+
+ tests := []struct {+ name string
+ algo Algorithm
+ hex string
+ }{+ {"unknown algo", AlgorithmUnknown, "00"},+ {"odd len", AlgorithmSHA1, "0"},+ {"wrong len", AlgorithmSHA1, "0123"},+ {"invalid hex", AlgorithmSHA1, "zz23456789abcdef0123456789abcdef01234567"},+ }
+
+ for _, tt := range tests {+ t.Run(tt.name, func(t *testing.T) {+ if _, err := ParseHex(tt.algo, tt.hex); err == nil {+ t.Fatalf("expected ParseHex error")+ }
+ })
+ }
+}
+
+func TestFromBytesErrors(t *testing.T) {+ t.Parallel()
+
+ if _, err := FromBytes(AlgorithmUnknown, []byte{1, 2}); err == nil {+ t.Fatalf("expected FromBytes unknown algo error")+ }
+ if _, err := FromBytes(AlgorithmSHA1, []byte{1, 2}); err == nil {+ t.Fatalf("expected FromBytes wrong size error")+ }
+}
+
+func TestBytesReturnsCopy(t *testing.T) {+ t.Parallel()
+
+ id, err := ParseHex(AlgorithmSHA1, "0123456789abcdef0123456789abcdef01234567")
+ if err != nil {+ t.Fatalf("ParseHex failed: %v", err)+ }
+
+ b1 := id.Bytes()
+ b2 := id.Bytes()
+ if !bytes.Equal(b1, b2) {+ t.Fatalf("Bytes mismatch")+ }
+ b1[0] ^= 0xff
+ if bytes.Equal(b1, b2) {+ t.Fatalf("Bytes should return independent copies")+ }
+}
+
+func TestAlgorithmSum(t *testing.T) {+ t.Parallel()
+
+ id1 := AlgorithmSHA1.Sum([]byte("hello"))+ if id1.Algorithm() != AlgorithmSHA1 || id1.Size() != AlgorithmSHA1.Size() {+ t.Fatalf("sha1 sum produced invalid object id")+ }
+
+ id2 := AlgorithmSHA256.Sum([]byte("hello"))+ if id2.Algorithm() != AlgorithmSHA256 || id2.Size() != AlgorithmSHA256.Size() {+ t.Fatalf("sha256 sum produced invalid object id")+ }
+
+ if id1.String() == id2.String() {+ t.Fatalf("sha1 and sha256 should differ")+ }
+}
--- a/oid/objectid.go
+++ /dev/null
@@ -1,186 +1,0 @@
-// Package oid provides object ID and algorithm primitives for Git objects.
-package oid
-
-import (
- "crypto/sha1"
- "crypto/sha256"
- "encoding/hex"
- "errors"
- "fmt"
- "hash"
-)
-
-var (
- // ErrInvalidAlgorithm indicates an unsupported object ID algorithm.
- ErrInvalidAlgorithm = errors.New("oid: invalid algorithm")- // ErrInvalidObjectID indicates malformed object ID data.
- ErrInvalidObjectID = errors.New("oid: invalid object id")-)
-
-// maxObjectIDSize MUST be >= the largest supported algorithm size.
-const maxObjectIDSize = sha256.Size
-
-// Algorithm identifies the hash algorithm used for Git object IDs.
-type Algorithm uint8
-
-const (
- AlgorithmUnknown Algorithm = iota
- AlgorithmSHA1
- AlgorithmSHA256
-)
-
-type algorithmDetails struct {- name string
- size int
- sum func([]byte) ObjectID
- new func() hash.Hash
-}
-
-var algorithmTable = [...]algorithmDetails{- AlgorithmUnknown: {},- AlgorithmSHA1: {- name: "sha1",
- size: sha1.Size,
- sum: func(data []byte) ObjectID {- sum := sha1.Sum(data)
- var id ObjectID
- copy(id.data[:], sum[:])
- id.algo = AlgorithmSHA1
- return id
- },
- new: func() hash.Hash {- return sha1.New()
- },
- },
- AlgorithmSHA256: {- name: "sha256",
- size: sha256.Size,
- sum: func(data []byte) ObjectID {- sum := sha256.Sum256(data)
- var id ObjectID
- copy(id.data[:], sum[:])
- id.algo = AlgorithmSHA256
- return id
- },
- new: func() hash.Hash {- return sha256.New()
- },
- },
-}
-
-var algorithmByName = map[string]Algorithm{}-
-func init() {- for algo, info := range algorithmTable {- if info.name == "" {- continue
- }
- algorithmByName[info.name] = Algorithm(algo)
- }
-}
-
-func (algo Algorithm) info() algorithmDetails {- return algorithmTable[algo]
-}
-
-// ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256").
-func ParseAlgorithm(s string) (Algorithm, bool) {- algo, ok := algorithmByName[s]
- return algo, ok
-}
-
-// Size returns the hash size in bytes.
-func (algo Algorithm) Size() int {- return algo.info().size
-}
-
-// String returns the canonical algorithm name.
-func (algo Algorithm) String() string {- inf := algo.info()
- if inf.name == "" {- return "unknown"
- }
- return inf.name
-}
-
-// HexLen returns the encoded hexadecimal length.
-func (algo Algorithm) HexLen() int {- return algo.Size() * 2
-}
-
-// Sum computes an object ID from raw data using the selected algorithm.
-func (algo Algorithm) Sum(data []byte) ObjectID {- return algo.info().sum(data)
-}
-
-// New returns a new hash.Hash for this algorithm.
-func (algo Algorithm) New() (hash.Hash, error) {- newFn := algo.info().new
- if newFn == nil {- return nil, ErrInvalidAlgorithm
- }
- return newFn(), nil
-}
-
-// ObjectID represents a Git object ID.
-type ObjectID struct {- algo Algorithm
- data [maxObjectIDSize]byte
-}
-
-// Algorithm returns the object ID's hash algorithm.
-func (id ObjectID) Algorithm() Algorithm {- return id.algo
-}
-
-// Size returns the object ID size in bytes.
-func (id ObjectID) Size() int {- return id.algo.Size()
-}
-
-// String returns the canonical hex representation.
-func (id ObjectID) String() string {- size := id.Size()
- return hex.EncodeToString(id.data[:size])
-}
-
-// Bytes returns a copy of the object ID bytes.
-func (id ObjectID) Bytes() []byte {- size := id.Size()
- return append([]byte(nil), id.data[:size]...)
-}
-
-// ParseHex parses an object ID from hex for the specified algorithm.
-func ParseHex(algo Algorithm, s string) (ObjectID, error) {- var id ObjectID
- if algo.Size() == 0 {- return id, ErrInvalidAlgorithm
- }
- if len(s)%2 != 0 {- return id, fmt.Errorf("%w: odd hex length %d", ErrInvalidObjectID, len(s))- }
- if len(s) != algo.HexLen() {- return id, fmt.Errorf("%w: got %d chars, expected %d", ErrInvalidObjectID, len(s), algo.HexLen())- }
- decoded, err := hex.DecodeString(s)
- if err != nil {- return id, fmt.Errorf("%w: decode: %v", ErrInvalidObjectID, err)- }
- copy(id.data[:], decoded)
- id.algo = algo
- return id, nil
-}
-
-// FromBytes builds an object ID from raw bytes for the specified algorithm.
-func FromBytes(algo Algorithm, b []byte) (ObjectID, error) {- var id ObjectID
- if algo.Size() == 0 {- return id, ErrInvalidAlgorithm
- }
- if len(b) != algo.Size() {- return id, fmt.Errorf("%w: got %d bytes, expected %d", ErrInvalidObjectID, len(b), algo.Size())- }
- copy(id.data[:], b)
- id.algo = algo
- return id, nil
-}
--- a/oid/objectid_test.go
+++ /dev/null
@@ -1,144 +1,0 @@
-package oid
-
-import (
- "bytes"
- "testing"
-)
-
-func TestParseAlgorithm(t *testing.T) {- t.Parallel()
-
- algo, ok := ParseAlgorithm("sha1")- if !ok || algo != AlgorithmSHA1 {- t.Fatalf("ParseAlgorithm(sha1) = (%v,%v)", algo, ok)- }
-
- algo, ok = ParseAlgorithm("sha256")- if !ok || algo != AlgorithmSHA256 {- t.Fatalf("ParseAlgorithm(sha256) = (%v,%v)", algo, ok)- }
-
- if _, ok := ParseAlgorithm("md5"); ok {- t.Fatalf("ParseAlgorithm(md5) should fail")- }
-}
-
-func TestParseHexRoundtrip(t *testing.T) {- t.Parallel()
-
- tests := []struct {- name string
- algo Algorithm
- hex string
- }{- {- name: "sha1",
- algo: AlgorithmSHA1,
- hex: "0123456789abcdef0123456789abcdef01234567",
- },
- {- name: "sha256",
- algo: AlgorithmSHA256,
- hex: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
- },
- }
-
- for _, tt := range tests {- t.Run(tt.name, func(t *testing.T) {- id, err := ParseHex(tt.algo, tt.hex)
- if err != nil {- t.Fatalf("ParseHex failed: %v", err)- }
- if got := id.String(); got != tt.hex {- t.Fatalf("String() = %q, want %q", got, tt.hex)- }
- if got := id.Size(); got != tt.algo.Size() {- t.Fatalf("Size() = %d, want %d", got, tt.algo.Size())- }
-
- raw := id.Bytes()
- if len(raw) != tt.algo.Size() {- t.Fatalf("Bytes len = %d, want %d", len(raw), tt.algo.Size())- }
-
- id2, err := FromBytes(tt.algo, raw)
- if err != nil {- t.Fatalf("FromBytes failed: %v", err)- }
- if id2.String() != tt.hex {- t.Fatalf("FromBytes roundtrip = %q, want %q", id2.String(), tt.hex)- }
- })
- }
-}
-
-func TestParseHexErrors(t *testing.T) {- t.Parallel()
-
- tests := []struct {- name string
- algo Algorithm
- hex string
- }{- {"unknown algo", AlgorithmUnknown, "00"},- {"odd len", AlgorithmSHA1, "0"},- {"wrong len", AlgorithmSHA1, "0123"},- {"invalid hex", AlgorithmSHA1, "zz23456789abcdef0123456789abcdef01234567"},- }
-
- for _, tt := range tests {- t.Run(tt.name, func(t *testing.T) {- if _, err := ParseHex(tt.algo, tt.hex); err == nil {- t.Fatalf("expected ParseHex error")- }
- })
- }
-}
-
-func TestFromBytesErrors(t *testing.T) {- t.Parallel()
-
- if _, err := FromBytes(AlgorithmUnknown, []byte{1, 2}); err == nil {- t.Fatalf("expected FromBytes unknown algo error")- }
- if _, err := FromBytes(AlgorithmSHA1, []byte{1, 2}); err == nil {- t.Fatalf("expected FromBytes wrong size error")- }
-}
-
-func TestBytesReturnsCopy(t *testing.T) {- t.Parallel()
-
- id, err := ParseHex(AlgorithmSHA1, "0123456789abcdef0123456789abcdef01234567")
- if err != nil {- t.Fatalf("ParseHex failed: %v", err)- }
-
- b1 := id.Bytes()
- b2 := id.Bytes()
- if !bytes.Equal(b1, b2) {- t.Fatalf("Bytes mismatch")- }
- b1[0] ^= 0xff
- if bytes.Equal(b1, b2) {- t.Fatalf("Bytes should return independent copies")- }
-}
-
-func TestAlgorithmSum(t *testing.T) {- t.Parallel()
-
- id1 := AlgorithmSHA1.Sum([]byte("hello"))- if id1.Algorithm() != AlgorithmSHA1 || id1.Size() != AlgorithmSHA1.Size() {- t.Fatalf("sha1 sum produced invalid object id")- }
-
- id2 := AlgorithmSHA256.Sum([]byte("hello"))- if id2.Algorithm() != AlgorithmSHA256 || id2.Size() != AlgorithmSHA256.Size() {- t.Fatalf("sha256 sum produced invalid object id")- }
-
- if id1.String() == id2.String() {- t.Fatalf("sha1 and sha256 should differ")- }
-}
--
⑨