trpc.group/trpc-go/trpc-go@v1.0.3/restful/serializer_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package restful_test
    15  
    16  import (
    17  	"net/url"
    18  	"reflect"
    19  	"strings"
    20  	"testing"
    21  
    22  	"trpc.group/trpc-go/trpc-go/restful"
    23  	"trpc.group/trpc-go/trpc-go/testdata/restful/bookstore"
    24  	"trpc.group/trpc-go/trpc-go/testdata/restful/helloworld"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/stretchr/testify/require"
    28  	"google.golang.org/protobuf/encoding/protojson"
    29  	"google.golang.org/protobuf/proto"
    30  	"google.golang.org/protobuf/testing/protocmp"
    31  	"google.golang.org/protobuf/types/known/durationpb"
    32  	"google.golang.org/protobuf/types/known/emptypb"
    33  	"google.golang.org/protobuf/types/known/structpb"
    34  	"google.golang.org/protobuf/types/known/timestamppb"
    35  	"google.golang.org/protobuf/types/known/wrapperspb"
    36  )
    37  
    38  var j = &restful.JSONPBSerializer{}
    39  var f = &restful.FormSerializer{}
    40  var p = &restful.ProtoSerializer{}
    41  
    42  type anonymousSerializer struct {
    43  	restful.Serializer
    44  }
    45  
    46  func (anonymousSerializer) Name() string { return "" }
    47  
    48  type mockSerializer struct {
    49  	restful.Serializer
    50  }
    51  
    52  func (mockSerializer) Name() string        { return "mock" }
    53  func (mockSerializer) ContentType() string { return "mock" }
    54  
    55  func TestRegisterSerializer(t *testing.T) {
    56  	for _, test := range []struct {
    57  		serializer  restful.Serializer
    58  		expectPanic bool
    59  		desc        string
    60  	}{
    61  		{
    62  			serializer:  nil,
    63  			expectPanic: true,
    64  			desc:        "register nil serializer test",
    65  		},
    66  		{
    67  			serializer:  anonymousSerializer{},
    68  			expectPanic: true,
    69  			desc:        "register anonymous serializer test",
    70  		},
    71  		{
    72  			serializer:  mockSerializer{},
    73  			expectPanic: false,
    74  			desc:        "register mock serializer test",
    75  		},
    76  	} {
    77  		register := func() { restful.RegisterSerializer(test.serializer) }
    78  		if test.expectPanic {
    79  			require.Panics(t, register, test.desc)
    80  		} else {
    81  			require.NotPanics(t, register, test.desc)
    82  		}
    83  		var s restful.Serializer
    84  		if !test.expectPanic {
    85  			s = restful.GetSerializer(test.serializer.Name())
    86  			require.True(t, reflect.DeepEqual(s, test.serializer), test.desc)
    87  		}
    88  	}
    89  }
    90  
    91  func TestSetDefaultSerializer(t *testing.T) {
    92  	for _, test := range []struct {
    93  		serializer  restful.Serializer
    94  		expectPanic bool
    95  		desc        string
    96  	}{
    97  		{
    98  			serializer:  nil,
    99  			expectPanic: true,
   100  			desc:        "set nil serializer test",
   101  		},
   102  		{
   103  			serializer:  anonymousSerializer{},
   104  			expectPanic: true,
   105  			desc:        "set anonymous serializer test",
   106  		},
   107  		{
   108  			serializer:  mockSerializer{},
   109  			expectPanic: false,
   110  			desc:        "set mock serializer test",
   111  		},
   112  	} {
   113  		register := func() { restful.SetDefaultSerializer(test.serializer) }
   114  		if test.expectPanic {
   115  			require.Panics(t, register, test.desc)
   116  		} else {
   117  			require.NotPanics(t, register, test.desc)
   118  		}
   119  	}
   120  }
   121  
   122  func TestContentType(t *testing.T) {
   123  	require.Equal(t, "application/json", j.ContentType())
   124  	require.Equal(t, "application/json", f.ContentType())
   125  	require.Equal(t, "application/octet-stream", p.ContentType())
   126  }
   127  
   128  func TestProtoSerializer(t *testing.T) {
   129  	input := &helloworld.HelloRequest{
   130  		Name: "nobody",
   131  		SingleNested: &helloworld.NestedOuter{
   132  			Name: "anybody",
   133  		},
   134  		PrimitiveDoubleValue: float64(1.23),
   135  		Time: &timestamppb.Timestamp{
   136  			Seconds: int64(111111111),
   137  		},
   138  		EnumValue: helloworld.NumericEnum_ONE,
   139  		OneofValue: &helloworld.HelloRequest_OneofString{
   140  			OneofString: "oneof",
   141  		},
   142  		MappedStringValue: map[string]string{
   143  			"foo": "bar",
   144  		},
   145  	}
   146  
   147  	// marshal
   148  	wrongMarshalObj := "foobar"
   149  	_, err := p.Marshal(wrongMarshalObj)
   150  	require.NotNil(t, err)
   151  
   152  	buf, err := p.Marshal(input)
   153  	require.Nil(t, err)
   154  
   155  	// unmarshal
   156  	wrongUnmarshalObj := 1
   157  	err = p.Unmarshal(buf, &wrongUnmarshalObj)
   158  	require.NotNil(t, err)
   159  
   160  	output := &helloworld.HelloRequest{}
   161  	err = p.Unmarshal(buf, output)
   162  	require.Nil(t, err)
   163  	require.True(t, proto.Equal(input, output))
   164  }
   165  
   166  func TestJSONPBSerializer(t *testing.T) {
   167  	input := &helloworld.HelloRequest{
   168  		Name: "nobody",
   169  		SingleNested: &helloworld.NestedOuter{
   170  			Name: "anybody",
   171  		},
   172  		PrimitiveDoubleValue: float64(1.23),
   173  		Time: &timestamppb.Timestamp{
   174  			Seconds: int64(111111111),
   175  		},
   176  		EnumValue: helloworld.NumericEnum_ONE,
   177  		OneofValue: &helloworld.HelloRequest_OneofString{
   178  			OneofString: "oneof",
   179  		},
   180  		MappedStringValue: map[string]string{
   181  			"foo": "bar",
   182  		},
   183  	}
   184  	// marshal
   185  	buf, err := j.Marshal(input)
   186  	require.Nil(t, err)
   187  	// unmarshal
   188  	output := &helloworld.HelloRequest{}
   189  	err = j.Unmarshal(buf, output)
   190  	require.Nil(t, err)
   191  	require.True(t, proto.Equal(input, output))
   192  }
   193  
   194  func TestJSONPBSerializerMarshalField(t *testing.T) {
   195  	for _, test := range []struct {
   196  		input interface{}
   197  		want  []byte
   198  		desc  string
   199  	}{
   200  		{input: int32(1), want: []byte("1"), desc: "jsonpb marshal field test 01"},
   201  		{input: proto.Int32(1), want: []byte("1"), desc: "jsonpb marshal field test 02"},
   202  		{input: int64(1), want: []byte("1"), desc: "jsonpb marshal field test 03"},
   203  		{input: proto.Int64(1), want: []byte("1"), desc: "jsonpb marshal field test 04"},
   204  		{input: uint32(1), want: []byte("1"), desc: "jsonpb marshal field test 05"},
   205  		{input: proto.Uint32(1), want: []byte("1"), desc: "jsonpb marshal field test 06"},
   206  		{input: uint64(1), want: []byte("1"), desc: "jsonpb marshal field test 07"},
   207  		{input: proto.Uint64(1), want: []byte("1"), desc: "jsonpb marshal field test 08"},
   208  		{input: "abc", want: []byte(`"abc"`), desc: "jsonpb marshal field test 09"},
   209  		{input: proto.String("abc"), want: []byte(`"abc"`), desc: "jsonpb marshal field test 10"},
   210  		{input: float32(1.5), want: []byte(`1.5`), desc: "jsonpb marshal field test 11"},
   211  		{input: proto.Float32(1.5), want: []byte(`1.5`), desc: "jsonpb marshal field test 12"},
   212  		{input: float64(1.5), want: []byte(`1.5`), desc: "jsonpb marshal field test 13"},
   213  		{input: proto.Float64(1.5), want: []byte(`1.5`), desc: "jsonpb marshal field test 14"},
   214  		{input: true, want: []byte("true"), desc: "jsonpb marshal field test 15"},
   215  		{input: false, want: []byte("false"), desc: "jsonpb marshal field test 16"},
   216  		{input: (*string)(nil), want: []byte("null"), desc: "jsonpb marshal field test 17"},
   217  		{
   218  			input: helloworld.NumericEnum_ONE,
   219  			want:  []byte(`"ONE"`),
   220  			desc:  "jsonpb marshal field test 18",
   221  		},
   222  		{
   223  			input: (*helloworld.NumericEnum)(proto.Int32(int32(helloworld.NumericEnum_ONE))),
   224  			want:  []byte(`"ONE"`),
   225  			desc:  "jsonpb marshal field test 19",
   226  		},
   227  		{
   228  			input: map[string]int32{
   229  				"foo": 1,
   230  			},
   231  			want: []byte(`{"foo":1}`),
   232  			desc: "jsonpb marshal field test 20",
   233  		},
   234  		{
   235  			input: map[string]*bookstore.Book{
   236  				"foo": {Id: 123},
   237  			},
   238  			want: []byte(`{"foo":{"id":123}}`),
   239  			desc: "jsonpb marshal field test 21",
   240  		},
   241  		{
   242  			input: map[int32]*bookstore.Book{
   243  				1: {Id: 123},
   244  			},
   245  			want: []byte(`{"1":{"id":123}}`),
   246  			desc: "jsonpb marshal field test 22",
   247  		},
   248  		{
   249  			input: map[bool]*bookstore.Book{
   250  				true: {Id: 123},
   251  			},
   252  			want: []byte(`{"true":{"id":123}}`),
   253  			desc: "jsonpb marshal field test 23",
   254  		},
   255  		{
   256  			input: &durationpb.Duration{
   257  				Seconds: 123,
   258  				Nanos:   456000000,
   259  			},
   260  			want: []byte(`"123.456s"`),
   261  			desc: "jsonpb marshal field test 24",
   262  		},
   263  		{
   264  			input: &timestamppb.Timestamp{
   265  				Seconds: 1462875553,
   266  				Nanos:   123000000,
   267  			},
   268  			want: []byte(`"2016-05-10T10:19:13.123Z"`),
   269  			desc: "jsonpb marshal field test 25",
   270  		},
   271  		{
   272  			input: new(emptypb.Empty),
   273  			want:  []byte("{}"),
   274  			desc:  "jsonpb marshal field test 26",
   275  		},
   276  		{
   277  			input: &structpb.Value{
   278  				Kind: new(structpb.Value_NullValue),
   279  			},
   280  			want: []byte("null"),
   281  			desc: "jsonpb marshal field test 27",
   282  		},
   283  		{
   284  			input: &structpb.Value{
   285  				Kind: &structpb.Value_NumberValue{
   286  					NumberValue: 123.4,
   287  				},
   288  			},
   289  			want: []byte("123.4"),
   290  			desc: "jsonpb marshal field test 28",
   291  		},
   292  		{
   293  			input: &structpb.Value{
   294  				Kind: &structpb.Value_StringValue{
   295  					StringValue: "abc",
   296  				},
   297  			},
   298  			want: []byte(`"abc"`),
   299  			desc: "jsonpb marshal field test 29",
   300  		},
   301  		{
   302  			input: &structpb.Value{
   303  				Kind: &structpb.Value_BoolValue{
   304  					BoolValue: true,
   305  				},
   306  			},
   307  			want: []byte("true"),
   308  			desc: "jsonpb marshal field test 30",
   309  		},
   310  		{
   311  			input: &structpb.Struct{
   312  				Fields: map[string]*structpb.Value{
   313  					"foo_bar": {
   314  						Kind: &structpb.Value_BoolValue{
   315  							BoolValue: true,
   316  						},
   317  					},
   318  				},
   319  			},
   320  			want: []byte(`{"foo_bar":true}`),
   321  			desc: "jsonpb marshal field test 31",
   322  		},
   323  
   324  		{
   325  			input: &wrapperspb.BoolValue{Value: true},
   326  			want:  []byte("true"),
   327  			desc:  "jsonpb marshal field test 32",
   328  		},
   329  		{
   330  			input: &wrapperspb.DoubleValue{Value: 123.456},
   331  			want:  []byte("123.456"),
   332  			desc:  "jsonpb marshal field test 33",
   333  		},
   334  		{
   335  			input: &wrapperspb.FloatValue{Value: 123.456},
   336  			want:  []byte("123.456"),
   337  			desc:  "jsonpb marshal field test 34",
   338  		},
   339  		{
   340  			input: &wrapperspb.Int32Value{Value: -123},
   341  			want:  []byte("-123"),
   342  			desc:  "jsonpb marshal field test 35",
   343  		},
   344  		{
   345  			input: &wrapperspb.Int64Value{Value: -123},
   346  			want:  []byte(`"-123"`),
   347  			desc:  "jsonpb marshal field test 36",
   348  		},
   349  		{
   350  			input: &wrapperspb.UInt32Value{Value: 123},
   351  			want:  []byte("123"),
   352  			desc:  "jsonpb marshal field test 37",
   353  		},
   354  		{
   355  			input: &wrapperspb.UInt64Value{Value: 123},
   356  			want:  []byte(`"123"`),
   357  			desc:  "jsonpb marshal field test 38",
   358  		},
   359  		{
   360  			input: []**bookstore.Book{},
   361  			want:  []byte("[]"),
   362  			desc:  "jsonpb marshal field test 39",
   363  		},
   364  		{
   365  			input: []*bookstore.Book{{Id: 1}},
   366  			want:  []byte(`[{"id":"1","author":"","title":"","content":null}]`),
   367  			desc:  "jsonpb marshal field test 40",
   368  		},
   369  		{
   370  			input: nil,
   371  			want:  []byte("null"),
   372  			desc:  "jsonpb marshal field test 41",
   373  		},
   374  	} {
   375  		got, err := j.Marshal(test.input)
   376  		require.Nil(t, err, test.desc)
   377  		s := strings.Replace(string(got), " ", "", -1)
   378  		s = strings.Replace(s, "\n", "", -1)
   379  		s = strings.Replace(s, "\t", "", -1)
   380  		require.Equal(t, test.want, []byte(s), test.desc)
   381  	}
   382  }
   383  
   384  func TestJSONPBSerializerUnmarshalField(t *testing.T) {
   385  	for _, test := range []struct {
   386  		input []byte
   387  		want  interface{}
   388  		desc  string
   389  	}{
   390  		{input: []byte("1"), want: int32(1), desc: "jsonpb unmarshal field test 01"},
   391  		{input: []byte("1"), want: proto.Int32(1), desc: "jsonpb unmarshal field test 02"},
   392  		{input: []byte("1"), want: int64(1), desc: "jsonpb unmarshal field test 03"},
   393  		{input: []byte("1"), want: proto.Int64(1), desc: "jsonpb unmarshal field test 04"},
   394  		{input: []byte("1"), want: uint32(1), desc: "jsonpb unmarshal field test 05"},
   395  		{input: []byte("1"), want: proto.Uint32(1), desc: "jsonpb unmarshal field test 06"},
   396  		{input: []byte("1"), want: uint64(1), desc: "jsonpb unmarshal field test 07"},
   397  		{input: []byte("1"), want: proto.Uint64(1), desc: "jsonpb unmarshal field test 08"},
   398  		{input: []byte(`"abc"`), want: "abc", desc: "jsonpb unmarshal field test 09"},
   399  		{input: []byte(`"abc"`), want: proto.String("abc"), desc: "jsonpb unmarshal field test 10"},
   400  		{input: []byte(`1.5`), want: float32(1.5), desc: "jsonpb unmarshal field test 11"},
   401  		{input: []byte(`1.5`), want: proto.Float32(1.5), desc: "jsonpb unmarshal field test 12"},
   402  		{input: []byte(`1.5`), want: float64(1.5), desc: "jsonpb unmarshal field test 13"},
   403  		{input: []byte(`1.5`), want: proto.Float64(1.5), desc: "jsonpb unmarshal field test 14"},
   404  		{input: []byte("true"), want: true, desc: "jsonpb unmarshal field test 15"},
   405  		{input: []byte("false"), want: false, desc: "jsonpb unmarshal field test 16"},
   406  		{input: []byte("null"), want: (*string)(nil), desc: "jsonpb unmarshal field test 17"},
   407  		{
   408  			input: []byte("1"),
   409  			want:  helloworld.NumericEnum_ONE,
   410  			desc:  "jsonpb unmarshal field test 18",
   411  		},
   412  		{
   413  			input: []byte("1"),
   414  			want:  (*helloworld.NumericEnum)(proto.Int32(int32(helloworld.NumericEnum_ONE))),
   415  			desc:  "jsonpb unmarshal field test 19",
   416  		},
   417  		{
   418  			input: []byte(`{"foo":1}`),
   419  			want: map[string]int32{
   420  				"foo": 1,
   421  			},
   422  			desc: "jsonpb unmarshal field test 20",
   423  		},
   424  		{
   425  			input: []byte(`{"foo":{"id":123}}`),
   426  			want: map[string]*bookstore.Book{
   427  				"foo": {Id: 123},
   428  			},
   429  			desc: "jsonpb unmarshal field test 21",
   430  		},
   431  		{
   432  			input: []byte(`{"1":{"id":123}}`),
   433  			want: map[int32]*bookstore.Book{
   434  				1: {Id: 123},
   435  			},
   436  			desc: "jsonpb unmarshal field test 22",
   437  		},
   438  		{
   439  			input: []byte(`{"true":{"id":123}}`),
   440  			want: map[bool]*bookstore.Book{
   441  				true: {Id: 123},
   442  			},
   443  			desc: "jsonpb unmarshal field test 23",
   444  		},
   445  		{
   446  			input: []byte(`"123.456s"`),
   447  			want: &durationpb.Duration{
   448  				Seconds: 123,
   449  				Nanos:   456000000,
   450  			},
   451  			desc: "jsonpb unmarshal field test 24",
   452  		},
   453  		{
   454  			input: []byte(`"2016-05-10T10:19:13.123Z"`),
   455  			want: &timestamppb.Timestamp{
   456  				Seconds: 1462875553,
   457  				Nanos:   123000000,
   458  			},
   459  			desc: "jsonpb unmarshal field test 25",
   460  		},
   461  		{
   462  			input: []byte("{}"),
   463  			want:  new(emptypb.Empty),
   464  			desc:  "jsonpb unmarshal field test 26",
   465  		},
   466  		{
   467  			input: []byte("null"),
   468  			want: &structpb.Value{
   469  				Kind: new(structpb.Value_NullValue),
   470  			},
   471  			desc: "jsonpb unmarshal field test 27",
   472  		},
   473  		{
   474  			input: []byte("123.4"),
   475  			want: &structpb.Value{
   476  				Kind: &structpb.Value_NumberValue{
   477  					NumberValue: 123.4,
   478  				},
   479  			},
   480  			desc: "jsonpb unmarshal field test 28",
   481  		},
   482  		{
   483  			input: []byte(`"abc"`),
   484  			want: &structpb.Value{
   485  				Kind: &structpb.Value_StringValue{
   486  					StringValue: "abc",
   487  				},
   488  			},
   489  			desc: "jsonpb unmarshal field test 29",
   490  		},
   491  		{
   492  			input: []byte("true"),
   493  			want: &structpb.Value{
   494  				Kind: &structpb.Value_BoolValue{
   495  					BoolValue: true,
   496  				},
   497  			},
   498  			desc: "jsonpb unmarshal field test 30",
   499  		},
   500  		{
   501  			input: []byte(`{"foo_bar":true}`),
   502  			want: &structpb.Struct{
   503  				Fields: map[string]*structpb.Value{
   504  					"foo_bar": {
   505  						Kind: &structpb.Value_BoolValue{
   506  							BoolValue: true,
   507  						},
   508  					},
   509  				},
   510  			},
   511  			desc: "jsonpb unmarshal field test 31",
   512  		},
   513  		{
   514  			input: []byte("true"),
   515  			want:  &wrapperspb.BoolValue{Value: true},
   516  			desc:  "jsonpb unmarshal field test 32",
   517  		},
   518  		{
   519  			input: []byte("123.456"),
   520  			want:  &wrapperspb.DoubleValue{Value: 123.456},
   521  			desc:  "jsonpb unmarshal field test 33",
   522  		},
   523  		{
   524  			input: []byte("123.456"),
   525  			want:  &wrapperspb.FloatValue{Value: 123.456},
   526  			desc:  "jsonpb unmarshal field test 34",
   527  		},
   528  		{
   529  			input: []byte("-123"),
   530  			want:  &wrapperspb.Int32Value{Value: -123},
   531  			desc:  "jsonpb unmarshal field test 35",
   532  		},
   533  		{
   534  			input: []byte(`"-123"`),
   535  			want:  &wrapperspb.Int64Value{Value: -123},
   536  			desc:  "jsonpb unmarshal field test 36",
   537  		},
   538  		{
   539  			input: []byte("123"),
   540  			want:  &wrapperspb.UInt32Value{Value: 123},
   541  			desc:  "jsonpb unmarshal field test 37",
   542  		},
   543  		{
   544  			input: []byte(`"123"`),
   545  			want:  &wrapperspb.UInt64Value{Value: 123},
   546  			desc:  "jsonpb unmarshal field test 38",
   547  		},
   548  		{
   549  			input: []byte(`{"1":"foo"}`),
   550  			want: map[uint32]string{
   551  				1: "foo",
   552  			},
   553  			desc: "jsonpb unmarshal field test 39",
   554  		},
   555  		{
   556  			input: []byte(`{"1":"foo"}`),
   557  			want: map[int64]string{
   558  				1: "foo",
   559  			},
   560  			desc: "jsonpb unmarshal field test 40",
   561  		},
   562  		{
   563  			input: []byte(`{"1":"foo"}`),
   564  			want: map[uint64]string{
   565  				1: "foo",
   566  			},
   567  			desc: "jsonpb unmarshal field test 41",
   568  		},
   569  		{
   570  			input: []byte(`{"1":"foo"}`),
   571  			want: map[float32]string{
   572  				1: "foo",
   573  			},
   574  			desc: "jsonpb unmarshal field test 42",
   575  		},
   576  		{
   577  			input: []byte(`{"1":"foo"}`),
   578  			want: map[float64]string{
   579  				1: "foo",
   580  			},
   581  			desc: "jsonpb unmarshal field test 43",
   582  		},
   583  		{
   584  			input: []byte(`{"1":null}`),
   585  			want: map[float64]*string{
   586  				1: nil,
   587  			},
   588  			desc: "jsonpb unmarshal field test 44",
   589  		},
   590  		{
   591  			input: []byte(`[{"id":"1"},{"id":"2"}]`),
   592  			want: []*bookstore.Book{
   593  				{Id: 1}, {Id: 2},
   594  			},
   595  			desc: "jsonpb unmarshal field test 45",
   596  		},
   597  		{
   598  			input: []byte(`[{"a":true},{"b":true}]`),
   599  			want: []helloworld.NestedInner{
   600  				{A: true}, {B: true},
   601  			},
   602  			desc: "jsonpb unmarshal field test 46",
   603  		},
   604  	} {
   605  		rflValue := reflect.New(reflect.TypeOf(test.want))
   606  		err := j.Unmarshal(test.input, rflValue.Interface())
   607  		require.Nil(t, err, test.desc)
   608  		require.Equal(t, "", cmp.Diff(rflValue.Elem().Interface(), test.want, protocmp.Transform()), test.desc)
   609  	}
   610  }
   611  
   612  func TestFormSerializerMarshal(t *testing.T) {
   613  	for _, test := range []struct {
   614  		input           interface{}
   615  		emitUnpopupated bool
   616  		expect          string
   617  		desc            string
   618  	}{
   619  		{
   620  			input: &helloworld.HelloRequest{
   621  				Name: "nobody",
   622  				SingleNested: &helloworld.NestedOuter{
   623  					Name: "anybody",
   624  				},
   625  				PrimitiveDoubleValue: float64(1.23),
   626  				Time: &timestamppb.Timestamp{
   627  					Seconds: int64(111111111),
   628  				},
   629  				EnumValue: helloworld.NumericEnum_ONE,
   630  				OneofValue: &helloworld.HelloRequest_OneofString{
   631  					OneofString: "oneof",
   632  				},
   633  				MappedStringValue: map[string]string{
   634  					"foo": "bar",
   635  				},
   636  			},
   637  			emitUnpopupated: false,
   638  			expect: `{
   639  						"name":"nobody", 
   640  						"singleNested":{"name":"anybody"}, 
   641  						"primitiveDoubleValue":1.23, 
   642  						"enumValue":"ONE", 
   643  						"oneofString":"oneof", 
   644  						"mappedStringValue":{"foo":"bar"}, 
   645  						"time":"1973-07-10T00:11:51Z"
   646  					}`,
   647  			desc: "form serializer marshal proto message test ",
   648  		},
   649  		{
   650  			input:           helloworld.NumericEnum_ONE,
   651  			emitUnpopupated: true,
   652  			expect:          `"ONE"`,
   653  			desc:            "form serializer marshal non proto field test",
   654  		},
   655  	} {
   656  		restful.Marshaller.EmitUnpopulated = test.emitUnpopupated
   657  		buf, err := f.Marshal(test.input)
   658  		require.Nil(t, err)
   659  		want := strings.Replace(test.expect, " ", "", -1)
   660  		want = strings.Replace(want, "\n", "", -1)
   661  		want = strings.Replace(want, "\t", "", -1)
   662  		got := strings.Replace(string(buf), " ", "", -1)
   663  		got = strings.Replace(got, "\n", "", -1)
   664  		got = strings.Replace(got, "\t", "", -1)
   665  		require.Equal(t, want, got, test.desc)
   666  	}
   667  }
   668  
   669  func TestFormSerializerUnmarshal(t *testing.T) {
   670  	for _, test := range []struct {
   671  		data         []byte
   672  		unmarshalObj interface{}
   673  		want         interface{}
   674  		wantErr      bool
   675  		desc         string
   676  	}{
   677  		{
   678  			data: []byte(url.Values{
   679  				"name":                   []string{"nobody"},
   680  				"single_nested.name":     []string{"anybody"},
   681  				"primitive_bool_value":   []string{"true"},
   682  				"primitive_int32_value":  []string{"1"},
   683  				"primitive_uint32_value": []string{"1"},
   684  				"primitive_int64_value":  []string{"1"},
   685  				"primitive_uint64_value": []string{"1"},
   686  				"primitive_float_value":  []string{"1"},
   687  				"primitive_double_value": []string{"1.23"},
   688  				"primitive_bytes_value":  []string{""},
   689  				"time":                   []string{"1970-01-01T00:00:01Z"},
   690  				"duration":               []string{"0"},
   691  				"wrapped_bool_value":     []string{"true"},
   692  				"wrapped_int32_value":    []string{"1"},
   693  				"wrapped_uint32_value":   []string{"1"},
   694  				"wrapped_int64_value":    []string{"1"},
   695  				"wrapped_uint64_value":   []string{"1"},
   696  				"wrapped_float_value":    []string{"1"},
   697  				"wrapped_double_value":   []string{"1"},
   698  				"wrapped_str_value":      []string{"foo"},
   699  				"wrapped_bytes_value":    []string{""},
   700  				"enum_value":             []string{"1"},
   701  				"oneof_string":           []string{"oneof"},
   702  				"mapped_string_value":    []string{"foo", "bar"},
   703  				"repeated_string_value":  []string{"foobar", "foo", "bar", "baz"},
   704  			}.Encode()),
   705  			unmarshalObj: &helloworld.HelloRequest{},
   706  			want: &helloworld.HelloRequest{
   707  				Name: "nobody",
   708  				SingleNested: &helloworld.NestedOuter{
   709  					Name: "anybody",
   710  				},
   711  				PrimitiveBoolValue:   true,
   712  				PrimitiveInt32Value:  1,
   713  				PrimitiveUint32Value: 1,
   714  				PrimitiveInt64Value:  1,
   715  				PrimitiveUint64Value: 1,
   716  				PrimitiveFloatValue:  1,
   717  				PrimitiveDoubleValue: float64(1.23),
   718  				PrimitiveBytesValue:  []byte(""),
   719  				Time: &timestamppb.Timestamp{
   720  					Seconds: int64(1),
   721  				},
   722  				Duration:           &durationpb.Duration{},
   723  				WrappedBoolValue:   &wrapperspb.BoolValue{Value: true},
   724  				WrappedFloatValue:  &wrapperspb.FloatValue{Value: 1},
   725  				WrappedStrValue:    &wrapperspb.StringValue{Value: "foo"},
   726  				WrappedBytesValue:  &wrapperspb.BytesValue{},
   727  				WrappedInt32Value:  &wrapperspb.Int32Value{Value: 1},
   728  				WrappedUint32Value: &wrapperspb.UInt32Value{Value: 1},
   729  				WrappedDoubleValue: &wrapperspb.DoubleValue{Value: 1},
   730  				WrappedInt64Value:  &wrapperspb.Int64Value{Value: 1},
   731  				WrappedUint64Value: &wrapperspb.UInt64Value{Value: 1},
   732  				EnumValue:          helloworld.NumericEnum_ONE,
   733  				OneofValue: &helloworld.HelloRequest_OneofString{
   734  					OneofString: "oneof",
   735  				},
   736  				RepeatedStringValue: []string{
   737  					"foobar", "foo", "bar", "baz",
   738  				},
   739  				MappedStringValue: map[string]string{
   740  					"foo": "bar",
   741  				},
   742  			},
   743  			wantErr: false,
   744  			desc:    "form serializer unmarshal to proto message test",
   745  		},
   746  		{
   747  			data:         []byte("!@#$%^&"),
   748  			unmarshalObj: &helloworld.HelloRequest{},
   749  			want:         nil,
   750  			wantErr:      true,
   751  			desc:         "form serializer unmarshal invalid data test",
   752  		},
   753  		{
   754  			data: []byte(url.Values{
   755  				"primitive_string_value": []string{"foo", "bar"},
   756  			}.Encode()),
   757  			unmarshalObj: &helloworld.HelloRequest{},
   758  			want:         nil,
   759  			wantErr:      true,
   760  			desc:         "form serializer unmarshal invalid len of values test",
   761  		},
   762  		{
   763  			data: []byte(url.Values{
   764  				"primitive_int32_value": []string{"foo"},
   765  			}.Encode()),
   766  			unmarshalObj: &helloworld.HelloRequest{},
   767  			want:         nil,
   768  			wantErr:      true,
   769  			desc:         "form serializer unmarshal invalid field data test",
   770  		},
   771  		{
   772  			data: []byte(url.Values{
   773  				"mapped_string_value": []string{"foo", "bar", "baz"},
   774  			}.Encode()),
   775  			unmarshalObj: &helloworld.HelloRequest{},
   776  			want:         nil,
   777  			wantErr:      true,
   778  			desc:         "form serializer unmarshal map invalid len of values test",
   779  		},
   780  		{
   781  			data: []byte(url.Values{
   782  				"mapped_enum_value": []string{"foo", "bar"},
   783  			}.Encode()),
   784  			unmarshalObj: &helloworld.HelloRequest{},
   785  			want:         nil,
   786  			wantErr:      true,
   787  			desc:         "form serializer unmarshal map invalid value test",
   788  		},
   789  		{
   790  			data: []byte(url.Values{
   791  				"repeated_enum_value": []string{"foo", "bar"},
   792  			}.Encode()),
   793  			unmarshalObj: &helloworld.HelloRequest{},
   794  			want:         nil,
   795  			wantErr:      true,
   796  			desc:         "form serializer unmarshal repeated test",
   797  		},
   798  		{
   799  			data: []byte(url.Values{
   800  				"wrapped_bool_value": []string{"foo"},
   801  			}.Encode()),
   802  			unmarshalObj: &helloworld.HelloRequest{},
   803  			want:         nil,
   804  			wantErr:      true,
   805  			desc:         "form serializer unmarshal google.protobuf.bool field data test",
   806  		},
   807  		{
   808  			data: []byte(url.Values{
   809  				"wrapped_int32_value": []string{"foo"},
   810  			}.Encode()),
   811  			unmarshalObj: &helloworld.HelloRequest{},
   812  			want:         nil,
   813  			wantErr:      true,
   814  			desc:         "form serializer unmarshal google.protobuf.int32 field data test",
   815  		},
   816  		{
   817  			data: []byte(url.Values{
   818  				"foo": []string{"bar"},
   819  			}.Encode()),
   820  			unmarshalObj: 1,
   821  			want:         nil,
   822  			wantErr:      true,
   823  			desc:         "form serializer unmarshal to wrong obj test",
   824  		},
   825  	} {
   826  		err := f.Unmarshal(test.data, test.unmarshalObj)
   827  		if test.wantErr {
   828  			require.NotNil(t, err, test.desc)
   829  		} else {
   830  			require.Nil(t, err, test.desc)
   831  			require.Equal(t, "", cmp.Diff(test.unmarshalObj, test.want, protocmp.Transform()), test.desc)
   832  		}
   833  	}
   834  }
   835  
   836  func TestJSONPBSerializerMarshalOptions(t *testing.T) {
   837  	for _, test := range []struct {
   838  		input   interface{}
   839  		option  func(*protojson.MarshalOptions)
   840  		want    []byte
   841  		wantErr bool
   842  		desc    string
   843  	}{
   844  		{
   845  			input: ([]*helloworld.HelloRequest)(nil),
   846  			option: func(o *protojson.MarshalOptions) {
   847  				o.EmitUnpopulated = true
   848  			},
   849  			want:    []byte("[]"),
   850  			wantErr: false,
   851  			desc:    "jsonpb marshal options test 01",
   852  		},
   853  		{
   854  			input: map[string]string{"foo": "bar"},
   855  			option: func(o *protojson.MarshalOptions) {
   856  				o.Indent = "  "
   857  			},
   858  			want: []byte(`{
   859    "foo": "bar"
   860  }`),
   861  			wantErr: false,
   862  			desc:    "jsonpb marshal options test 02",
   863  		},
   864  	} {
   865  		test.option(&restful.Marshaller)
   866  		got, err := j.Marshal(test.input)
   867  		if test.wantErr {
   868  			require.NotNil(t, err, test.desc)
   869  		} else {
   870  			require.Nil(t, err, test.desc)
   871  			require.Equal(t, got, test.want, test.desc)
   872  		}
   873  	}
   874  }
   875  
   876  func TestJSONPBAllowUnmarshalNil(t *testing.T) {
   877  	var req helloworld.HelloRequest
   878  	j.AllowUnmarshalNil = true
   879  	err := j.Unmarshal([]byte{}, &req)
   880  	require.Nil(t, err)
   881  	require.True(t, reflect.DeepEqual(&req, &helloworld.HelloRequest{}))
   882  }