From b94ea975f3beb73799fac17cc24ee923fcd3cb5c Mon Sep 17 00:00:00 2001 From: Fabian Holler Date: Fri, 1 Jun 2018 19:56:55 +0200 Subject: [PATCH] codes: fix: marshal/unmarshal a Code to JSON fails (#2116) Marshalling a Code to JSON and unmarshalling it failed with an "invalid code" error message. Code is of type uint32. It has no custom MarshalJson() implemented therefore it is marshalled into an JSON integer value. The UnmarshalJSON() function expected that the marshalled Code is a String type, unmarshalling failed. Check in UnmarshalJSON() if the value is an uint32 in the range of the defined Code values. If it is, unmarshal it. This commit also adds an Marshal/Unmarshal testcase. --- codes/codes.go | 13 +++++++++++++ codes/codes_test.go | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/codes/codes.go b/codes/codes.go index a8280ae6..d9b9d578 100644 --- a/codes/codes.go +++ b/codes/codes.go @@ -22,6 +22,7 @@ package codes // import "google.golang.org/grpc/codes" import ( "fmt" + "strconv" ) // A Code is an unsigned 32-bit error code as defined in the gRPC spec. @@ -143,6 +144,8 @@ const ( // Unauthenticated indicates the request does not have valid // authentication credentials for the operation. Unauthenticated Code = 16 + + _maxCode = 17 ) var strToCode = map[string]Code{ @@ -176,6 +179,16 @@ func (c *Code) UnmarshalJSON(b []byte) error { if c == nil { return fmt.Errorf("nil receiver passed to UnmarshalJSON") } + + if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil { + if ci >= _maxCode { + return fmt.Errorf("invalid code: %q", ci) + } + + *c = Code(ci) + return nil + } + if jc, ok := strToCode[string(b)]; ok { *c = jc return nil diff --git a/codes/codes_test.go b/codes/codes_test.go index 1e3b9918..d3e32d22 100644 --- a/codes/codes_test.go +++ b/codes/codes_test.go @@ -62,3 +62,23 @@ func TestUnmarshalJSON_UnknownInput(t *testing.T) { } } } + +func TestUnmarshalJSON_MarshalUnmarshal(t *testing.T) { + for i := 0; i < _maxCode; i++ { + var cUnMarshaled Code + c := Code(i) + + cJSON, err := json.Marshal(c) + if err != nil { + t.Errorf("marshalling %q failed: %v", c, err) + } + + if err := json.Unmarshal(cJSON, &cUnMarshaled); err != nil { + t.Errorf("unmarshalling code failed: %s", err) + } + + if c != cUnMarshaled { + t.Errorf("code is %q after marshalling/unmarshalling, expected %q", cUnMarshaled, c) + } + } +}