diff options
| author | 2026-03-04 08:26:56 +0800 | |
|---|---|---|
| committer | 2026-03-04 08:59:53 +0800 | |
| commit | ab7501be34032fb9e5c48726a68ae90a917af9eb (patch) | |
| tree | 20d005647569befea8133e953c3270e8fd2a2a5b /objectid | |
| parent | *: gofumpt (diff) | |
| signature | No signature | |
*: Lint
Diffstat (limited to 'objectid')
| -rw-r--r-- | objectid/objectid.go | 21 | ||||
| -rw-r--r-- | objectid/objectid_test.go | 19 |
2 files changed, 36 insertions, 4 deletions
diff --git a/objectid/objectid.go b/objectid/objectid.go index 7ce011f3..c1ebfb2c 100644 --- a/objectid/objectid.go +++ b/objectid/objectid.go @@ -43,9 +43,11 @@ var algorithmTable = [...]algorithmDetails{ size: sha1.Size, sum: func(data []byte) ObjectID { sum := sha1.Sum(data) //#nosec G401 + var id ObjectID copy(id.data[:], sum[:]) id.algo = AlgorithmSHA1 + return id }, new: sha1.New, @@ -55,9 +57,11 @@ var algorithmTable = [...]algorithmDetails{ 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: sha256.New, @@ -69,12 +73,13 @@ var ( supportedAlgorithms []Algorithm ) -func init() { +func init() { //nolint:gochecknoinits for algo := Algorithm(0); int(algo) < len(algorithmTable); algo++ { info := algorithmTable[algo] if info.name == "" { continue } + algorithmByName[info.name] = algo supportedAlgorithms = append(supportedAlgorithms, algo) } @@ -89,6 +94,7 @@ func SupportedAlgorithms() []Algorithm { // ParseAlgorithm parses a canonical algorithm name (e.g. "sha1", "sha256"). func ParseAlgorithm(s string) (Algorithm, bool) { algo, ok := algorithmByName[s] + return algo, ok } @@ -103,6 +109,7 @@ func (algo Algorithm) String() string { if inf.name == "" { return "unknown" } + return inf.name } @@ -122,6 +129,7 @@ func (algo Algorithm) New() (hash.Hash, error) { if newFn == nil { return nil, ErrInvalidAlgorithm } + return newFn(), nil } @@ -150,12 +158,14 @@ func (id ObjectID) Size() int { // 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]...) } @@ -167,6 +177,7 @@ func (id ObjectID) Bytes() []byte { // Use Bytes when an independent copy is required. func (id *ObjectID) RawBytes() []byte { size := id.Size() + return id.data[:size:size] } @@ -176,18 +187,23 @@ func ParseHex(algo Algorithm, s string) (ObjectID, error) { 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: %w", ErrInvalidObjectID, err) } + copy(id.data[:], decoded) id.algo = algo + return id, nil } @@ -197,10 +213,13 @@ func FromBytes(algo Algorithm, b []byte) (ObjectID, error) { 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 } diff --git a/objectid/objectid_test.go b/objectid/objectid_test.go index ef191d39..1c5f337a 100644 --- a/objectid/objectid_test.go +++ b/objectid/objectid_test.go @@ -48,13 +48,16 @@ func TestParseHexRoundtrip(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() + id, err := objectid.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()) } @@ -68,6 +71,7 @@ func TestParseHexRoundtrip(t *testing.T) { 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) } @@ -92,7 +96,9 @@ func TestParseHexErrors(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - if _, err := objectid.ParseHex(tt.algo, tt.hex); err == nil { + + _, err := objectid.ParseHex(tt.algo, tt.hex) + if err == nil { t.Fatalf("expected ParseHex error") } }) @@ -102,10 +108,13 @@ func TestParseHexErrors(t *testing.T) { func TestFromBytesErrors(t *testing.T) { t.Parallel() - if _, err := objectid.FromBytes(objectid.AlgorithmUnknown, []byte{1, 2}); err == nil { + _, err := objectid.FromBytes(objectid.AlgorithmUnknown, []byte{1, 2}) + if err == nil { t.Fatalf("expected FromBytes unknown algo error") } - if _, err := objectid.FromBytes(objectid.AlgorithmSHA1, []byte{1, 2}); err == nil { + + _, err = objectid.FromBytes(objectid.AlgorithmSHA1, []byte{1, 2}) + if err == nil { t.Fatalf("expected FromBytes wrong size error") } } @@ -119,10 +128,12 @@ func TestBytesReturnsCopy(t *testing.T) { } 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") @@ -141,12 +152,14 @@ func TestRawBytesAliasesStorage(t *testing.T) { if len(b) != id.Size() { t.Fatalf("RawBytes len = %d, want %d", len(b), id.Size()) } + if cap(b) != len(b) { t.Fatalf("RawBytes cap = %d, want %d", cap(b), len(b)) } orig := id.String() b[0] ^= 0xff + if id.String() == orig { t.Fatalf("RawBytes should alias object ID storage") } |
