github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/runtime/marshal_json_test.go (about) 1 package runtime_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "reflect" 7 "strings" 8 "testing" 9 10 "github.com/google/go-cmp/cmp" 11 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 12 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime/internal/examplepb" 13 "google.golang.org/protobuf/proto" 14 "google.golang.org/protobuf/testing/protocmp" 15 "google.golang.org/protobuf/types/known/emptypb" 16 "google.golang.org/protobuf/types/known/timestamppb" 17 "google.golang.org/protobuf/types/known/wrapperspb" 18 ) 19 20 func TestJSONBuiltinMarshal(t *testing.T) { 21 var m runtime.JSONBuiltin 22 msg := &examplepb.SimpleMessage{ 23 Id: "foo", 24 } 25 26 buf, err := m.Marshal(msg) 27 if err != nil { 28 t.Errorf("m.Marshal(%v) failed with %v; want success", msg, err) 29 } 30 31 got := new(examplepb.SimpleMessage) 32 if err := json.Unmarshal(buf, got); err != nil { 33 t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf, err) 34 } 35 if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { 36 t.Error(diff) 37 } 38 } 39 40 func TestJSONBuiltinMarshalField(t *testing.T) { 41 var m runtime.JSONBuiltin 42 for _, fixt := range builtinFieldFixtures { 43 buf, err := m.Marshal(fixt.data) 44 if err != nil { 45 t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) 46 } 47 if got, want := string(buf), fixt.json; got != want { 48 t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) 49 } 50 } 51 } 52 53 func TestJSONBuiltinMarshalFieldKnownErrors(t *testing.T) { 54 var m runtime.JSONBuiltin 55 for _, fixt := range builtinKnownErrors { 56 buf, err := m.Marshal(fixt.data) 57 if err != nil { 58 t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err) 59 } 60 if got, want := string(buf), fixt.json; got == want { 61 t.Errorf("surprisingly got = %q; as want %q; data = %#v", got, want, fixt.data) 62 } 63 } 64 } 65 66 func TestJSONBuiltinsnmarshal(t *testing.T) { 67 var ( 68 m runtime.JSONBuiltin 69 got = new(examplepb.SimpleMessage) 70 71 data = []byte(`{"id": "foo"}`) 72 ) 73 if err := m.Unmarshal(data, got); err != nil { 74 t.Errorf("m.Unmarshal(%q, got) failed with %v; want success", data, err) 75 } 76 77 want := &examplepb.SimpleMessage{ 78 Id: "foo", 79 } 80 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 81 t.Errorf(diff) 82 } 83 } 84 85 func TestJSONBuiltinUnmarshalField(t *testing.T) { 86 var m runtime.JSONBuiltin 87 for _, fixt := range builtinFieldFixtures { 88 dest := alloc(reflect.TypeOf(fixt.data)) 89 if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil { 90 t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", fixt.json, err) 91 } 92 93 got, want := dest.Elem().Interface(), fixt.data 94 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 95 t.Error(diff) 96 } 97 } 98 } 99 100 func alloc(t reflect.Type) reflect.Value { 101 if t == nil { 102 return reflect.ValueOf(new(interface{})) 103 } 104 return reflect.New(t) 105 } 106 107 func TestJSONBuiltinUnmarshalFieldKnownErrors(t *testing.T) { 108 var m runtime.JSONBuiltin 109 for _, fixt := range builtinKnownErrors { 110 dest := reflect.New(reflect.TypeOf(fixt.data)) 111 if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err == nil { 112 t.Errorf("m.Unmarshal(%q, dest) succeeded; want ane error", fixt.json) 113 } 114 } 115 } 116 117 func TestJSONBuiltinEncoder(t *testing.T) { 118 var m runtime.JSONBuiltin 119 msg := &examplepb.SimpleMessage{ 120 Id: "foo", 121 } 122 123 var buf bytes.Buffer 124 enc := m.NewEncoder(&buf) 125 if err := enc.Encode(msg); err != nil { 126 t.Errorf("enc.Encode(%v) failed with %v; want success", msg, err) 127 } 128 129 got := new(examplepb.SimpleMessage) 130 if err := json.Unmarshal(buf.Bytes(), got); err != nil { 131 t.Errorf("json.Unmarshal(%q, got) failed with %v; want success", buf.String(), err) 132 } 133 if diff := cmp.Diff(got, msg, protocmp.Transform()); diff != "" { 134 t.Error(diff) 135 } 136 } 137 138 func TestJSONBuiltinEncoderFields(t *testing.T) { 139 var m runtime.JSONBuiltin 140 for _, fixt := range builtinFieldFixtures { 141 var buf bytes.Buffer 142 enc := m.NewEncoder(&buf) 143 if err := enc.Encode(fixt.data); err != nil { 144 t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err) 145 } 146 147 if got, want := buf.String(), fixt.json+"\n"; got != want { 148 t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data) 149 } 150 } 151 } 152 153 func TestJSONBuiltinDecoder(t *testing.T) { 154 var ( 155 m runtime.JSONBuiltin 156 got = new(examplepb.SimpleMessage) 157 158 data = `{"id": "foo"}` 159 ) 160 r := strings.NewReader(data) 161 dec := m.NewDecoder(r) 162 if err := dec.Decode(got); err != nil { 163 t.Errorf("m.Unmarshal(got) failed with %v; want success", err) 164 } 165 166 want := &examplepb.SimpleMessage{ 167 Id: "foo", 168 } 169 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 170 t.Errorf("got = %v; want = %v", got, want) 171 } 172 } 173 174 func TestJSONBuiltinDecoderFields(t *testing.T) { 175 var m runtime.JSONBuiltin 176 for _, fixt := range builtinFieldFixtures { 177 r := strings.NewReader(fixt.json) 178 dec := m.NewDecoder(r) 179 dest := alloc(reflect.TypeOf(fixt.data)) 180 if err := dec.Decode(dest.Interface()); err != nil { 181 t.Errorf("dec.Decode(dest) failed with %v; want success; data = %q", err, fixt.json) 182 } 183 184 got, want := dest.Elem().Interface(), fixt.data 185 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 186 t.Error(diff) 187 } 188 } 189 } 190 191 var ( 192 builtinFieldFixtures = []struct { 193 data interface{} 194 json string 195 }{ 196 {data: "", json: `""`}, 197 {data: proto.String(""), json: `""`}, 198 {data: "foo", json: `"foo"`}, 199 {data: []byte("foo"), json: `"Zm9v"`}, 200 {data: []byte{}, json: `""`}, 201 {data: proto.String("foo"), json: `"foo"`}, 202 {data: int32(-1), json: "-1"}, 203 {data: proto.Int32(-1), json: "-1"}, 204 {data: int64(-1), json: "-1"}, 205 {data: proto.Int64(-1), json: "-1"}, 206 {data: uint32(123), json: "123"}, 207 {data: proto.Uint32(123), json: "123"}, 208 {data: uint64(123), json: "123"}, 209 {data: proto.Uint64(123), json: "123"}, 210 {data: float32(-1.5), json: "-1.5"}, 211 {data: proto.Float32(-1.5), json: "-1.5"}, 212 {data: float64(-1.5), json: "-1.5"}, 213 {data: proto.Float64(-1.5), json: "-1.5"}, 214 {data: true, json: "true"}, 215 {data: proto.Bool(true), json: "true"}, 216 {data: (*string)(nil), json: "null"}, 217 {data: new(emptypb.Empty), json: "{}"}, 218 {data: examplepb.NumericEnum_ONE, json: "1"}, 219 {data: nil, json: "null"}, 220 {data: (*string)(nil), json: "null"}, 221 {data: []interface{}{nil, "foo", -1.0, 1.234, true}, json: `[null,"foo",-1,1.234,true]`}, 222 { 223 data: map[string]interface{}{"bar": nil, "baz": -1.0, "fiz": 1.234, "foo": true}, 224 json: `{"bar":null,"baz":-1,"fiz":1.234,"foo":true}`, 225 }, 226 { 227 data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), 228 json: "1", 229 }, 230 } 231 builtinKnownErrors = []struct { 232 data interface{} 233 json string 234 }{ 235 {data: examplepb.NumericEnum_ONE, json: "ONE"}, 236 { 237 data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))), 238 json: "ONE", 239 }, 240 { 241 data: &examplepb.ABitOfEverything_OneofString{OneofString: "abc"}, 242 json: `"abc"`, 243 }, 244 { 245 data: ×tamppb.Timestamp{ 246 Seconds: 1462875553, 247 Nanos: 123000000, 248 }, 249 json: `"2016-05-10T10:19:13.123Z"`, 250 }, 251 { 252 data: wrapperspb.Int32(123), 253 json: "123", 254 }, 255 } 256 )