...

Source file src/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb_test.go

Documentation: github.com/grpc-ecosystem/grpc-gateway/runtime

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

View as plain text