github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/runtime/marshal_jsonpb_test.go (about)

     1  package runtime_test
     2  
     3  import (
     4  	"bytes"
     5  	"reflect"
     6  	"strconv"
     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/encoding/protojson"
    14  	"google.golang.org/protobuf/proto"
    15  	"google.golang.org/protobuf/testing/protocmp"
    16  	"google.golang.org/protobuf/types/known/durationpb"
    17  	"google.golang.org/protobuf/types/known/emptypb"
    18  	"google.golang.org/protobuf/types/known/structpb"
    19  	"google.golang.org/protobuf/types/known/timestamppb"
    20  	"google.golang.org/protobuf/types/known/wrapperspb"
    21  )
    22  
    23  func TestJSONPbMarshal(t *testing.T) {
    24  	msg := examplepb.ABitOfEverything{
    25  		SingleNested:        &examplepb.ABitOfEverything_Nested{},
    26  		RepeatedStringValue: []string{},
    27  		MappedStringValue:   map[string]string{},
    28  		MappedNestedValue:   map[string]*examplepb.ABitOfEverything_Nested{},
    29  		RepeatedEnumValue:   []examplepb.NumericEnum{},
    30  		TimestampValue:      &timestamppb.Timestamp{},
    31  		Uuid:                "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
    32  		Nested: []*examplepb.ABitOfEverything_Nested{
    33  			{
    34  				Name:   "foo",
    35  				Amount: 12345,
    36  			},
    37  		},
    38  		Uint64Value: 0xFFFFFFFFFFFFFFFF,
    39  		EnumValue:   examplepb.NumericEnum_ONE,
    40  		OneofValue: &examplepb.ABitOfEverything_OneofString{
    41  			OneofString: "bar",
    42  		},
    43  		MapValue: map[string]examplepb.NumericEnum{
    44  			"a": examplepb.NumericEnum_ONE,
    45  			"b": examplepb.NumericEnum_ZERO,
    46  		},
    47  		RepeatedEnumAnnotation:   []examplepb.NumericEnum{},
    48  		EnumValueAnnotation:      examplepb.NumericEnum_ONE,
    49  		RepeatedStringAnnotation: []string{},
    50  		RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{},
    51  		NestedAnnotation:         &examplepb.ABitOfEverything_Nested{},
    52  	}
    53  
    54  	for i, spec := range []struct {
    55  		useEnumNumbers, emitUnpopulated bool
    56  		indent                          string
    57  		useProtoNames                   bool
    58  		verifier                        func(json string)
    59  	}{
    60  		{
    61  			verifier: func(json string) {
    62  				if !strings.Contains(json, "ONE") {
    63  					t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json)
    64  				}
    65  				if want := "uint64Value"; !strings.Contains(json, want) {
    66  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
    67  				}
    68  			},
    69  		},
    70  		{
    71  			useEnumNumbers: true,
    72  			verifier: func(json string) {
    73  				if strings.Contains(json, "ONE") {
    74  					t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json)
    75  				}
    76  			},
    77  		},
    78  		{
    79  			emitUnpopulated: true,
    80  			verifier: func(json string) {
    81  				if want := `"sfixed32Value"`; !strings.Contains(json, want) {
    82  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
    83  				}
    84  			},
    85  		},
    86  		{
    87  			indent: "\t\t",
    88  			verifier: func(json string) {
    89  				if want := "\t\t\"amount\":"; !strings.Contains(json, want) {
    90  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
    91  				}
    92  			},
    93  		},
    94  		{
    95  			useProtoNames: true,
    96  			verifier: func(json string) {
    97  				if want := "uint64_value"; !strings.Contains(json, want) {
    98  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
    99  				}
   100  			},
   101  		},
   102  	} {
   103  		t.Run(strconv.Itoa(i), func(t *testing.T) {
   104  			m := runtime.JSONPb{
   105  				MarshalOptions: protojson.MarshalOptions{
   106  					EmitUnpopulated: spec.emitUnpopulated,
   107  					Indent:          spec.indent,
   108  					UseProtoNames:   spec.useProtoNames,
   109  					UseEnumNumbers:  spec.useEnumNumbers,
   110  				},
   111  			}
   112  			buf, err := m.Marshal(&msg)
   113  			if err != nil {
   114  				t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec)
   115  			}
   116  
   117  			var got examplepb.ABitOfEverything
   118  			unmarshaler := &protojson.UnmarshalOptions{}
   119  			if err = unmarshaler.Unmarshal(buf, &got); err != nil {
   120  				t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec)
   121  			}
   122  			if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" {
   123  				t.Errorf("case %d: spec=%v; %s", i, spec, diff)
   124  			}
   125  			if spec.verifier != nil {
   126  				spec.verifier(string(buf))
   127  			}
   128  		})
   129  	}
   130  }
   131  
   132  func TestJSONPbMarshalFields(t *testing.T) {
   133  	var m runtime.JSONPb
   134  	m.UseEnumNumbers = true // builtin fixtures include an enum, expected to be marshaled as int
   135  	for _, spec := range builtinFieldFixtures {
   136  		buf, err := m.Marshal(spec.data)
   137  		if err != nil {
   138  			t.Errorf("m.Marshal(%#v) failed with %v; want success", spec.data, err)
   139  		}
   140  		if got, want := string(buf), spec.json; got != want {
   141  			t.Errorf("m.Marshal(%#v) = %q; want %q", spec.data, got, want)
   142  		}
   143  	}
   144  
   145  	nums := []examplepb.NumericEnum{examplepb.NumericEnum_ZERO, examplepb.NumericEnum_ONE}
   146  
   147  	buf, err := m.Marshal(nums)
   148  	if err != nil {
   149  		t.Errorf("m.Marshal(%#v) failed with %v; want success", nums, err)
   150  	}
   151  	if got, want := string(buf), `[0,1]`; got != want {
   152  		t.Errorf("m.Marshal(%#v) = %q; want %q", nums, got, want)
   153  	}
   154  
   155  	m.UseEnumNumbers = false
   156  	buf, err = m.Marshal(examplepb.NumericEnum_ONE)
   157  	if err != nil {
   158  		t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err)
   159  	}
   160  	if got, want := string(buf), `"ONE"`; got != want {
   161  		t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want)
   162  	}
   163  
   164  	buf, err = m.Marshal(nums)
   165  	if err != nil {
   166  		t.Errorf("m.Marshal(%#v) failed with %v; want success", nums, err)
   167  	}
   168  	if got, want := string(buf), `["ZERO","ONE"]`; got != want {
   169  		t.Errorf("m.Marshal(%#v) = %q; want %q", nums, got, want)
   170  	}
   171  }
   172  
   173  func TestJSONPbUnmarshal(t *testing.T) {
   174  	var (
   175  		m   runtime.JSONPb
   176  		got examplepb.ABitOfEverything
   177  	)
   178  	for i, data := range []string{
   179  		`{
   180  			"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   181  			"nested": [
   182  				{"name": "foo", "amount": 12345}
   183  			],
   184  			"uint64Value": 18446744073709551615,
   185  			"enumValue": "ONE",
   186  			"oneofString": "bar",
   187  			"mapValue": {
   188  				"a": 1,
   189  				"b": 0
   190  			}
   191  		}`,
   192  		`{
   193  			"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   194  			"nested": [
   195  				{"name": "foo", "amount": 12345}
   196  			],
   197  			"uint64Value": "18446744073709551615",
   198  			"enumValue": "ONE",
   199  			"oneofString": "bar",
   200  			"mapValue": {
   201  				"a": 1,
   202  				"b": 0
   203  			}
   204  		}`,
   205  		`{
   206  			"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   207  			"nested": [
   208  				{"name": "foo", "amount": 12345}
   209  			],
   210  			"uint64Value": 18446744073709551615,
   211  			"enumValue": 1,
   212  			"oneofString": "bar",
   213  			"mapValue": {
   214  				"a": 1,
   215  				"b": 0
   216  			}
   217  		}`,
   218  	} {
   219  		if err := m.Unmarshal([]byte(data), &got); err != nil {
   220  			t.Errorf("case %d: m.Unmarshal(%q, &got) failed with %v; want success", i, data, err)
   221  		}
   222  
   223  		want := examplepb.ABitOfEverything{
   224  			Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   225  			Nested: []*examplepb.ABitOfEverything_Nested{
   226  				{
   227  					Name:   "foo",
   228  					Amount: 12345,
   229  				},
   230  			},
   231  			Uint64Value: 0xFFFFFFFFFFFFFFFF,
   232  			EnumValue:   examplepb.NumericEnum_ONE,
   233  			OneofValue: &examplepb.ABitOfEverything_OneofString{
   234  				OneofString: "bar",
   235  			},
   236  			MapValue: map[string]examplepb.NumericEnum{
   237  				"a": examplepb.NumericEnum_ONE,
   238  				"b": examplepb.NumericEnum_ZERO,
   239  			},
   240  		}
   241  
   242  		if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" {
   243  			t.Errorf("case %d: %s", i, diff)
   244  		}
   245  	}
   246  }
   247  
   248  func TestJSONPbUnmarshalFields(t *testing.T) {
   249  	var m runtime.JSONPb
   250  	for _, fixt := range fieldFixtures {
   251  		if fixt.skipUnmarshal {
   252  			continue
   253  		}
   254  
   255  		dest := reflect.New(reflect.TypeOf(fixt.data))
   256  		if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil {
   257  			t.Errorf("m.Unmarshal(%q, %T) failed with %v; want success", fixt.json, dest.Interface(), err)
   258  		}
   259  		if diff := cmp.Diff(dest.Elem().Interface(), fixt.data, protocmp.Transform()); diff != "" {
   260  			t.Errorf("dest = %#v; want %#v; input = %v", dest.Elem().Interface(), fixt.data, fixt.json)
   261  		}
   262  	}
   263  }
   264  
   265  func TestJSONPbEncoder(t *testing.T) {
   266  	msg := examplepb.ABitOfEverything{
   267  		SingleNested:        &examplepb.ABitOfEverything_Nested{},
   268  		RepeatedStringValue: []string{},
   269  		MappedStringValue:   map[string]string{},
   270  		MappedNestedValue:   map[string]*examplepb.ABitOfEverything_Nested{},
   271  		RepeatedEnumValue:   []examplepb.NumericEnum{},
   272  		TimestampValue:      &timestamppb.Timestamp{},
   273  		Uuid:                "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   274  		Nested: []*examplepb.ABitOfEverything_Nested{
   275  			{
   276  				Name:   "foo",
   277  				Amount: 12345,
   278  			},
   279  		},
   280  		Uint64Value: 0xFFFFFFFFFFFFFFFF,
   281  		OneofValue: &examplepb.ABitOfEverything_OneofString{
   282  			OneofString: "bar",
   283  		},
   284  		MapValue: map[string]examplepb.NumericEnum{
   285  			"a": examplepb.NumericEnum_ONE,
   286  			"b": examplepb.NumericEnum_ZERO,
   287  		},
   288  		RepeatedEnumAnnotation:   []examplepb.NumericEnum{},
   289  		EnumValueAnnotation:      examplepb.NumericEnum_ONE,
   290  		RepeatedStringAnnotation: []string{},
   291  		RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{},
   292  		NestedAnnotation:         &examplepb.ABitOfEverything_Nested{},
   293  	}
   294  
   295  	for i, spec := range []struct {
   296  		useEnumNumbers, emitUnpopulated bool
   297  		indent                          string
   298  		useProtoNames                   bool
   299  		verifier                        func(json string)
   300  	}{
   301  		{
   302  			verifier: func(json string) {
   303  				if !strings.Contains(json, "ONE") {
   304  					t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json)
   305  				}
   306  				if want := "uint64Value"; !strings.Contains(json, want) {
   307  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
   308  				}
   309  			},
   310  		},
   311  		{
   312  			useEnumNumbers: true,
   313  			verifier: func(json string) {
   314  				if strings.Contains(json, "ONE") {
   315  					t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json)
   316  				}
   317  			},
   318  		},
   319  		{
   320  			emitUnpopulated: true,
   321  			verifier: func(json string) {
   322  				if want := `"sfixed32Value"`; !strings.Contains(json, want) {
   323  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
   324  				}
   325  			},
   326  		},
   327  		{
   328  			indent: "\t\t",
   329  			verifier: func(json string) {
   330  				if want := "\t\t\"amount\":"; !strings.Contains(json, want) {
   331  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
   332  				}
   333  			},
   334  		},
   335  		{
   336  			useProtoNames: true,
   337  			verifier: func(json string) {
   338  				if want := "uint64_value"; !strings.Contains(json, want) {
   339  					t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
   340  				}
   341  			},
   342  		},
   343  	} {
   344  		m := runtime.JSONPb{
   345  			MarshalOptions: protojson.MarshalOptions{
   346  				EmitUnpopulated: spec.emitUnpopulated,
   347  				Indent:          spec.indent,
   348  				UseProtoNames:   spec.useProtoNames,
   349  				UseEnumNumbers:  spec.useEnumNumbers,
   350  			},
   351  		}
   352  
   353  		var buf bytes.Buffer
   354  		enc := m.NewEncoder(&buf)
   355  		if err := enc.Encode(&msg); err != nil {
   356  			t.Errorf("enc.Encode(%v) failed with %v; want success; spec=%v", &msg, err, spec)
   357  		}
   358  
   359  		var got examplepb.ABitOfEverything
   360  		unmarshaler := &protojson.UnmarshalOptions{}
   361  		if err := unmarshaler.Unmarshal(buf.Bytes(), &got); err != nil {
   362  			t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec)
   363  		}
   364  		if diff := cmp.Diff(&got, &msg, protocmp.Transform()); diff != "" {
   365  			t.Errorf("case %d: %s", i, diff)
   366  		}
   367  		if spec.verifier != nil {
   368  			spec.verifier(buf.String())
   369  		}
   370  	}
   371  }
   372  
   373  func TestJSONPbEncoderFields(t *testing.T) {
   374  	var m runtime.JSONPb
   375  	for _, fixt := range fieldFixtures {
   376  		var buf bytes.Buffer
   377  		enc := m.NewEncoder(&buf)
   378  		if err := enc.Encode(fixt.data); err != nil {
   379  			t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err)
   380  		}
   381  		if got, want := buf.String(), fixt.json+string(m.Delimiter()); got != want {
   382  			t.Errorf("enc.Encode(%#v) = %q; want %q", fixt.data, got, want)
   383  		}
   384  	}
   385  
   386  	m.UseEnumNumbers = true
   387  	buf, err := m.Marshal(examplepb.NumericEnum_ONE)
   388  	if err != nil {
   389  		t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err)
   390  	}
   391  	if got, want := string(buf), "1"; got != want {
   392  		t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want)
   393  	}
   394  }
   395  
   396  func TestJSONPbDecoder(t *testing.T) {
   397  	var (
   398  		m   runtime.JSONPb
   399  		got examplepb.ABitOfEverything
   400  	)
   401  	for _, data := range []string{
   402  		`{
   403  			"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   404  			"nested": [
   405  				{"name": "foo", "amount": 12345}
   406  			],
   407  			"uint64Value": 18446744073709551615,
   408  			"enumValue": "ONE",
   409  			"oneofString": "bar",
   410  			"mapValue": {
   411  				"a": 1,
   412  				"b": 0
   413  			}
   414  		}`,
   415  		`{
   416  			"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   417  			"nested": [
   418  				{"name": "foo", "amount": 12345}
   419  			],
   420  			"uint64Value": "18446744073709551615",
   421  			"enumValue": "ONE",
   422  			"oneofString": "bar",
   423  			"mapValue": {
   424  				"a": 1,
   425  				"b": 0
   426  			}
   427  		}`,
   428  		`{
   429  			"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   430  			"nested": [
   431  				{"name": "foo", "amount": 12345}
   432  			],
   433  			"uint64Value": 18446744073709551615,
   434  			"enumValue": 1,
   435  			"oneofString": "bar",
   436  			"mapValue": {
   437  				"a": 1,
   438  				"b": 0
   439  			}
   440  		}`,
   441  	} {
   442  		r := strings.NewReader(data)
   443  		dec := m.NewDecoder(r)
   444  		if err := dec.Decode(&got); err != nil {
   445  			t.Errorf("m.Unmarshal(&got) failed with %v; want success; data=%q", err, data)
   446  		}
   447  
   448  		want := examplepb.ABitOfEverything{
   449  			Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   450  			Nested: []*examplepb.ABitOfEverything_Nested{
   451  				{
   452  					Name:   "foo",
   453  					Amount: 12345,
   454  				},
   455  			},
   456  			Uint64Value: 0xFFFFFFFFFFFFFFFF,
   457  			EnumValue:   examplepb.NumericEnum_ONE,
   458  			OneofValue: &examplepb.ABitOfEverything_OneofString{
   459  				OneofString: "bar",
   460  			},
   461  			MapValue: map[string]examplepb.NumericEnum{
   462  				"a": examplepb.NumericEnum_ONE,
   463  				"b": examplepb.NumericEnum_ZERO,
   464  			},
   465  		}
   466  		if diff := cmp.Diff(&got, &want, protocmp.Transform()); diff != "" {
   467  			t.Errorf("data %q: %s", data, diff)
   468  		}
   469  	}
   470  }
   471  
   472  func TestJSONPbDecoderFields(t *testing.T) {
   473  	var m runtime.JSONPb
   474  	for _, fixt := range fieldFixtures {
   475  		if fixt.skipUnmarshal {
   476  			continue
   477  		}
   478  
   479  		dest := reflect.New(reflect.TypeOf(fixt.data))
   480  		dec := m.NewDecoder(strings.NewReader(fixt.json))
   481  		if err := dec.Decode(dest.Interface()); err != nil {
   482  			t.Errorf("dec.Decode(%T) failed with %v; want success; input = %q", dest.Interface(), err, fixt.json)
   483  		}
   484  		if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) {
   485  			t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json)
   486  		}
   487  	}
   488  }
   489  
   490  func TestJSONPbDecoderUnknownField(t *testing.T) {
   491  	var (
   492  		m = runtime.JSONPb{
   493  			UnmarshalOptions: protojson.UnmarshalOptions{
   494  				DiscardUnknown: false,
   495  			},
   496  		}
   497  		got examplepb.ABitOfEverything
   498  	)
   499  	data := `{
   500  		"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
   501  		"unknownField": "111"
   502  	}`
   503  
   504  	r := strings.NewReader(data)
   505  	dec := m.NewDecoder(r)
   506  	if err := dec.Decode(&got); err == nil {
   507  		t.Errorf("m.Unmarshal(&got) not failed; want `unknown field` error; data=%q", data)
   508  	}
   509  }
   510  
   511  var (
   512  	fieldFixtures = []struct {
   513  		data          interface{}
   514  		json          string
   515  		skipUnmarshal bool
   516  	}{
   517  		{data: int32(1), json: "1"},
   518  		{data: proto.Int32(1), json: "1"},
   519  		{data: int64(1), json: "1"},
   520  		{data: proto.Int64(1), json: "1"},
   521  		{data: uint32(1), json: "1"},
   522  		{data: proto.Uint32(1), json: "1"},
   523  		{data: uint64(1), json: "1"},
   524  		{data: proto.Uint64(1), json: "1"},
   525  		{data: "abc", json: `"abc"`},
   526  		{data: []byte("abc"), json: `"YWJj"`},
   527  		{data: []byte{}, json: `""`},
   528  		{data: proto.String("abc"), json: `"abc"`},
   529  		{data: float32(1.5), json: "1.5"},
   530  		{data: proto.Float32(1.5), json: "1.5"},
   531  		{data: float64(1.5), json: "1.5"},
   532  		{data: proto.Float64(1.5), json: "1.5"},
   533  		{data: true, json: "true"},
   534  		{data: false, json: "false"},
   535  		{data: (*string)(nil), json: "null"},
   536  		{
   537  			data: examplepb.NumericEnum_ONE,
   538  			json: `"ONE"`,
   539  			// TODO(yugui) support unmarshaling of symbolic enum
   540  			skipUnmarshal: true,
   541  		},
   542  		{
   543  			data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))),
   544  			json: `"ONE"`,
   545  			// TODO(yugui) support unmarshaling of symbolic enum
   546  			skipUnmarshal: true,
   547  		},
   548  
   549  		{
   550  			data: map[string]int32{
   551  				"foo": 1,
   552  			},
   553  			json: `{"foo":1}`,
   554  		},
   555  		{
   556  			data: map[string]*examplepb.SimpleMessage{
   557  				"foo": {Id: "bar"},
   558  			},
   559  			json: `{"foo":{"id":"bar"}}`,
   560  		},
   561  		{
   562  			data: map[int32]*examplepb.SimpleMessage{
   563  				1: {Id: "foo"},
   564  			},
   565  			json: `{"1":{"id":"foo"}}`,
   566  		},
   567  		{
   568  			data: map[bool]*examplepb.SimpleMessage{
   569  				true: {Id: "foo"},
   570  			},
   571  			json: `{"true":{"id":"foo"}}`,
   572  		},
   573  		{
   574  			data: &durationpb.Duration{
   575  				Seconds: 123,
   576  				Nanos:   456000000,
   577  			},
   578  			json: `"123.456s"`,
   579  		},
   580  		{
   581  			data: &timestamppb.Timestamp{
   582  				Seconds: 1462875553,
   583  				Nanos:   123000000,
   584  			},
   585  			json: `"2016-05-10T10:19:13.123Z"`,
   586  		},
   587  		{
   588  			data: new(emptypb.Empty),
   589  			json: "{}",
   590  		},
   591  		{
   592  			data: &structpb.Value{
   593  				Kind: new(structpb.Value_NullValue),
   594  			},
   595  			json:          "null",
   596  			skipUnmarshal: true,
   597  		},
   598  		{
   599  			data: &structpb.Value{
   600  				Kind: &structpb.Value_NumberValue{
   601  					NumberValue: 123.4,
   602  				},
   603  			},
   604  			json:          "123.4",
   605  			skipUnmarshal: true,
   606  		},
   607  		{
   608  			data: &structpb.Value{
   609  				Kind: &structpb.Value_StringValue{
   610  					StringValue: "abc",
   611  				},
   612  			},
   613  			json:          `"abc"`,
   614  			skipUnmarshal: true,
   615  		},
   616  		{
   617  			data: &structpb.Value{
   618  				Kind: &structpb.Value_BoolValue{
   619  					BoolValue: true,
   620  				},
   621  			},
   622  			json:          "true",
   623  			skipUnmarshal: true,
   624  		},
   625  		{
   626  			data: &structpb.Struct{
   627  				Fields: map[string]*structpb.Value{
   628  					"foo_bar": {
   629  						Kind: &structpb.Value_BoolValue{
   630  							BoolValue: true,
   631  						},
   632  					},
   633  				},
   634  			},
   635  			json:          `{"foo_bar":true}`,
   636  			skipUnmarshal: true,
   637  		},
   638  
   639  		{
   640  			data: wrapperspb.Bool(true),
   641  			json: "true",
   642  		},
   643  		{
   644  			data: wrapperspb.Double(123.456),
   645  			json: "123.456",
   646  		},
   647  		{
   648  			data: wrapperspb.Float(123.456),
   649  			json: "123.456",
   650  		},
   651  		{
   652  			data: wrapperspb.Int32(-123),
   653  			json: "-123",
   654  		},
   655  		{
   656  			data: wrapperspb.Int64(-123),
   657  			json: `"-123"`,
   658  		},
   659  		{
   660  			data: wrapperspb.UInt32(123),
   661  			json: "123",
   662  		},
   663  		{
   664  			data: wrapperspb.UInt64(123),
   665  			json: `"123"`,
   666  		},
   667  		// TODO(yugui) Add other well-known types once jsonpb supports them
   668  	}
   669  )
   670  
   671  func TestJSONPbUnmarshalNullField(t *testing.T) {
   672  	var out map[string]interface{}
   673  
   674  	const json = `{"foo": null}`
   675  	marshaler := &runtime.JSONPb{}
   676  	if err := marshaler.Unmarshal([]byte(json), &out); err != nil {
   677  		t.Fatalf("unexpected error: %v", err)
   678  	}
   679  
   680  	value, hasKey := out["foo"]
   681  	if !hasKey {
   682  		t.Fatalf("unmarshaled map did not have key 'foo'")
   683  	}
   684  	if value != nil {
   685  		t.Fatalf("unexpected value: %v", value)
   686  	}
   687  }
   688  
   689  func TestJSONPbMarshalResponseBodies(t *testing.T) {
   690  	marshaler := &runtime.JSONPb{}
   691  	for i, spec := range []struct {
   692  		input           interface{}
   693  		emitUnpopulated bool
   694  		verifier        func(*testing.T, interface{}, []byte)
   695  	}{
   696  		{
   697  			input: &examplepb.ResponseBodyOut{
   698  				Response: &examplepb.ResponseBodyOut_Response{Data: "abcdef"},
   699  			},
   700  			verifier: func(t *testing.T, input interface{}, json []byte) {
   701  				var out examplepb.ResponseBodyOut
   702  				err := marshaler.Unmarshal(json, &out)
   703  				if err != nil {
   704  					t.Fatalf("unexpected error: %v", err)
   705  				}
   706  				diff := cmp.Diff(input, &out, protocmp.Transform())
   707  				if diff != "" {
   708  					t.Errorf("json not equal:\n%s", diff)
   709  				}
   710  			},
   711  		},
   712  		{
   713  			emitUnpopulated: true,
   714  			input:           &examplepb.ResponseBodyOut{},
   715  			verifier: func(t *testing.T, input interface{}, json []byte) {
   716  				var out examplepb.ResponseBodyOut
   717  				err := marshaler.Unmarshal(json, &out)
   718  				if err != nil {
   719  					t.Fatalf("unexpected error: %v", err)
   720  				}
   721  				diff := cmp.Diff(input, &out, protocmp.Transform())
   722  				if diff != "" {
   723  					t.Errorf("json not equal:\n%s", diff)
   724  				}
   725  			},
   726  		},
   727  		{
   728  			input: &examplepb.RepeatedResponseBodyOut_Response{},
   729  			verifier: func(t *testing.T, input interface{}, json []byte) {
   730  				var out examplepb.RepeatedResponseBodyOut_Response
   731  				err := marshaler.Unmarshal(json, &out)
   732  				if err != nil {
   733  					t.Fatalf("unexpected error: %v", err)
   734  				}
   735  				diff := cmp.Diff(input, &out, protocmp.Transform())
   736  				if diff != "" {
   737  					t.Errorf("json not equal:\n%s", diff)
   738  				}
   739  			},
   740  		},
   741  		{
   742  			emitUnpopulated: true,
   743  			input:           &examplepb.RepeatedResponseBodyOut_Response{},
   744  			verifier: func(t *testing.T, input interface{}, json []byte) {
   745  				var out examplepb.RepeatedResponseBodyOut_Response
   746  				err := marshaler.Unmarshal(json, &out)
   747  				if err != nil {
   748  					t.Fatalf("unexpected error: %v", err)
   749  				}
   750  				diff := cmp.Diff(input, &out, protocmp.Transform())
   751  				if diff != "" {
   752  					t.Errorf("json not equal:\n%s", diff)
   753  				}
   754  			},
   755  		},
   756  		{
   757  			input: ([]*examplepb.RepeatedResponseBodyOut_Response)(nil),
   758  			verifier: func(t *testing.T, input interface{}, json []byte) {
   759  				var out []*examplepb.RepeatedResponseBodyOut_Response
   760  				err := marshaler.Unmarshal(json, &out)
   761  				if err != nil {
   762  					t.Fatalf("unexpected error: %v", err)
   763  				}
   764  				diff := cmp.Diff(input, out, protocmp.Transform())
   765  				if diff != "" {
   766  					t.Errorf("json not equal:\n%s", diff)
   767  				}
   768  			},
   769  		},
   770  		{
   771  			emitUnpopulated: true,
   772  			input:           ([]*examplepb.RepeatedResponseBodyOut_Response)(nil),
   773  			verifier: func(t *testing.T, _ interface{}, json []byte) {
   774  				var out []*examplepb.RepeatedResponseBodyOut_Response
   775  				err := marshaler.Unmarshal(json, &out)
   776  				if err != nil {
   777  					t.Fatalf("unexpected error: %v", err)
   778  				}
   779  				diff := cmp.Diff([]*examplepb.RepeatedResponseBodyOut_Response{}, out, protocmp.Transform())
   780  				if diff != "" {
   781  					t.Errorf("json not equal:\n%s", diff)
   782  				}
   783  			},
   784  		},
   785  		{
   786  			input: []*examplepb.RepeatedResponseBodyOut_Response{},
   787  			verifier: func(t *testing.T, input interface{}, json []byte) {
   788  				var out []*examplepb.RepeatedResponseBodyOut_Response
   789  				err := marshaler.Unmarshal(json, &out)
   790  				if err != nil {
   791  					t.Fatalf("unexpected error: %v", err)
   792  				}
   793  				diff := cmp.Diff(input, out, protocmp.Transform())
   794  				if diff != "" {
   795  					t.Errorf("json not equal:\n%s", diff)
   796  				}
   797  			},
   798  		},
   799  		{
   800  			input: []string{"something"},
   801  			verifier: func(t *testing.T, input interface{}, json []byte) {
   802  				var out []string
   803  				err := marshaler.Unmarshal(json, &out)
   804  				if err != nil {
   805  					t.Fatalf("unexpected error: %v", err)
   806  				}
   807  				diff := cmp.Diff(input, out, protocmp.Transform())
   808  				if diff != "" {
   809  					t.Errorf("json not equal:\n%s", diff)
   810  				}
   811  			},
   812  		},
   813  		{
   814  			input: []string{},
   815  			verifier: func(t *testing.T, input interface{}, json []byte) {
   816  				var out []string
   817  				err := marshaler.Unmarshal(json, &out)
   818  				if err != nil {
   819  					t.Fatalf("unexpected error: %v", err)
   820  				}
   821  				diff := cmp.Diff(input, out, protocmp.Transform())
   822  				if diff != "" {
   823  					t.Errorf("json not equal:\n%s", diff)
   824  				}
   825  			},
   826  		},
   827  		{
   828  			input: ([]string)(nil),
   829  			verifier: func(t *testing.T, input interface{}, json []byte) {
   830  				var out []string
   831  				err := marshaler.Unmarshal(json, &out)
   832  				if err != nil {
   833  					t.Fatalf("unexpected error: %v", err)
   834  				}
   835  				diff := cmp.Diff(input, out, protocmp.Transform())
   836  				if diff != "" {
   837  					t.Errorf("json not equal:\n%s", diff)
   838  				}
   839  			},
   840  		},
   841  		{
   842  			emitUnpopulated: true,
   843  			input:           ([]string)(nil),
   844  			verifier: func(t *testing.T, _ interface{}, json []byte) {
   845  				var out []string
   846  				err := marshaler.Unmarshal(json, &out)
   847  				if err != nil {
   848  					t.Fatalf("unexpected error: %v", err)
   849  				}
   850  				diff := cmp.Diff([]string{}, out, protocmp.Transform())
   851  				if diff != "" {
   852  					t.Errorf("json not equal:\n%s", diff)
   853  				}
   854  			},
   855  		},
   856  		{
   857  			input: []*examplepb.RepeatedResponseBodyOut_Response{
   858  				{},
   859  				{
   860  					Data: "abc",
   861  					Type: examplepb.RepeatedResponseBodyOut_Response_A,
   862  				},
   863  			},
   864  			verifier: func(t *testing.T, input interface{}, json []byte) {
   865  				var out []*examplepb.RepeatedResponseBodyOut_Response
   866  				err := marshaler.Unmarshal(json, &out)
   867  				if err != nil {
   868  					t.Fatalf("unexpected error: %v", err)
   869  				}
   870  				diff := cmp.Diff(input, out, protocmp.Transform())
   871  				if diff != "" {
   872  					t.Errorf("json not equal:\n%s", diff)
   873  				}
   874  			},
   875  		},
   876  		{
   877  			emitUnpopulated: true,
   878  			input: []*examplepb.RepeatedResponseBodyOut_Response{
   879  				{},
   880  				{
   881  					Data: "abc",
   882  					Type: examplepb.RepeatedResponseBodyOut_Response_B,
   883  				},
   884  			},
   885  			verifier: func(t *testing.T, input interface{}, json []byte) {
   886  				var out []*examplepb.RepeatedResponseBodyOut_Response
   887  				err := marshaler.Unmarshal(json, &out)
   888  				if err != nil {
   889  					t.Fatalf("unexpected error: %v", err)
   890  				}
   891  				diff := cmp.Diff(input, out, protocmp.Transform())
   892  				if diff != "" {
   893  					t.Errorf("json not equal:\n%s", diff)
   894  				}
   895  			},
   896  		},
   897  	} {
   898  
   899  		t.Run(strconv.Itoa(i), func(t *testing.T) {
   900  			m := runtime.JSONPb{
   901  				MarshalOptions: protojson.MarshalOptions{
   902  					EmitUnpopulated: spec.emitUnpopulated,
   903  				},
   904  			}
   905  			val := spec.input
   906  			buf, err := m.Marshal(val)
   907  			if err != nil {
   908  				t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", val, err, spec)
   909  			}
   910  			if spec.verifier != nil {
   911  				spec.verifier(t, spec.input, buf)
   912  			}
   913  		})
   914  	}
   915  }