From 27c7fdd5a67eb082d3f44747e589be48c1b1011f Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Thu, 26 Mar 2026 04:39:38 +0000 Subject: object/id: Empty tree --- object/id/algorithms.go | 12 +++++++++++- object/id/objectid_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/object/id/algorithms.go b/object/id/algorithms.go index 404d3bbf..f3540c42 100644 --- a/object/id/algorithms.go +++ b/object/id/algorithms.go @@ -24,6 +24,7 @@ type algorithmDetails struct { packHashID uint32 sum func([]byte) ObjectID new func() hash.Hash + emptyTree ObjectID } //nolint:gochecknoglobals @@ -69,12 +70,15 @@ var ( ) func init() { //nolint:gochecknoinits + emptyTreeInput := []byte("tree 0\x00") + for algo := Algorithm(0); int(algo) < len(algorithmTable); algo++ { - info := algorithmTable[algo] + info := &algorithmTable[algo] if info.name == "" { continue } + info.emptyTree = info.sum(emptyTreeInput) algorithmByName[info.name] = algo supportedAlgorithms = append(supportedAlgorithms, algo) } @@ -135,6 +139,12 @@ func (algo Algorithm) New() (hash.Hash, error) { return newFn(), nil } +// EmptyTree returns the object ID of an empty tree ("tree 0\x00") for this +// algorithm. +func (algo Algorithm) EmptyTree() ObjectID { + return algo.info().emptyTree +} + func (algo Algorithm) info() algorithmDetails { return algorithmTable[algo] } diff --git a/object/id/objectid_test.go b/object/id/objectid_test.go index 2559be0a..dc25832b 100644 --- a/object/id/objectid_test.go +++ b/object/id/objectid_test.go @@ -182,3 +182,48 @@ func TestAlgorithmSum(t *testing.T) { t.Fatalf("sha1 and sha256 should differ") } } + +func TestAlgorithmEmptyTree(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + algo objectid.Algorithm + want string + }{ + { + name: "sha1", + algo: objectid.AlgorithmSHA1, + want: "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + }, + { + name: "sha256", + algo: objectid.AlgorithmSHA256, + want: "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got := tt.algo.EmptyTree() + if got.Algorithm() != tt.algo { + t.Fatalf("EmptyTree() algorithm = %v, want %v", got.Algorithm(), tt.algo) + } + + if got.String() != tt.want { + t.Fatalf("EmptyTree() = %q, want %q", got.String(), tt.want) + } + }) + } +} + +func TestUnknownAlgorithmEmptyTree(t *testing.T) { + t.Parallel() + + got := objectid.AlgorithmUnknown.EmptyTree() + if got != (objectid.ObjectID{}) { + t.Fatalf("EmptyTree() for unknown algorithm = %#v, want zero value", got) + } +} -- cgit v1.3.1-10-gc9f91