github.com/Finschia/finschia-sdk@v0.48.1/codec/unknownproto/unknown_fields_test.go (about)

     1  package unknownproto
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/gogo/protobuf/proto"
    10  
    11  	"github.com/Finschia/finschia-sdk/codec/types"
    12  	"github.com/Finschia/finschia-sdk/testutil/testdata"
    13  )
    14  
    15  func TestRejectUnknownFieldsRepeated(t *testing.T) {
    16  	tests := []struct {
    17  		name                     string
    18  		in                       proto.Message
    19  		recv                     proto.Message
    20  		wantErr                  error
    21  		allowUnknownNonCriticals bool
    22  		hasUnknownNonCriticals   bool
    23  	}{
    24  		{
    25  			name: "Unknown field in midst of repeated values",
    26  			in: &testdata.TestVersion2{
    27  				C: []*testdata.TestVersion2{
    28  					{
    29  						C: []*testdata.TestVersion2{
    30  							{
    31  								Sum: &testdata.TestVersion2_F{
    32  									F: &testdata.TestVersion2{
    33  										A: &testdata.TestVersion2{
    34  											B: &testdata.TestVersion2{
    35  												H: []*testdata.TestVersion1{
    36  													{
    37  														X: 0x01,
    38  													},
    39  												},
    40  											},
    41  										},
    42  									},
    43  								},
    44  							},
    45  							{
    46  								Sum: &testdata.TestVersion2_F{
    47  									F: &testdata.TestVersion2{
    48  										A: &testdata.TestVersion2{
    49  											B: &testdata.TestVersion2{
    50  												H: []*testdata.TestVersion1{
    51  													{
    52  														X: 0x02,
    53  													},
    54  												},
    55  											},
    56  										},
    57  									},
    58  								},
    59  							},
    60  							{
    61  								Sum: &testdata.TestVersion2_F{
    62  									F: &testdata.TestVersion2{
    63  										NewField: 411,
    64  									},
    65  								},
    66  							},
    67  						},
    68  					},
    69  				},
    70  			},
    71  			recv: new(testdata.TestVersion1),
    72  			wantErr: &errUnknownField{
    73  				Type:     "*testdata.TestVersion1",
    74  				TagNum:   25,
    75  				WireType: 0,
    76  			},
    77  		},
    78  		{
    79  			name:                     "Unknown field in midst of repeated values, allowUnknownNonCriticals set",
    80  			allowUnknownNonCriticals: true,
    81  			in: &testdata.TestVersion2{
    82  				C: []*testdata.TestVersion2{
    83  					{
    84  						C: []*testdata.TestVersion2{
    85  							{
    86  								Sum: &testdata.TestVersion2_F{
    87  									F: &testdata.TestVersion2{
    88  										A: &testdata.TestVersion2{
    89  											B: &testdata.TestVersion2{
    90  												H: []*testdata.TestVersion1{
    91  													{
    92  														X: 0x01,
    93  													},
    94  												},
    95  											},
    96  										},
    97  									},
    98  								},
    99  							},
   100  							{
   101  								Sum: &testdata.TestVersion2_F{
   102  									F: &testdata.TestVersion2{
   103  										A: &testdata.TestVersion2{
   104  											B: &testdata.TestVersion2{
   105  												H: []*testdata.TestVersion1{
   106  													{
   107  														X: 0x02,
   108  													},
   109  												},
   110  											},
   111  										},
   112  									},
   113  								},
   114  							},
   115  							{
   116  								Sum: &testdata.TestVersion2_F{
   117  									F: &testdata.TestVersion2{
   118  										NewField: 411,
   119  									},
   120  								},
   121  							},
   122  						},
   123  					},
   124  				},
   125  			},
   126  			recv: new(testdata.TestVersion1),
   127  			wantErr: &errUnknownField{
   128  				Type:     "*testdata.TestVersion1",
   129  				TagNum:   25,
   130  				WireType: 0,
   131  			},
   132  		},
   133  		{
   134  			name: "Unknown field in midst of repeated values, non-critical field to be rejected",
   135  			in: &testdata.TestVersion3{
   136  				C: []*testdata.TestVersion3{
   137  					{
   138  						C: []*testdata.TestVersion3{
   139  							{
   140  								Sum: &testdata.TestVersion3_F{
   141  									F: &testdata.TestVersion3{
   142  										A: &testdata.TestVersion3{
   143  											B: &testdata.TestVersion3{
   144  												X: 0x01,
   145  											},
   146  										},
   147  									},
   148  								},
   149  							},
   150  							{
   151  								Sum: &testdata.TestVersion3_F{
   152  									F: &testdata.TestVersion3{
   153  										A: &testdata.TestVersion3{
   154  											B: &testdata.TestVersion3{
   155  												X: 0x02,
   156  											},
   157  										},
   158  									},
   159  								},
   160  							},
   161  							{
   162  								Sum: &testdata.TestVersion3_F{
   163  									F: &testdata.TestVersion3{
   164  										NonCriticalField: "non-critical",
   165  									},
   166  								},
   167  							},
   168  						},
   169  					},
   170  				},
   171  			},
   172  			recv: new(testdata.TestVersion1),
   173  			wantErr: &errUnknownField{
   174  				Type:     "*testdata.TestVersion1",
   175  				TagNum:   1031,
   176  				WireType: 2,
   177  			},
   178  			hasUnknownNonCriticals: true,
   179  		},
   180  		{
   181  			name:                     "Unknown field in midst of repeated values, non-critical field ignored",
   182  			allowUnknownNonCriticals: true,
   183  			in: &testdata.TestVersion3{
   184  				C: []*testdata.TestVersion3{
   185  					{
   186  						C: []*testdata.TestVersion3{
   187  							{
   188  								Sum: &testdata.TestVersion3_F{
   189  									F: &testdata.TestVersion3{
   190  										A: &testdata.TestVersion3{
   191  											B: &testdata.TestVersion3{
   192  												X: 0x01,
   193  											},
   194  										},
   195  									},
   196  								},
   197  							},
   198  							{
   199  								Sum: &testdata.TestVersion3_F{
   200  									F: &testdata.TestVersion3{
   201  										A: &testdata.TestVersion3{
   202  											B: &testdata.TestVersion3{
   203  												X: 0x02,
   204  											},
   205  										},
   206  									},
   207  								},
   208  							},
   209  							{
   210  								Sum: &testdata.TestVersion3_F{
   211  									F: &testdata.TestVersion3{
   212  										NonCriticalField: "non-critical",
   213  									},
   214  								},
   215  							},
   216  						},
   217  					},
   218  				},
   219  			},
   220  			recv:                   new(testdata.TestVersion1),
   221  			wantErr:                nil,
   222  			hasUnknownNonCriticals: true,
   223  		},
   224  	}
   225  
   226  	for _, tt := range tests {
   227  		tt := tt
   228  		t.Run(tt.name, func(t *testing.T) {
   229  			protoBlob, err := proto.Marshal(tt.in)
   230  			if err != nil {
   231  				t.Fatal(err)
   232  			}
   233  			hasUnknownNonCriticals, gotErr := RejectUnknownFields(protoBlob, tt.recv, tt.allowUnknownNonCriticals, DefaultAnyResolver{})
   234  			require.Equal(t, tt.wantErr, gotErr)
   235  			require.Equal(t, tt.hasUnknownNonCriticals, hasUnknownNonCriticals)
   236  		})
   237  	}
   238  }
   239  
   240  func TestRejectUnknownFields_allowUnknownNonCriticals(t *testing.T) {
   241  	tests := []struct {
   242  		name                     string
   243  		in                       proto.Message
   244  		allowUnknownNonCriticals bool
   245  		wantErr                  error
   246  	}{
   247  		{
   248  			name: "Field that's in the reserved range, should fail by default",
   249  			in: &testdata.Customer2{
   250  				Id:       289,
   251  				Reserved: 99,
   252  			},
   253  			wantErr: &errUnknownField{
   254  				Type:     "*testdata.Customer1",
   255  				TagNum:   1047,
   256  				WireType: 0,
   257  			},
   258  		},
   259  		{
   260  			name:                     "Field that's in the reserved range, toggle allowUnknownNonCriticals",
   261  			allowUnknownNonCriticals: true,
   262  			in: &testdata.Customer2{
   263  				Id:       289,
   264  				Reserved: 99,
   265  			},
   266  			wantErr: nil,
   267  		},
   268  		{
   269  			name:                     "Unknown fields that are critical, but with allowUnknownNonCriticals set",
   270  			allowUnknownNonCriticals: true,
   271  			in: &testdata.Customer2{
   272  				Id:   289,
   273  				City: testdata.Customer2_PaloAlto,
   274  			},
   275  			wantErr: &errUnknownField{
   276  				Type:     "*testdata.Customer1",
   277  				TagNum:   6,
   278  				WireType: 0,
   279  			},
   280  		},
   281  	}
   282  
   283  	for _, tt := range tests {
   284  		tt := tt
   285  		t.Run(tt.name, func(t *testing.T) {
   286  			blob, err := proto.Marshal(tt.in)
   287  			if err != nil {
   288  				t.Fatalf("Failed to marshal input: %v", err)
   289  			}
   290  
   291  			c1 := new(testdata.Customer1)
   292  			_, gotErr := RejectUnknownFields(blob, c1, tt.allowUnknownNonCriticals, DefaultAnyResolver{})
   293  			if !reflect.DeepEqual(gotErr, tt.wantErr) {
   294  				t.Fatalf("Error mismatch\nGot:\n%s\n\nWant:\n%s", gotErr, tt.wantErr)
   295  			}
   296  		})
   297  	}
   298  }
   299  
   300  func TestRejectUnknownFieldsNested(t *testing.T) {
   301  	tests := []struct {
   302  		name    string
   303  		in      proto.Message
   304  		recv    proto.Message
   305  		wantErr error
   306  	}{
   307  		{
   308  			name: "TestVersion3 from TestVersionFD1",
   309  			in: &testdata.TestVersion2{
   310  				X: 5,
   311  				Sum: &testdata.TestVersion2_E{
   312  					E: 100,
   313  				},
   314  				H: []*testdata.TestVersion1{
   315  					{X: 999},
   316  					{X: -55},
   317  					{
   318  						X: 102,
   319  						Sum: &testdata.TestVersion1_F{
   320  							F: &testdata.TestVersion1{
   321  								X: 4,
   322  							},
   323  						},
   324  					},
   325  				},
   326  				Customer1: &testdata.Customer1{
   327  					Id:              45,
   328  					Name:            "customer1",
   329  					SubscriptionFee: 99,
   330  				},
   331  			},
   332  			recv: new(testdata.TestVersionFD1),
   333  			wantErr: &errUnknownField{
   334  				Type:     "*testdata.TestVersionFD1",
   335  				TagNum:   12,
   336  				WireType: 2,
   337  			},
   338  		},
   339  		{
   340  			name: "Alternating oneofs",
   341  			in: &testdata.TestVersion3{
   342  				Sum: &testdata.TestVersion3_E{
   343  					E: 99,
   344  				},
   345  			},
   346  			recv:    new(testdata.TestVersion3LoneOneOfValue),
   347  			wantErr: nil,
   348  		},
   349  		{
   350  			name: "Alternating oneofs mismatched field",
   351  			in: &testdata.TestVersion3{
   352  				Sum: &testdata.TestVersion3_F{
   353  					F: &testdata.TestVersion3{
   354  						X: 99,
   355  					},
   356  				},
   357  			},
   358  			recv: new(testdata.TestVersion3LoneOneOfValue),
   359  			wantErr: &errUnknownField{
   360  				Type:     "*testdata.TestVersion3LoneOneOfValue",
   361  				TagNum:   7,
   362  				WireType: 2,
   363  			},
   364  		},
   365  		{
   366  			name: "Discrepancy in a deeply nested one of field",
   367  			in: &testdata.TestVersion3{
   368  				Sum: &testdata.TestVersion3_F{
   369  					F: &testdata.TestVersion3{
   370  						Sum: &testdata.TestVersion3_F{
   371  							F: &testdata.TestVersion3{
   372  								X: 19,
   373  								Sum: &testdata.TestVersion3_E{
   374  									E: 99,
   375  								},
   376  							},
   377  						},
   378  					},
   379  				},
   380  			},
   381  			recv: new(testdata.TestVersion3LoneNesting),
   382  			wantErr: &errUnknownField{
   383  				Type:     "*testdata.TestVersion3LoneNesting",
   384  				TagNum:   6,
   385  				WireType: 0,
   386  			},
   387  		},
   388  		{
   389  			name: "unknown field types.Any in G",
   390  			in: &testdata.TestVersion3{
   391  				G: &types.Any{
   392  					TypeUrl: "/testdata.TestVersion1",
   393  					Value: mustMarshal(&testdata.TestVersion2{
   394  						Sum: &testdata.TestVersion2_F{
   395  							F: &testdata.TestVersion2{
   396  								NewField: 999,
   397  							},
   398  						},
   399  					}),
   400  				},
   401  			},
   402  			recv: new(testdata.TestVersion3),
   403  			wantErr: &errUnknownField{
   404  				Type:   "*testdata.TestVersion1",
   405  				TagNum: 25,
   406  			},
   407  		},
   408  		{
   409  			name: "types.Any with extra fields",
   410  			in: &testdata.TestVersionFD1WithExtraAny{
   411  				G: &testdata.AnyWithExtra{
   412  					Any: &types.Any{
   413  						TypeUrl: "/testdata.TestVersion1",
   414  						Value: mustMarshal(&testdata.TestVersion2{
   415  							Sum: &testdata.TestVersion2_F{
   416  								F: &testdata.TestVersion2{
   417  									NewField: 999,
   418  								},
   419  							},
   420  						}),
   421  					},
   422  					B: 3,
   423  					C: 2,
   424  				},
   425  			},
   426  			recv: new(testdata.TestVersion3),
   427  			wantErr: &errUnknownField{
   428  				Type:     "*types.Any",
   429  				TagNum:   3,
   430  				WireType: 0,
   431  			},
   432  		},
   433  		{
   434  			name: "mismatched types.Any in G",
   435  			in: &testdata.TestVersion1{
   436  				G: &types.Any{
   437  					TypeUrl: "/testdata.TestVersion4LoneNesting",
   438  					Value: mustMarshal(&testdata.TestVersion3LoneNesting_Inner1{
   439  						Inner: &testdata.TestVersion3LoneNesting_Inner1_InnerInner{
   440  							Id:   "ID",
   441  							City: "Gotham",
   442  						},
   443  					}),
   444  				},
   445  			},
   446  			recv: new(testdata.TestVersion1),
   447  			wantErr: &errMismatchedWireType{
   448  				Type:         "*testdata.TestVersion3",
   449  				TagNum:       8,
   450  				GotWireType:  7,
   451  				WantWireType: 2,
   452  			},
   453  		},
   454  		{
   455  			name: "From nested proto message, message index 0",
   456  			in: &testdata.TestVersion3LoneNesting{
   457  				Inner1: &testdata.TestVersion3LoneNesting_Inner1{
   458  					Id:   10,
   459  					Name: "foo",
   460  					Inner: &testdata.TestVersion3LoneNesting_Inner1_InnerInner{
   461  						Id:   "ID",
   462  						City: "Palo Alto",
   463  					},
   464  				},
   465  			},
   466  			recv:    new(testdata.TestVersion4LoneNesting),
   467  			wantErr: nil,
   468  		},
   469  		{
   470  			name: "From nested proto message, message index 1",
   471  			in: &testdata.TestVersion3LoneNesting{
   472  				Inner2: &testdata.TestVersion3LoneNesting_Inner2{
   473  					Id:      "ID",
   474  					Country: "Maldives",
   475  					Inner: &testdata.TestVersion3LoneNesting_Inner2_InnerInner{
   476  						Id:   "ID",
   477  						City: "Unknown",
   478  					},
   479  				},
   480  			},
   481  			recv:    new(testdata.TestVersion4LoneNesting),
   482  			wantErr: nil,
   483  		},
   484  	}
   485  
   486  	for _, tt := range tests {
   487  		tt := tt
   488  		t.Run(tt.name, func(t *testing.T) {
   489  			protoBlob, err := proto.Marshal(tt.in)
   490  			if err != nil {
   491  				t.Fatal(err)
   492  			}
   493  			gotErr := RejectUnknownFieldsStrict(protoBlob, tt.recv, DefaultAnyResolver{})
   494  			if !reflect.DeepEqual(gotErr, tt.wantErr) {
   495  				t.Fatalf("Error mismatch\nGot:\n%s\n\nWant:\n%s", gotErr, tt.wantErr)
   496  			}
   497  		})
   498  	}
   499  }
   500  
   501  func TestRejectUnknownFieldsFlat(t *testing.T) {
   502  	tests := []struct {
   503  		name    string
   504  		in      proto.Message
   505  		wantErr error
   506  	}{
   507  		{
   508  			name: "Oneof with same field number, shouldn't complain",
   509  			in: &testdata.Customer3{
   510  				Id:   68,
   511  				Name: "ACME3",
   512  				Payment: &testdata.Customer3_CreditCardNo{
   513  					CreditCardNo: "123-XXXX-XXX881",
   514  				},
   515  			},
   516  			wantErr: nil,
   517  		},
   518  		{
   519  			name: "Oneof with different field number, should fail",
   520  			in: &testdata.Customer3{
   521  				Id:   68,
   522  				Name: "ACME3",
   523  				Payment: &testdata.Customer3_ChequeNo{
   524  					ChequeNo: "123XXXXXXX881",
   525  				},
   526  			},
   527  			wantErr: &errUnknownField{
   528  				Type:   "*testdata.Customer1",
   529  				TagNum: 8, WireType: 2,
   530  			},
   531  		},
   532  		{
   533  			name: "Any in a field, the extra field will be serialized so should fail",
   534  			in: &testdata.Customer2{
   535  				Miscellaneous: &types.Any{},
   536  			},
   537  			wantErr: &errUnknownField{
   538  				Type:     "*testdata.Customer1",
   539  				TagNum:   10,
   540  				WireType: 2,
   541  			},
   542  		},
   543  		{
   544  			name: "With a nested struct as a field",
   545  			in: &testdata.Customer3{
   546  				Id: 289,
   547  				Original: &testdata.Customer1{
   548  					Id: 991,
   549  				},
   550  			},
   551  			wantErr: &errUnknownField{
   552  				Type:     "*testdata.Customer1",
   553  				TagNum:   9,
   554  				WireType: 2,
   555  			},
   556  		},
   557  		{
   558  			name: "An extra field that's non-existent in Customer1",
   559  			in: &testdata.Customer2{
   560  				Id:       289,
   561  				Name:     "Customer1",
   562  				Industry: 5299,
   563  				Fewer:    199.9,
   564  			},
   565  			wantErr: &errMismatchedWireType{
   566  				Type:   "*testdata.Customer1",
   567  				TagNum: 2, GotWireType: 0, WantWireType: 2,
   568  			},
   569  		},
   570  		{
   571  			name: "Using a field that's in the reserved range, should fail by default",
   572  			in: &testdata.Customer2{
   573  				Id:       289,
   574  				Reserved: 99,
   575  			},
   576  			wantErr: &errUnknownField{
   577  				Type:     "*testdata.Customer1",
   578  				TagNum:   1047,
   579  				WireType: 0,
   580  			},
   581  		},
   582  		{
   583  			name: "Only fields matching",
   584  			in: &testdata.Customer2{
   585  				Id:   289,
   586  				Name: "Customer1",
   587  			},
   588  			wantErr: &errMismatchedWireType{
   589  				Type:   "*testdata.Customer1",
   590  				TagNum: 3, GotWireType: 2, WantWireType: 5,
   591  			},
   592  		},
   593  		{
   594  			name: "Extra field that's non-existent in Customer1, along with Reserved set",
   595  			in: &testdata.Customer2{
   596  				Id:       289,
   597  				Name:     "Customer1",
   598  				Industry: 5299,
   599  				Fewer:    199.9,
   600  				Reserved: 819,
   601  			},
   602  			wantErr: &errMismatchedWireType{
   603  				Type:   "*testdata.Customer1",
   604  				TagNum: 2, GotWireType: 0, WantWireType: 2,
   605  			},
   606  		},
   607  		{
   608  			name: "Using enumerated field",
   609  			in: &testdata.Customer2{
   610  				Id:       289,
   611  				Name:     "Customer1",
   612  				Industry: 5299,
   613  				City:     testdata.Customer2_PaloAlto,
   614  			},
   615  			wantErr: &errMismatchedWireType{
   616  				Type:        "*testdata.Customer1",
   617  				TagNum:      2,
   618  				GotWireType: 0, WantWireType: 2,
   619  			},
   620  		},
   621  		{
   622  			name: "multiple extraneous fields",
   623  			in: &testdata.Customer2{
   624  				Id:       289,
   625  				Name:     "Customer1",
   626  				Industry: 5299,
   627  				City:     testdata.Customer2_PaloAlto,
   628  				Fewer:    45,
   629  			},
   630  			wantErr: &errMismatchedWireType{
   631  				TagNum: 2, GotWireType: 0, WantWireType: 2,
   632  				Type: "*testdata.Customer1",
   633  			},
   634  		},
   635  	}
   636  
   637  	for _, tt := range tests {
   638  		tt := tt
   639  		t.Run(tt.name, func(t *testing.T) {
   640  			blob, err := proto.Marshal(tt.in)
   641  			if err != nil {
   642  				t.Fatalf("Failed to marshal input: %v", err)
   643  			}
   644  
   645  			c1 := new(testdata.Customer1)
   646  			gotErr := RejectUnknownFieldsStrict(blob, c1, DefaultAnyResolver{})
   647  			if !reflect.DeepEqual(gotErr, tt.wantErr) {
   648  				t.Fatalf("Error mismatch\nGot:\n%s\n\nWant:\n%s", gotErr, tt.wantErr)
   649  			}
   650  		})
   651  	}
   652  }
   653  
   654  // Issue https://github.com/cosmos/cosmos-sdk/issues/7222, we need to ensure that repeated
   655  // uint64 are recognized as packed.
   656  func TestPackedEncoding(t *testing.T) {
   657  	data := testdata.TestRepeatedUints{Nums: []uint64{12, 13}}
   658  
   659  	marshalled, err := data.Marshal()
   660  	require.NoError(t, err)
   661  
   662  	unmarshalled := &testdata.TestRepeatedUints{}
   663  	_, err = RejectUnknownFields(marshalled, unmarshalled, false, DefaultAnyResolver{})
   664  	require.NoError(t, err)
   665  }
   666  
   667  func mustMarshal(msg proto.Message) []byte {
   668  	blob, err := proto.Marshal(msg)
   669  	if err != nil {
   670  		panic(err)
   671  	}
   672  	return blob
   673  }