From 93df2fd7651c5abd61e8d77ecf53f9492176bf33 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 13 Nov 2020 16:30:35 +0300 Subject: [PATCH] [#168] refs: Implement binary/JSON encoders/decoders on Checksum Signed-off-by: Leonard Lyubich --- pkg/checksum.go | 32 ++++++++++++++++++++++++++++++++ pkg/checksum_test.go | 33 +++++++++++++++++++++++++++++++++ v2/refs/json.go | 20 ++++++++++++++++++++ v2/refs/json_test.go | 14 ++++++++++++++ v2/refs/marshal.go | 11 +++++++++++ v2/refs/marshal_test.go | 8 ++------ 6 files changed, 112 insertions(+), 6 deletions(-) diff --git a/pkg/checksum.go b/pkg/checksum.go index 2a93b399..4182b712 100644 --- a/pkg/checksum.go +++ b/pkg/checksum.go @@ -77,3 +77,35 @@ func (c *Checksum) ToV2() *refs.Checksum { func EqualChecksums(cs1, cs2 *Checksum) bool { return cs1.GetType() == cs2.GetType() && bytes.Equal(cs1.GetSum(), cs2.GetSum()) } + +// Marshal marshals Checksum into a protobuf binary form. +// +// Buffer is allocated when the argument is empty. +// Otherwise, the first buffer is used. +func (c *Checksum) Marshal(b ...[]byte) ([]byte, error) { + var buf []byte + if len(b) > 0 { + buf = b[0] + } + + return (*refs.Checksum)(c). + StableMarshal(buf) +} + +// Unmarshal unmarshals protobuf binary representation of Checksum. +func (c *Checksum) Unmarshal(data []byte) error { + return (*refs.Checksum)(c). + Unmarshal(data) +} + +// MarshalJSON encodes Checksum to protobuf JSON format. +func (c *Checksum) MarshalJSON() ([]byte, error) { + return (*refs.Checksum)(c). + MarshalJSON() +} + +// UnmarshalJSON decodes Checksum from protobuf JSON format. +func (c *Checksum) UnmarshalJSON(data []byte) error { + return (*refs.Checksum)(c). + UnmarshalJSON(data) +} diff --git a/pkg/checksum_test.go b/pkg/checksum_test.go index 906f68b5..9d402a47 100644 --- a/pkg/checksum_test.go +++ b/pkg/checksum_test.go @@ -9,6 +9,14 @@ import ( "github.com/stretchr/testify/require" ) +func randSHA256(t *testing.T) [sha256.Size]byte { + cSHA256 := [sha256.Size]byte{} + _, err := rand.Read(cSHA256[:]) + require.NoError(t, err) + + return cSHA256 +} + func TestChecksum(t *testing.T) { c := NewChecksum() @@ -58,3 +66,28 @@ func TestEqualChecksums(t *testing.T) { require.False(t, EqualChecksums(cs1, cs2)) } + +func TestChecksumEncoding(t *testing.T) { + cs := NewChecksum() + cs.SetSHA256(randSHA256(t)) + + t.Run("binary", func(t *testing.T) { + data, err := cs.Marshal() + require.NoError(t, err) + + c2 := NewChecksum() + require.NoError(t, c2.Unmarshal(data)) + + require.Equal(t, cs, c2) + }) + + t.Run("json", func(t *testing.T) { + data, err := cs.MarshalJSON() + require.NoError(t, err) + + cs2 := NewChecksum() + require.NoError(t, cs2.UnmarshalJSON(data)) + + require.Equal(t, cs, cs2) + }) +} diff --git a/v2/refs/json.go b/v2/refs/json.go index dd0f8367..bd68cd6d 100644 --- a/v2/refs/json.go +++ b/v2/refs/json.go @@ -124,3 +124,23 @@ func (s *Signature) UnmarshalJSON(data []byte) error { return nil } + +func (c *Checksum) MarshalJSON() ([]byte, error) { + return protojson.MarshalOptions{ + EmitUnpopulated: true, + }.Marshal( + ChecksumToGRPCMessage(c), + ) +} + +func (c *Checksum) UnmarshalJSON(data []byte) error { + msg := new(refs.Checksum) + + if err := protojson.Unmarshal(data, msg); err != nil { + return err + } + + *c = *ChecksumFromGRPCMessage(msg) + + return nil +} diff --git a/v2/refs/json_test.go b/v2/refs/json_test.go index 5671ed2f..b04df1ad 100644 --- a/v2/refs/json_test.go +++ b/v2/refs/json_test.go @@ -81,3 +81,17 @@ func TestSignatureSON(t *testing.T) { require.Equal(t, s, s2) } + +func TestChecksumJSON(t *testing.T) { + cs := new(refs.Checksum) + cs.SetType(refs.SHA256) + cs.SetSum([]byte{1, 2, 3}) + + data, err := cs.MarshalJSON() + require.NoError(t, err) + + cs2 := new(refs.Checksum) + require.NoError(t, cs2.UnmarshalJSON(data)) + + require.Equal(t, cs, cs2) +} diff --git a/v2/refs/marshal.go b/v2/refs/marshal.go index 5f2358ba..3c3ef1e9 100644 --- a/v2/refs/marshal.go +++ b/v2/refs/marshal.go @@ -226,6 +226,17 @@ func (c *Checksum) StableSize() (size int) { return size } +func (c *Checksum) Unmarshal(data []byte) error { + m := new(refs.Checksum) + if err := goproto.Unmarshal(data, m); err != nil { + return err + } + + *c = *ChecksumFromGRPCMessage(m) + + return nil +} + func (s *Signature) StableMarshal(buf []byte) ([]byte, error) { if s == nil { return []byte{}, nil diff --git a/v2/refs/marshal_test.go b/v2/refs/marshal_test.go index 3cead073..3bc2eb27 100644 --- a/v2/refs/marshal_test.go +++ b/v2/refs/marshal_test.go @@ -4,9 +4,7 @@ import ( "testing" "github.com/nspcc-dev/neofs-api-go/v2/refs" - grpc "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc" "github.com/stretchr/testify/require" - goproto "google.golang.org/protobuf/proto" ) func TestOwnerID_StableMarshal(t *testing.T) { @@ -76,7 +74,6 @@ func TestAddress_StableMarshal(t *testing.T) { func TestChecksum_StableMarshal(t *testing.T) { checksumFrom := new(refs.Checksum) - transport := new(grpc.Checksum) t.Run("non empty", func(t *testing.T) { checksumFrom.SetType(refs.TillichZemor) @@ -85,10 +82,9 @@ func TestChecksum_StableMarshal(t *testing.T) { wire, err := checksumFrom.StableMarshal(nil) require.NoError(t, err) - err = goproto.Unmarshal(wire, transport) - require.NoError(t, err) + checksumTo := new(refs.Checksum) + require.NoError(t, checksumTo.Unmarshal(wire)) - checksumTo := refs.ChecksumFromGRPCMessage(transport) require.Equal(t, checksumFrom, checksumTo) }) }