diff --git a/pkg/object/address.go b/pkg/object/address.go index 0c50e4f0..a1c24755 100644 --- a/pkg/object/address.go +++ b/pkg/object/address.go @@ -1,6 +1,9 @@ package object import ( + "strings" + + "github.com/nspcc-dev/neofs-api-go/internal" "github.com/nspcc-dev/neofs-api-go/pkg/container" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/pkg/errors" @@ -9,6 +12,15 @@ import ( // Address represents v2-compatible object address. type Address refs.Address +// ErrBadAddress returns when string representation doesn't +// contains Container.ID and Object.ID separated by `/`. +const ErrBadAddress = internal.Error("address should contains container.ID and object.ID separated with `/`") + +const ( + addressParts = 2 + addressSeparator = "/" +) + // NewAddressFromV2 converts v2 Address message to Address. func NewAddressFromV2(aV2 *refs.Address) *Address { return (*Address)(aV2) @@ -59,3 +71,34 @@ func (a *Address) GetObjectID() *ID { func (a *Address) SetObjectID(id *ID) { (*refs.Address)(a).SetObjectID(id.ToV2()) } + +// Parse converts base58 string representation into Address. +func (a *Address) Parse(s string) error { + var ( + err error + oid = NewID() + cid = container.NewID() + parts = strings.Split(s, addressSeparator) + ) + + if len(parts) != addressParts { + return ErrBadAddress + } else if err = cid.Parse(parts[0]); err != nil { + return err + } else if err = oid.Parse(parts[1]); err != nil { + return err + } + + a.SetObjectID(oid) + a.SetContainerID(cid) + + return nil +} + +// String returns string representation of Object.Address. +func (a *Address) String() string { + return strings.Join([]string{ + a.GetContainerID().String(), + a.GetObjectID().String(), + }, addressSeparator) +} diff --git a/pkg/object/address_test.go b/pkg/object/address_test.go index d286ed48..5b4ae1ba 100644 --- a/pkg/object/address_test.go +++ b/pkg/object/address_test.go @@ -1,6 +1,7 @@ package object import ( + "strings" "testing" "github.com/nspcc-dev/neofs-api-go/pkg/container" @@ -27,3 +28,35 @@ func TestAddress_SetObjectID(t *testing.T) { require.Equal(t, oid, a.GetObjectID()) } + +func TestAddress_Parse(t *testing.T) { + cid := container.NewID() + cid.SetSHA256(randSHA256Checksum(t)) + + oid := NewID() + oid.SetSHA256(randSHA256Checksum(t)) + + t.Run("should parse successful", func(t *testing.T) { + s := strings.Join([]string{cid.String(), oid.String()}, addressSeparator) + a := NewAddress() + + require.NoError(t, a.Parse(s)) + require.Equal(t, oid, a.GetObjectID()) + require.Equal(t, cid, a.GetContainerID()) + }) + + t.Run("should fail for bad address", func(t *testing.T) { + s := strings.Join([]string{cid.String()}, addressSeparator) + require.EqualError(t, NewAddress().Parse(s), ErrBadAddress.Error()) + }) + + t.Run("should fail on container.ID", func(t *testing.T) { + s := strings.Join([]string{"1", "2"}, addressSeparator) + require.EqualError(t, NewAddress().Parse(s), container.ErrBadID.Error()) + }) + + t.Run("should fail on object.ID", func(t *testing.T) { + s := strings.Join([]string{cid.String(), "2"}, addressSeparator) + require.EqualError(t, NewAddress().Parse(s), ErrBadID.Error()) + }) +}