Skip to content

Commit

Permalink
marshal_jsonpb: Added nil slice default value (#854)
Browse files Browse the repository at this point in the history
* marshal_jsonpb: Added nil slice default value

* marshal_jsonpb: reduced indentation
  • Loading branch information
abice authored and johanbrandhorst committed Jan 18, 2019
1 parent a0500cb commit ff4dc68
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 18 deletions.
68 changes: 50 additions & 18 deletions examples/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1360,25 +1360,57 @@ func testResponseBodies(t *testing.T, port int) {
}

func testResponseStrings(t *testing.T, port int) {
url := fmt.Sprintf("http://localhost:%d/responsestrings/foo", port)
resp, err := http.Get(url)
if err != nil {
t.Errorf("http.Get(%q) failed with %v; want success", url, err)
return
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err)
return
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Run Secondary server with different marshalling
ch := make(chan error)
go func() {
if err := runGateway(ctx, ":8081", runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{EmitDefaults: true})); err != nil {
ch <- fmt.Errorf("cannot run gateway service: %v", err)
}
}()

if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("resp.StatusCode = %d; want %d", got, want)
t.Logf("%s", buf)
}
port = 8081

if got, want := string(buf), `["hello","foo"]`; got != want {
t.Errorf("response = %q; want %q", got, want)
for i, spec := range []struct {
endpoint string
expectedCode int
expectedBody string
}{
{
endpoint: fmt.Sprintf("http://localhost:%d/responsestrings/foo", port),
expectedCode: http.StatusOK,
expectedBody: `["hello","foo"]`,
},
{
endpoint: fmt.Sprintf("http://localhost:%d/responsestrings/empty", port),
expectedCode: http.StatusOK,
expectedBody: `[]`,
},
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
url := spec.endpoint
resp, err := http.Get(url)
if err != nil {
t.Errorf("http.Get(%q) failed with %v; want success", url, err)
return
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err)
return
}

if got, want := resp.StatusCode, spec.expectedCode; got != want {
t.Errorf("resp.StatusCode = %d; want %d", got, want)
t.Logf("%s", buf)
}

if got, want := string(buf), spec.expectedBody; got != want {
t.Errorf("response = %q; want %q", got, want)
}
})
}

}
5 changes: 5 additions & 0 deletions examples/server/responsebody.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ func (s *responseBodyServer) ListResponseBodies(ctx context.Context, req *exampl
}

func (s *responseBodyServer) ListResponseStrings(ctx context.Context, req *examples.ResponseBodyIn) (*examples.RepeatedResponseStrings, error) {
if req.Data == "empty" {
return &examples.RepeatedResponseStrings{
Values: []string{},
}, nil
}
return &examples.RepeatedResponseStrings{
Values: []string{"hello", req.Data},
}, nil
Expand Down
4 changes: 4 additions & 0 deletions runtime/marshal_jsonpb.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
rv = rv.Elem()
}

if rv.Kind() == reflect.Slice && rv.IsNil() && j.EmitDefaults {
return []byte("[]"), nil
}

if rv.Kind() == reflect.Map {
m := make(map[string]*json.RawMessage)
for _, k := range rv.MapKeys() {
Expand Down
130 changes: 130 additions & 0 deletions runtime/marshal_jsonpb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package runtime_test
import (
"bytes"
"reflect"
"strconv"
"strings"
"testing"

Expand Down Expand Up @@ -614,3 +615,132 @@ var (
// TODO(yugui) Add other well-known types once jsonpb supports them
}
)

func TestJSONPbMarshalResponseBodies(t *testing.T) {
for i, spec := range []struct {
input interface{}
emitDefaults bool
verifier func(json string)
}{
{
input: &examplepb.ResponseBodyOut{
Response: &examplepb.ResponseBodyOut_Response{Data: "abcdef"},
},
verifier: func(json string) {
expected := `{"response":{"data":"abcdef"}}`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
emitDefaults: true,
input: &examplepb.ResponseBodyOut{},
verifier: func(json string) {
expected := `{"response":null}`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
input: &examplepb.RepeatedResponseBodyOut_Response{},
verifier: func(json string) {
expected := `{}`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
emitDefaults: true,
input: &examplepb.RepeatedResponseBodyOut_Response{},
verifier: func(json string) {
expected := `{"data":""}`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil),
verifier: func(json string) {
expected := `null`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
emitDefaults: true,
input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil),
verifier: func(json string) {
expected := `[]`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
input: []*examplepb.RepeatedResponseBodyOut_Response{},
verifier: func(json string) {
expected := `[]`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
input: []string{"something"},
verifier: func(json string) {
expected := `["something"]`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
input: []string{},
verifier: func(json string) {
expected := `[]`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
input: ([]string)(nil),
verifier: func(json string) {
expected := `null`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
{
emitDefaults: true,
input: ([]string)(nil),
verifier: func(json string) {
expected := `[]`
if json != expected {
t.Errorf("json not equal (%q, %q)", json, expected)
}
},
},
} {

t.Run(strconv.Itoa(i), func(t *testing.T) {
m := runtime.JSONPb{
EmitDefaults: spec.emitDefaults,
}
val := spec.input
buf, err := m.Marshal(val)
if err != nil {
t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", val, err, spec)
}
if spec.verifier != nil {
spec.verifier(string(buf))
}
})
}
}

0 comments on commit ff4dc68

Please sign in to comment.