Home | History | Annotate | Download | only in jsonpb
      1 // Go support for Protocol Buffers - Google's data interchange format
      2 //
      3 // Copyright 2015 The Go Authors.  All rights reserved.
      4 // https://github.com/golang/protobuf
      5 //
      6 // Redistribution and use in source and binary forms, with or without
      7 // modification, are permitted provided that the following conditions are
      8 // met:
      9 //
     10 //     * Redistributions of source code must retain the above copyright
     11 // notice, this list of conditions and the following disclaimer.
     12 //     * Redistributions in binary form must reproduce the above
     13 // copyright notice, this list of conditions and the following disclaimer
     14 // in the documentation and/or other materials provided with the
     15 // distribution.
     16 //     * Neither the name of Google Inc. nor the names of its
     17 // contributors may be used to endorse or promote products derived from
     18 // this software without specific prior written permission.
     19 //
     20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 package jsonpb
     33 
     34 import (
     35 	"bytes"
     36 	"encoding/json"
     37 	"io"
     38 	"math"
     39 	"reflect"
     40 	"strings"
     41 	"testing"
     42 
     43 	"github.com/golang/protobuf/proto"
     44 
     45 	pb "github.com/golang/protobuf/jsonpb/jsonpb_test_proto"
     46 	proto3pb "github.com/golang/protobuf/proto/proto3_proto"
     47 	"github.com/golang/protobuf/ptypes"
     48 	anypb "github.com/golang/protobuf/ptypes/any"
     49 	durpb "github.com/golang/protobuf/ptypes/duration"
     50 	stpb "github.com/golang/protobuf/ptypes/struct"
     51 	tspb "github.com/golang/protobuf/ptypes/timestamp"
     52 	wpb "github.com/golang/protobuf/ptypes/wrappers"
     53 )
     54 
     55 var (
     56 	marshaler = Marshaler{}
     57 
     58 	marshalerAllOptions = Marshaler{
     59 		Indent: "  ",
     60 	}
     61 
     62 	simpleObject = &pb.Simple{
     63 		OInt32:  proto.Int32(-32),
     64 		OInt64:  proto.Int64(-6400000000),
     65 		OUint32: proto.Uint32(32),
     66 		OUint64: proto.Uint64(6400000000),
     67 		OSint32: proto.Int32(-13),
     68 		OSint64: proto.Int64(-2600000000),
     69 		OFloat:  proto.Float32(3.14),
     70 		ODouble: proto.Float64(6.02214179e23),
     71 		OBool:   proto.Bool(true),
     72 		OString: proto.String("hello \"there\""),
     73 		OBytes:  []byte("beep boop"),
     74 	}
     75 
     76 	simpleObjectJSON = `{` +
     77 		`"oBool":true,` +
     78 		`"oInt32":-32,` +
     79 		`"oInt64":"-6400000000",` +
     80 		`"oUint32":32,` +
     81 		`"oUint64":"6400000000",` +
     82 		`"oSint32":-13,` +
     83 		`"oSint64":"-2600000000",` +
     84 		`"oFloat":3.14,` +
     85 		`"oDouble":6.02214179e+23,` +
     86 		`"oString":"hello \"there\"",` +
     87 		`"oBytes":"YmVlcCBib29w"` +
     88 		`}`
     89 
     90 	simpleObjectPrettyJSON = `{
     91   "oBool": true,
     92   "oInt32": -32,
     93   "oInt64": "-6400000000",
     94   "oUint32": 32,
     95   "oUint64": "6400000000",
     96   "oSint32": -13,
     97   "oSint64": "-2600000000",
     98   "oFloat": 3.14,
     99   "oDouble": 6.02214179e+23,
    100   "oString": "hello \"there\"",
    101   "oBytes": "YmVlcCBib29w"
    102 }`
    103 
    104 	repeatsObject = &pb.Repeats{
    105 		RBool:   []bool{true, false, true},
    106 		RInt32:  []int32{-3, -4, -5},
    107 		RInt64:  []int64{-123456789, -987654321},
    108 		RUint32: []uint32{1, 2, 3},
    109 		RUint64: []uint64{6789012345, 3456789012},
    110 		RSint32: []int32{-1, -2, -3},
    111 		RSint64: []int64{-6789012345, -3456789012},
    112 		RFloat:  []float32{3.14, 6.28},
    113 		RDouble: []float64{299792458 * 1e20, 6.62606957e-34},
    114 		RString: []string{"happy", "days"},
    115 		RBytes:  [][]byte{[]byte("skittles"), []byte("m&m's")},
    116 	}
    117 
    118 	repeatsObjectJSON = `{` +
    119 		`"rBool":[true,false,true],` +
    120 		`"rInt32":[-3,-4,-5],` +
    121 		`"rInt64":["-123456789","-987654321"],` +
    122 		`"rUint32":[1,2,3],` +
    123 		`"rUint64":["6789012345","3456789012"],` +
    124 		`"rSint32":[-1,-2,-3],` +
    125 		`"rSint64":["-6789012345","-3456789012"],` +
    126 		`"rFloat":[3.14,6.28],` +
    127 		`"rDouble":[2.99792458e+28,6.62606957e-34],` +
    128 		`"rString":["happy","days"],` +
    129 		`"rBytes":["c2tpdHRsZXM=","bSZtJ3M="]` +
    130 		`}`
    131 
    132 	repeatsObjectPrettyJSON = `{
    133   "rBool": [
    134     true,
    135     false,
    136     true
    137   ],
    138   "rInt32": [
    139     -3,
    140     -4,
    141     -5
    142   ],
    143   "rInt64": [
    144     "-123456789",
    145     "-987654321"
    146   ],
    147   "rUint32": [
    148     1,
    149     2,
    150     3
    151   ],
    152   "rUint64": [
    153     "6789012345",
    154     "3456789012"
    155   ],
    156   "rSint32": [
    157     -1,
    158     -2,
    159     -3
    160   ],
    161   "rSint64": [
    162     "-6789012345",
    163     "-3456789012"
    164   ],
    165   "rFloat": [
    166     3.14,
    167     6.28
    168   ],
    169   "rDouble": [
    170     2.99792458e+28,
    171     6.62606957e-34
    172   ],
    173   "rString": [
    174     "happy",
    175     "days"
    176   ],
    177   "rBytes": [
    178     "c2tpdHRsZXM=",
    179     "bSZtJ3M="
    180   ]
    181 }`
    182 
    183 	innerSimple   = &pb.Simple{OInt32: proto.Int32(-32)}
    184 	innerSimple2  = &pb.Simple{OInt64: proto.Int64(25)}
    185 	innerRepeats  = &pb.Repeats{RString: []string{"roses", "red"}}
    186 	innerRepeats2 = &pb.Repeats{RString: []string{"violets", "blue"}}
    187 	complexObject = &pb.Widget{
    188 		Color:    pb.Widget_GREEN.Enum(),
    189 		RColor:   []pb.Widget_Color{pb.Widget_RED, pb.Widget_GREEN, pb.Widget_BLUE},
    190 		Simple:   innerSimple,
    191 		RSimple:  []*pb.Simple{innerSimple, innerSimple2},
    192 		Repeats:  innerRepeats,
    193 		RRepeats: []*pb.Repeats{innerRepeats, innerRepeats2},
    194 	}
    195 
    196 	complexObjectJSON = `{"color":"GREEN",` +
    197 		`"rColor":["RED","GREEN","BLUE"],` +
    198 		`"simple":{"oInt32":-32},` +
    199 		`"rSimple":[{"oInt32":-32},{"oInt64":"25"}],` +
    200 		`"repeats":{"rString":["roses","red"]},` +
    201 		`"rRepeats":[{"rString":["roses","red"]},{"rString":["violets","blue"]}]` +
    202 		`}`
    203 
    204 	complexObjectPrettyJSON = `{
    205   "color": "GREEN",
    206   "rColor": [
    207     "RED",
    208     "GREEN",
    209     "BLUE"
    210   ],
    211   "simple": {
    212     "oInt32": -32
    213   },
    214   "rSimple": [
    215     {
    216       "oInt32": -32
    217     },
    218     {
    219       "oInt64": "25"
    220     }
    221   ],
    222   "repeats": {
    223     "rString": [
    224       "roses",
    225       "red"
    226     ]
    227   },
    228   "rRepeats": [
    229     {
    230       "rString": [
    231         "roses",
    232         "red"
    233       ]
    234     },
    235     {
    236       "rString": [
    237         "violets",
    238         "blue"
    239       ]
    240     }
    241   ]
    242 }`
    243 
    244 	colorPrettyJSON = `{
    245  "color": 2
    246 }`
    247 
    248 	colorListPrettyJSON = `{
    249   "color": 1000,
    250   "rColor": [
    251     "RED"
    252   ]
    253 }`
    254 
    255 	nummyPrettyJSON = `{
    256   "nummy": {
    257     "1": 2,
    258     "3": 4
    259   }
    260 }`
    261 
    262 	objjyPrettyJSON = `{
    263   "objjy": {
    264     "1": {
    265       "dub": 1
    266     }
    267   }
    268 }`
    269 	realNumber     = &pb.Real{Value: proto.Float64(3.14159265359)}
    270 	realNumberName = "Pi"
    271 	complexNumber  = &pb.Complex{Imaginary: proto.Float64(0.5772156649)}
    272 	realNumberJSON = `{` +
    273 		`"value":3.14159265359,` +
    274 		`"[jsonpb.Complex.real_extension]":{"imaginary":0.5772156649},` +
    275 		`"[jsonpb.name]":"Pi"` +
    276 		`}`
    277 
    278 	anySimple = &pb.KnownTypes{
    279 		An: &anypb.Any{
    280 			TypeUrl: "something.example.com/jsonpb.Simple",
    281 			Value: []byte{
    282 				// &pb.Simple{OBool:true}
    283 				1 << 3, 1,
    284 			},
    285 		},
    286 	}
    287 	anySimpleJSON       = `{"an":{"@type":"something.example.com/jsonpb.Simple","oBool":true}}`
    288 	anySimplePrettyJSON = `{
    289   "an": {
    290     "@type": "something.example.com/jsonpb.Simple",
    291     "oBool": true
    292   }
    293 }`
    294 
    295 	anyWellKnown = &pb.KnownTypes{
    296 		An: &anypb.Any{
    297 			TypeUrl: "type.googleapis.com/google.protobuf.Duration",
    298 			Value: []byte{
    299 				// &durpb.Duration{Seconds: 1, Nanos: 212000000 }
    300 				1 << 3, 1, // seconds
    301 				2 << 3, 0x80, 0xba, 0x8b, 0x65, // nanos
    302 			},
    303 		},
    304 	}
    305 	anyWellKnownJSON       = `{"an":{"@type":"type.googleapis.com/google.protobuf.Duration","value":"1.212s"}}`
    306 	anyWellKnownPrettyJSON = `{
    307   "an": {
    308     "@type": "type.googleapis.com/google.protobuf.Duration",
    309     "value": "1.212s"
    310   }
    311 }`
    312 
    313 	nonFinites = &pb.NonFinites{
    314 		FNan:  proto.Float32(float32(math.NaN())),
    315 		FPinf: proto.Float32(float32(math.Inf(1))),
    316 		FNinf: proto.Float32(float32(math.Inf(-1))),
    317 		DNan:  proto.Float64(float64(math.NaN())),
    318 		DPinf: proto.Float64(float64(math.Inf(1))),
    319 		DNinf: proto.Float64(float64(math.Inf(-1))),
    320 	}
    321 	nonFinitesJSON = `{` +
    322 		`"fNan":"NaN",` +
    323 		`"fPinf":"Infinity",` +
    324 		`"fNinf":"-Infinity",` +
    325 		`"dNan":"NaN",` +
    326 		`"dPinf":"Infinity",` +
    327 		`"dNinf":"-Infinity"` +
    328 		`}`
    329 )
    330 
    331 func init() {
    332 	if err := proto.SetExtension(realNumber, pb.E_Name, &realNumberName); err != nil {
    333 		panic(err)
    334 	}
    335 	if err := proto.SetExtension(realNumber, pb.E_Complex_RealExtension, complexNumber); err != nil {
    336 		panic(err)
    337 	}
    338 }
    339 
    340 var marshalingTests = []struct {
    341 	desc      string
    342 	marshaler Marshaler
    343 	pb        proto.Message
    344 	json      string
    345 }{
    346 	{"simple flat object", marshaler, simpleObject, simpleObjectJSON},
    347 	{"simple pretty object", marshalerAllOptions, simpleObject, simpleObjectPrettyJSON},
    348 	{"non-finite floats fields object", marshaler, nonFinites, nonFinitesJSON},
    349 	{"repeated fields flat object", marshaler, repeatsObject, repeatsObjectJSON},
    350 	{"repeated fields pretty object", marshalerAllOptions, repeatsObject, repeatsObjectPrettyJSON},
    351 	{"nested message/enum flat object", marshaler, complexObject, complexObjectJSON},
    352 	{"nested message/enum pretty object", marshalerAllOptions, complexObject, complexObjectPrettyJSON},
    353 	{"enum-string flat object", Marshaler{},
    354 		&pb.Widget{Color: pb.Widget_BLUE.Enum()}, `{"color":"BLUE"}`},
    355 	{"enum-value pretty object", Marshaler{EnumsAsInts: true, Indent: " "},
    356 		&pb.Widget{Color: pb.Widget_BLUE.Enum()}, colorPrettyJSON},
    357 	{"unknown enum value object", marshalerAllOptions,
    358 		&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}, colorListPrettyJSON},
    359 	{"repeated proto3 enum", Marshaler{},
    360 		&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
    361 			proto3pb.Message_PUNS,
    362 			proto3pb.Message_SLAPSTICK,
    363 		}},
    364 		`{"rFunny":["PUNS","SLAPSTICK"]}`},
    365 	{"repeated proto3 enum as int", Marshaler{EnumsAsInts: true},
    366 		&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
    367 			proto3pb.Message_PUNS,
    368 			proto3pb.Message_SLAPSTICK,
    369 		}},
    370 		`{"rFunny":[1,2]}`},
    371 	{"empty value", marshaler, &pb.Simple3{}, `{}`},
    372 	{"empty value emitted", Marshaler{EmitDefaults: true}, &pb.Simple3{}, `{"dub":0}`},
    373 	{"empty repeated emitted", Marshaler{EmitDefaults: true}, &pb.SimpleSlice3{}, `{"slices":[]}`},
    374 	{"empty map emitted", Marshaler{EmitDefaults: true}, &pb.SimpleMap3{}, `{"stringy":{}}`},
    375 	{"nested struct null", Marshaler{EmitDefaults: true}, &pb.SimpleNull3{}, `{"simple":null}`},
    376 	{"map<int64, int32>", marshaler, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, `{"nummy":{"1":2,"3":4}}`},
    377 	{"map<int64, int32>", marshalerAllOptions, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, nummyPrettyJSON},
    378 	{"map<string, string>", marshaler,
    379 		&pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}},
    380 		`{"strry":{"\"one\"":"two","three":"four"}}`},
    381 	{"map<int32, Object>", marshaler,
    382 		&pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, `{"objjy":{"1":{"dub":1}}}`},
    383 	{"map<int32, Object>", marshalerAllOptions,
    384 		&pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, objjyPrettyJSON},
    385 	{"map<int64, string>", marshaler, &pb.Mappy{Buggy: map[int64]string{1234: "yup"}},
    386 		`{"buggy":{"1234":"yup"}}`},
    387 	{"map<bool, bool>", marshaler, &pb.Mappy{Booly: map[bool]bool{false: true}}, `{"booly":{"false":true}}`},
    388 	// TODO: This is broken.
    389 	//{"map<string, enum>", marshaler, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":"ROMAN"}`},
    390 	{"map<string, enum as int>", Marshaler{EnumsAsInts: true}, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":2}}`},
    391 	{"map<int32, bool>", marshaler, &pb.Mappy{S32Booly: map[int32]bool{1: true, 3: false, 10: true, 12: false}}, `{"s32booly":{"1":true,"3":false,"10":true,"12":false}}`},
    392 	{"map<int64, bool>", marshaler, &pb.Mappy{S64Booly: map[int64]bool{1: true, 3: false, 10: true, 12: false}}, `{"s64booly":{"1":true,"3":false,"10":true,"12":false}}`},
    393 	{"map<uint32, bool>", marshaler, &pb.Mappy{U32Booly: map[uint32]bool{1: true, 3: false, 10: true, 12: false}}, `{"u32booly":{"1":true,"3":false,"10":true,"12":false}}`},
    394 	{"map<uint64, bool>", marshaler, &pb.Mappy{U64Booly: map[uint64]bool{1: true, 3: false, 10: true, 12: false}}, `{"u64booly":{"1":true,"3":false,"10":true,"12":false}}`},
    395 	{"proto2 map<int64, string>", marshaler, &pb.Maps{MInt64Str: map[int64]string{213: "cat"}},
    396 		`{"mInt64Str":{"213":"cat"}}`},
    397 	{"proto2 map<bool, Object>", marshaler,
    398 		&pb.Maps{MBoolSimple: map[bool]*pb.Simple{true: {OInt32: proto.Int32(1)}}},
    399 		`{"mBoolSimple":{"true":{"oInt32":1}}}`},
    400 	{"oneof, not set", marshaler, &pb.MsgWithOneof{}, `{}`},
    401 	{"oneof, set", marshaler, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Title{"Grand Poobah"}}, `{"title":"Grand Poobah"}`},
    402 	{"force orig_name", Marshaler{OrigName: true}, &pb.Simple{OInt32: proto.Int32(4)},
    403 		`{"o_int32":4}`},
    404 	{"proto2 extension", marshaler, realNumber, realNumberJSON},
    405 	{"Any with message", marshaler, anySimple, anySimpleJSON},
    406 	{"Any with message and indent", marshalerAllOptions, anySimple, anySimplePrettyJSON},
    407 	{"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON},
    408 	{"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON},
    409 	{"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}, `{"dur":"3.000s"}`},
    410 	{"Struct", marshaler, &pb.KnownTypes{St: &stpb.Struct{
    411 		Fields: map[string]*stpb.Value{
    412 			"one": {Kind: &stpb.Value_StringValue{"loneliest number"}},
    413 			"two": {Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}},
    414 		},
    415 	}}, `{"st":{"one":"loneliest number","two":null}}`},
    416 	{"empty ListValue", marshaler, &pb.KnownTypes{Lv: &stpb.ListValue{}}, `{"lv":[]}`},
    417 	{"basic ListValue", marshaler, &pb.KnownTypes{Lv: &stpb.ListValue{Values: []*stpb.Value{
    418 		{Kind: &stpb.Value_StringValue{"x"}},
    419 		{Kind: &stpb.Value_NullValue{}},
    420 		{Kind: &stpb.Value_NumberValue{3}},
    421 		{Kind: &stpb.Value_BoolValue{true}},
    422 	}}}, `{"lv":["x",null,3,true]}`},
    423 	{"Timestamp", marshaler, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 21e6}}, `{"ts":"2014-05-13T16:53:20.021Z"}`},
    424 	{"number Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NumberValue{1}}}, `{"val":1}`},
    425 	{"null Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}}}, `{"val":null}`},
    426 	{"string number value", marshaler, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"9223372036854775807"}}}, `{"val":"9223372036854775807"}`},
    427 	{"list of lists Value", marshaler, &pb.KnownTypes{Val: &stpb.Value{
    428 		Kind: &stpb.Value_ListValue{&stpb.ListValue{
    429 			Values: []*stpb.Value{
    430 				{Kind: &stpb.Value_StringValue{"x"}},
    431 				{Kind: &stpb.Value_ListValue{&stpb.ListValue{
    432 					Values: []*stpb.Value{
    433 						{Kind: &stpb.Value_ListValue{&stpb.ListValue{
    434 							Values: []*stpb.Value{{Kind: &stpb.Value_StringValue{"y"}}},
    435 						}}},
    436 						{Kind: &stpb.Value_StringValue{"z"}},
    437 					},
    438 				}}},
    439 			},
    440 		}},
    441 	}}, `{"val":["x",[["y"],"z"]]}`},
    442 
    443 	{"DoubleValue", marshaler, &pb.KnownTypes{Dbl: &wpb.DoubleValue{Value: 1.2}}, `{"dbl":1.2}`},
    444 	{"FloatValue", marshaler, &pb.KnownTypes{Flt: &wpb.FloatValue{Value: 1.2}}, `{"flt":1.2}`},
    445 	{"Int64Value", marshaler, &pb.KnownTypes{I64: &wpb.Int64Value{Value: -3}}, `{"i64":"-3"}`},
    446 	{"UInt64Value", marshaler, &pb.KnownTypes{U64: &wpb.UInt64Value{Value: 3}}, `{"u64":"3"}`},
    447 	{"Int32Value", marshaler, &pb.KnownTypes{I32: &wpb.Int32Value{Value: -4}}, `{"i32":-4}`},
    448 	{"UInt32Value", marshaler, &pb.KnownTypes{U32: &wpb.UInt32Value{Value: 4}}, `{"u32":4}`},
    449 	{"BoolValue", marshaler, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}, `{"bool":true}`},
    450 	{"StringValue", marshaler, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}, `{"str":"plush"}`},
    451 	{"BytesValue", marshaler, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`},
    452 }
    453 
    454 func TestMarshaling(t *testing.T) {
    455 	for _, tt := range marshalingTests {
    456 		json, err := tt.marshaler.MarshalToString(tt.pb)
    457 		if err != nil {
    458 			t.Errorf("%s: marshaling error: %v", tt.desc, err)
    459 		} else if tt.json != json {
    460 			t.Errorf("%s: got [%v] want [%v]", tt.desc, json, tt.json)
    461 		}
    462 	}
    463 }
    464 
    465 func TestMarshalJSONPBMarshaler(t *testing.T) {
    466 	rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
    467 	msg := dynamicMessage{rawJson: rawJson}
    468 	str, err := new(Marshaler).MarshalToString(&msg)
    469 	if err != nil {
    470 		t.Errorf("an unexpected error occurred when marshalling JSONPBMarshaler: %v", err)
    471 	}
    472 	if str != rawJson {
    473 		t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, rawJson)
    474 	}
    475 }
    476 
    477 func TestMarshalAnyJSONPBMarshaler(t *testing.T) {
    478 	msg := dynamicMessage{rawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`}
    479 	a, err := ptypes.MarshalAny(&msg)
    480 	if err != nil {
    481 		t.Errorf("an unexpected error occurred when marshalling to Any: %v", err)
    482 	}
    483 	str, err := new(Marshaler).MarshalToString(a)
    484 	if err != nil {
    485 		t.Errorf("an unexpected error occurred when marshalling Any to JSON: %v", err)
    486 	}
    487 	// after custom marshaling, it's round-tripped through JSON decoding/encoding already,
    488 	// so the keys are sorted, whitespace is compacted, and "@type" key has been added
    489 	expected := `{"@type":"type.googleapis.com/` + dynamicMessageName + `","baz":[0,1,2,3],"foo":"bar"}`
    490 	if str != expected {
    491 		t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, expected)
    492 	}
    493 }
    494 
    495 var unmarshalingTests = []struct {
    496 	desc        string
    497 	unmarshaler Unmarshaler
    498 	json        string
    499 	pb          proto.Message
    500 }{
    501 	{"simple flat object", Unmarshaler{}, simpleObjectJSON, simpleObject},
    502 	{"simple pretty object", Unmarshaler{}, simpleObjectPrettyJSON, simpleObject},
    503 	{"repeated fields flat object", Unmarshaler{}, repeatsObjectJSON, repeatsObject},
    504 	{"repeated fields pretty object", Unmarshaler{}, repeatsObjectPrettyJSON, repeatsObject},
    505 	{"nested message/enum flat object", Unmarshaler{}, complexObjectJSON, complexObject},
    506 	{"nested message/enum pretty object", Unmarshaler{}, complexObjectPrettyJSON, complexObject},
    507 	{"enum-string object", Unmarshaler{}, `{"color":"BLUE"}`, &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
    508 	{"enum-value object", Unmarshaler{}, "{\n \"color\": 2\n}", &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
    509 	{"unknown field with allowed option", Unmarshaler{AllowUnknownFields: true}, `{"unknown": "foo"}`, new(pb.Simple)},
    510 	{"proto3 enum string", Unmarshaler{}, `{"hilarity":"PUNS"}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
    511 	{"proto3 enum value", Unmarshaler{}, `{"hilarity":1}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
    512 	{"unknown enum value object",
    513 		Unmarshaler{},
    514 		"{\n  \"color\": 1000,\n  \"r_color\": [\n    \"RED\"\n  ]\n}",
    515 		&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}},
    516 	{"repeated proto3 enum", Unmarshaler{}, `{"rFunny":["PUNS","SLAPSTICK"]}`,
    517 		&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
    518 			proto3pb.Message_PUNS,
    519 			proto3pb.Message_SLAPSTICK,
    520 		}}},
    521 	{"repeated proto3 enum as int", Unmarshaler{}, `{"rFunny":[1,2]}`,
    522 		&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
    523 			proto3pb.Message_PUNS,
    524 			proto3pb.Message_SLAPSTICK,
    525 		}}},
    526 	{"repeated proto3 enum as mix of strings and ints", Unmarshaler{}, `{"rFunny":["PUNS",2]}`,
    527 		&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
    528 			proto3pb.Message_PUNS,
    529 			proto3pb.Message_SLAPSTICK,
    530 		}}},
    531 	{"unquoted int64 object", Unmarshaler{}, `{"oInt64":-314}`, &pb.Simple{OInt64: proto.Int64(-314)}},
    532 	{"unquoted uint64 object", Unmarshaler{}, `{"oUint64":123}`, &pb.Simple{OUint64: proto.Uint64(123)}},
    533 	{"NaN", Unmarshaler{}, `{"oDouble":"NaN"}`, &pb.Simple{ODouble: proto.Float64(math.NaN())}},
    534 	{"Inf", Unmarshaler{}, `{"oFloat":"Infinity"}`, &pb.Simple{OFloat: proto.Float32(float32(math.Inf(1)))}},
    535 	{"-Inf", Unmarshaler{}, `{"oDouble":"-Infinity"}`, &pb.Simple{ODouble: proto.Float64(math.Inf(-1))}},
    536 	{"map<int64, int32>", Unmarshaler{}, `{"nummy":{"1":2,"3":4}}`, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}},
    537 	{"map<string, string>", Unmarshaler{}, `{"strry":{"\"one\"":"two","three":"four"}}`, &pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}}},
    538 	{"map<int32, Object>", Unmarshaler{}, `{"objjy":{"1":{"dub":1}}}`, &pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}},
    539 	{"proto2 extension", Unmarshaler{}, realNumberJSON, realNumber},
    540 	{"Any with message", Unmarshaler{}, anySimpleJSON, anySimple},
    541 	{"Any with message and indent", Unmarshaler{}, anySimplePrettyJSON, anySimple},
    542 	{"Any with WKT", Unmarshaler{}, anyWellKnownJSON, anyWellKnown},
    543 	{"Any with WKT and indent", Unmarshaler{}, anyWellKnownPrettyJSON, anyWellKnown},
    544 	// TODO: This is broken.
    545 	//{"map<string, enum>", Unmarshaler{}, `{"enumy":{"XIV":"ROMAN"}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
    546 	{"map<string, enum as int>", Unmarshaler{}, `{"enumy":{"XIV":2}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
    547 	{"oneof", Unmarshaler{}, `{"salary":31000}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Salary{31000}}},
    548 	{"oneof spec name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{"Australia"}}},
    549 	{"oneof orig_name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{"Australia"}}},
    550 	{"oneof spec name2", Unmarshaler{}, `{"homeAddress":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{"Australia"}}},
    551 	{"oneof orig_name2", Unmarshaler{}, `{"home_address":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{"Australia"}}},
    552 	{"orig_name input", Unmarshaler{}, `{"o_bool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
    553 	{"camelName input", Unmarshaler{}, `{"oBool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
    554 
    555 	{"Duration", Unmarshaler{}, `{"dur":"3.000s"}`, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}},
    556 	{"null Duration", Unmarshaler{}, `{"dur":null}`, &pb.KnownTypes{Dur: nil}},
    557 	{"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20.021Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: 14e8, Nanos: 21e6}}},
    558 	{"PreEpochTimestamp", Unmarshaler{}, `{"ts":"1969-12-31T23:59:58.999999995Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: -2, Nanos: 999999995}}},
    559 	{"ZeroTimeTimestamp", Unmarshaler{}, `{"ts":"0001-01-01T00:00:00Z"}`, &pb.KnownTypes{Ts: &tspb.Timestamp{Seconds: -62135596800, Nanos: 0}}},
    560 	{"null Timestamp", Unmarshaler{}, `{"ts":null}`, &pb.KnownTypes{Ts: nil}},
    561 	{"null Struct", Unmarshaler{}, `{"st": null}`, &pb.KnownTypes{St: nil}},
    562 	{"empty Struct", Unmarshaler{}, `{"st": {}}`, &pb.KnownTypes{St: &stpb.Struct{}}},
    563 	{"basic Struct", Unmarshaler{}, `{"st": {"a": "x", "b": null, "c": 3, "d": true}}`, &pb.KnownTypes{St: &stpb.Struct{Fields: map[string]*stpb.Value{
    564 		"a": {Kind: &stpb.Value_StringValue{"x"}},
    565 		"b": {Kind: &stpb.Value_NullValue{}},
    566 		"c": {Kind: &stpb.Value_NumberValue{3}},
    567 		"d": {Kind: &stpb.Value_BoolValue{true}},
    568 	}}}},
    569 	{"nested Struct", Unmarshaler{}, `{"st": {"a": {"b": 1, "c": [{"d": true}, "f"]}}}`, &pb.KnownTypes{St: &stpb.Struct{Fields: map[string]*stpb.Value{
    570 		"a": {Kind: &stpb.Value_StructValue{&stpb.Struct{Fields: map[string]*stpb.Value{
    571 			"b": {Kind: &stpb.Value_NumberValue{1}},
    572 			"c": {Kind: &stpb.Value_ListValue{&stpb.ListValue{Values: []*stpb.Value{
    573 				{Kind: &stpb.Value_StructValue{&stpb.Struct{Fields: map[string]*stpb.Value{"d": {Kind: &stpb.Value_BoolValue{true}}}}}},
    574 				{Kind: &stpb.Value_StringValue{"f"}},
    575 			}}}},
    576 		}}}},
    577 	}}}},
    578 	{"null ListValue", Unmarshaler{}, `{"lv": null}`, &pb.KnownTypes{Lv: nil}},
    579 	{"empty ListValue", Unmarshaler{}, `{"lv": []}`, &pb.KnownTypes{Lv: &stpb.ListValue{}}},
    580 	{"basic ListValue", Unmarshaler{}, `{"lv": ["x", null, 3, true]}`, &pb.KnownTypes{Lv: &stpb.ListValue{Values: []*stpb.Value{
    581 		{Kind: &stpb.Value_StringValue{"x"}},
    582 		{Kind: &stpb.Value_NullValue{}},
    583 		{Kind: &stpb.Value_NumberValue{3}},
    584 		{Kind: &stpb.Value_BoolValue{true}},
    585 	}}}},
    586 	{"number Value", Unmarshaler{}, `{"val":1}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NumberValue{1}}}},
    587 	{"null Value", Unmarshaler{}, `{"val":null}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_NullValue{stpb.NullValue_NULL_VALUE}}}},
    588 	{"bool Value", Unmarshaler{}, `{"val":true}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_BoolValue{true}}}},
    589 	{"string Value", Unmarshaler{}, `{"val":"x"}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"x"}}}},
    590 	{"string number value", Unmarshaler{}, `{"val":"9223372036854775807"}`, &pb.KnownTypes{Val: &stpb.Value{Kind: &stpb.Value_StringValue{"9223372036854775807"}}}},
    591 	{"list of lists Value", Unmarshaler{}, `{"val":["x", [["y"], "z"]]}`, &pb.KnownTypes{Val: &stpb.Value{
    592 		Kind: &stpb.Value_ListValue{&stpb.ListValue{
    593 			Values: []*stpb.Value{
    594 				{Kind: &stpb.Value_StringValue{"x"}},
    595 				{Kind: &stpb.Value_ListValue{&stpb.ListValue{
    596 					Values: []*stpb.Value{
    597 						{Kind: &stpb.Value_ListValue{&stpb.ListValue{
    598 							Values: []*stpb.Value{{Kind: &stpb.Value_StringValue{"y"}}},
    599 						}}},
    600 						{Kind: &stpb.Value_StringValue{"z"}},
    601 					},
    602 				}}},
    603 			},
    604 		}}}}},
    605 
    606 	{"DoubleValue", Unmarshaler{}, `{"dbl":1.2}`, &pb.KnownTypes{Dbl: &wpb.DoubleValue{Value: 1.2}}},
    607 	{"FloatValue", Unmarshaler{}, `{"flt":1.2}`, &pb.KnownTypes{Flt: &wpb.FloatValue{Value: 1.2}}},
    608 	{"Int64Value", Unmarshaler{}, `{"i64":"-3"}`, &pb.KnownTypes{I64: &wpb.Int64Value{Value: -3}}},
    609 	{"UInt64Value", Unmarshaler{}, `{"u64":"3"}`, &pb.KnownTypes{U64: &wpb.UInt64Value{Value: 3}}},
    610 	{"Int32Value", Unmarshaler{}, `{"i32":-4}`, &pb.KnownTypes{I32: &wpb.Int32Value{Value: -4}}},
    611 	{"UInt32Value", Unmarshaler{}, `{"u32":4}`, &pb.KnownTypes{U32: &wpb.UInt32Value{Value: 4}}},
    612 	{"BoolValue", Unmarshaler{}, `{"bool":true}`, &pb.KnownTypes{Bool: &wpb.BoolValue{Value: true}}},
    613 	{"StringValue", Unmarshaler{}, `{"str":"plush"}`, &pb.KnownTypes{Str: &wpb.StringValue{Value: "plush"}}},
    614 	{"BytesValue", Unmarshaler{}, `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &wpb.BytesValue{Value: []byte("wow")}}},
    615 
    616 	// Ensure that `null` as a value ends up with a nil pointer instead of a [type]Value struct.
    617 	{"null DoubleValue", Unmarshaler{}, `{"dbl":null}`, &pb.KnownTypes{Dbl: nil}},
    618 	{"null FloatValue", Unmarshaler{}, `{"flt":null}`, &pb.KnownTypes{Flt: nil}},
    619 	{"null Int64Value", Unmarshaler{}, `{"i64":null}`, &pb.KnownTypes{I64: nil}},
    620 	{"null UInt64Value", Unmarshaler{}, `{"u64":null}`, &pb.KnownTypes{U64: nil}},
    621 	{"null Int32Value", Unmarshaler{}, `{"i32":null}`, &pb.KnownTypes{I32: nil}},
    622 	{"null UInt32Value", Unmarshaler{}, `{"u32":null}`, &pb.KnownTypes{U32: nil}},
    623 	{"null BoolValue", Unmarshaler{}, `{"bool":null}`, &pb.KnownTypes{Bool: nil}},
    624 	{"null StringValue", Unmarshaler{}, `{"str":null}`, &pb.KnownTypes{Str: nil}},
    625 	{"null BytesValue", Unmarshaler{}, `{"bytes":null}`, &pb.KnownTypes{Bytes: nil}},
    626 }
    627 
    628 func TestUnmarshaling(t *testing.T) {
    629 	for _, tt := range unmarshalingTests {
    630 		// Make a new instance of the type of our expected object.
    631 		p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
    632 
    633 		err := tt.unmarshaler.Unmarshal(strings.NewReader(tt.json), p)
    634 		if err != nil {
    635 			t.Errorf("%s: %v", tt.desc, err)
    636 			continue
    637 		}
    638 
    639 		// For easier diffs, compare text strings of the protos.
    640 		exp := proto.MarshalTextString(tt.pb)
    641 		act := proto.MarshalTextString(p)
    642 		if string(exp) != string(act) {
    643 			t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
    644 		}
    645 	}
    646 }
    647 
    648 func TestUnmarshalNullArray(t *testing.T) {
    649 	var repeats pb.Repeats
    650 	if err := UnmarshalString(`{"rBool":null}`, &repeats); err != nil {
    651 		t.Fatal(err)
    652 	}
    653 	if !reflect.DeepEqual(repeats, pb.Repeats{}) {
    654 		t.Errorf("got non-nil fields in [%#v]", repeats)
    655 	}
    656 }
    657 
    658 func TestUnmarshalNullObject(t *testing.T) {
    659 	var maps pb.Maps
    660 	if err := UnmarshalString(`{"mInt64Str":null}`, &maps); err != nil {
    661 		t.Fatal(err)
    662 	}
    663 	if !reflect.DeepEqual(maps, pb.Maps{}) {
    664 		t.Errorf("got non-nil fields in [%#v]", maps)
    665 	}
    666 }
    667 
    668 func TestUnmarshalNext(t *testing.T) {
    669 	// We only need to check against a few, not all of them.
    670 	tests := unmarshalingTests[:5]
    671 
    672 	// Create a buffer with many concatenated JSON objects.
    673 	var b bytes.Buffer
    674 	for _, tt := range tests {
    675 		b.WriteString(tt.json)
    676 	}
    677 
    678 	dec := json.NewDecoder(&b)
    679 	for _, tt := range tests {
    680 		// Make a new instance of the type of our expected object.
    681 		p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
    682 
    683 		err := tt.unmarshaler.UnmarshalNext(dec, p)
    684 		if err != nil {
    685 			t.Errorf("%s: %v", tt.desc, err)
    686 			continue
    687 		}
    688 
    689 		// For easier diffs, compare text strings of the protos.
    690 		exp := proto.MarshalTextString(tt.pb)
    691 		act := proto.MarshalTextString(p)
    692 		if string(exp) != string(act) {
    693 			t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
    694 		}
    695 	}
    696 
    697 	p := &pb.Simple{}
    698 	err := new(Unmarshaler).UnmarshalNext(dec, p)
    699 	if err != io.EOF {
    700 		t.Errorf("eof: got %v, expected io.EOF", err)
    701 	}
    702 }
    703 
    704 var unmarshalingShouldError = []struct {
    705 	desc string
    706 	in   string
    707 	pb   proto.Message
    708 }{
    709 	{"a value", "666", new(pb.Simple)},
    710 	{"gibberish", "{adskja123;l23=-=", new(pb.Simple)},
    711 	{"unknown field", `{"unknown": "foo"}`, new(pb.Simple)},
    712 	{"unknown enum name", `{"hilarity":"DAVE"}`, new(proto3pb.Message)},
    713 }
    714 
    715 func TestUnmarshalingBadInput(t *testing.T) {
    716 	for _, tt := range unmarshalingShouldError {
    717 		err := UnmarshalString(tt.in, tt.pb)
    718 		if err == nil {
    719 			t.Errorf("an error was expected when parsing %q instead of an object", tt.desc)
    720 		}
    721 	}
    722 }
    723 
    724 func TestUnmarshalJSONPBUnmarshaler(t *testing.T) {
    725 	rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
    726 	var msg dynamicMessage
    727 	if err := Unmarshal(strings.NewReader(rawJson), &msg); err != nil {
    728 		t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
    729 	}
    730 	if msg.rawJson != rawJson {
    731 		t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.rawJson, rawJson)
    732 	}
    733 }
    734 
    735 func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) {
    736 	rawJson := `{ "@type": "blah.com/` + dynamicMessageName + `", "foo": "bar", "baz": [0, 1, 2, 3] }`
    737 	var got anypb.Any
    738 	if err := Unmarshal(strings.NewReader(rawJson), &got); err != nil {
    739 		t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
    740 	}
    741 
    742 	dm := &dynamicMessage{rawJson: `{"baz":[0,1,2,3],"foo":"bar"}`}
    743 	var want anypb.Any
    744 	if b, err := proto.Marshal(dm); err != nil {
    745 		t.Errorf("an unexpected error occurred when marshaling message: %v", err)
    746 	} else {
    747 		want.TypeUrl = "blah.com/" + dynamicMessageName
    748 		want.Value = b
    749 	}
    750 
    751 	if !proto.Equal(&got, &want) {
    752 		t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", got, want)
    753 	}
    754 }
    755 
    756 const (
    757 	dynamicMessageName = "google.protobuf.jsonpb.testing.dynamicMessage"
    758 )
    759 
    760 func init() {
    761 	// we register the custom type below so that we can use it in Any types
    762 	proto.RegisterType((*dynamicMessage)(nil), dynamicMessageName)
    763 }
    764 
    765 // dynamicMessage implements protobuf.Message but is not a normal generated message type.
    766 // It provides implementations of JSONPBMarshaler and JSONPBUnmarshaler for JSON support.
    767 type dynamicMessage struct {
    768 	rawJson string `protobuf:"bytes,1,opt,name=rawJson"`
    769 }
    770 
    771 func (m *dynamicMessage) Reset() {
    772 	m.rawJson = "{}"
    773 }
    774 
    775 func (m *dynamicMessage) String() string {
    776 	return m.rawJson
    777 }
    778 
    779 func (m *dynamicMessage) ProtoMessage() {
    780 }
    781 
    782 func (m *dynamicMessage) MarshalJSONPB(jm *Marshaler) ([]byte, error) {
    783 	return []byte(m.rawJson), nil
    784 }
    785 
    786 func (m *dynamicMessage) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error {
    787 	m.rawJson = string(js)
    788 	return nil
    789 }
    790