...

Source file src/cloud.google.com/go/bigquery/storage/managedwriter/adapt/protoconversion_test.go

Documentation: cloud.google.com/go/bigquery/storage/managedwriter/adapt

     1  // Copyright 2021 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package adapt
    16  
    17  import (
    18  	"encoding/json"
    19  	"reflect"
    20  	"testing"
    21  
    22  	"cloud.google.com/go/bigquery/storage/apiv1/storagepb"
    23  	"cloud.google.com/go/bigquery/storage/managedwriter/testdata"
    24  	"github.com/google/go-cmp/cmp"
    25  	"google.golang.org/protobuf/encoding/protojson"
    26  	"google.golang.org/protobuf/proto"
    27  	"google.golang.org/protobuf/reflect/protodesc"
    28  	"google.golang.org/protobuf/reflect/protoreflect"
    29  	"google.golang.org/protobuf/testing/protocmp"
    30  	"google.golang.org/protobuf/types/descriptorpb"
    31  	"google.golang.org/protobuf/types/dynamicpb"
    32  )
    33  
    34  // TestSchemaToProtoConversion validates behavior around converting table schemas to
    35  // a descriptor.  The challenges here are that we use dynamic proto registries to
    36  // do this work, which means that we're unable to do things like proto.Equal comparisons
    37  // between MessageDescriptors directly.
    38  //
    39  // Instead, we compare to two forms of the message in DescriptorProto form:  In the first,
    40  // we ensure the structure of the outer message is as expected.  In the second, we compare
    41  // to the normalized form of the DescriptorProto as that encapsulates all the dependencies
    42  // within the NestedTypes definition.
    43  func TestSchemaToProtoConversion(t *testing.T) {
    44  	testCases := []struct {
    45  		description string
    46  		bq          *storagepb.TableSchema
    47  		// The un-normalized descriptor (sans dependencies)
    48  		wantProto2 *descriptorpb.DescriptorProto
    49  		// Normalized descriptor (all dependencies nested)
    50  		wantProto2Normalized *descriptorpb.DescriptorProto
    51  
    52  		// The un-normalized descriptor (sans dependencies)
    53  		wantProto3 *descriptorpb.DescriptorProto
    54  		// Normalized descriptor
    55  		wantProto3Normalized *descriptorpb.DescriptorProto
    56  	}{
    57  		{
    58  			description: "basic",
    59  			bq: &storagepb.TableSchema{
    60  				Fields: []*storagepb.TableFieldSchema{
    61  					{Name: "foo", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_NULLABLE},
    62  					{Name: "bar", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_REQUIRED},
    63  					{Name: "baz", Type: storagepb.TableFieldSchema_BYTES, Mode: storagepb.TableFieldSchema_REPEATED},
    64  				}},
    65  			wantProto2: &descriptorpb.DescriptorProto{
    66  				Name: proto.String("root"),
    67  				Field: []*descriptorpb.FieldDescriptorProto{
    68  					{
    69  						Name:   proto.String("foo"),
    70  						Number: proto.Int32(1),
    71  						Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
    72  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
    73  					{Name: proto.String("bar"), Number: proto.Int32(2), Type: descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum()},
    74  					{Name: proto.String("baz"), Number: proto.Int32(3), Type: descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()},
    75  				},
    76  			},
    77  			wantProto2Normalized: &descriptorpb.DescriptorProto{
    78  				Name: proto.String("root"),
    79  				Field: []*descriptorpb.FieldDescriptorProto{
    80  					{
    81  						Name:   proto.String("foo"),
    82  						Number: proto.Int32(1),
    83  						Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
    84  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
    85  					{Name: proto.String("bar"), Number: proto.Int32(2), Type: descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum()},
    86  					{Name: proto.String("baz"), Number: proto.Int32(3), Type: descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()},
    87  				},
    88  			},
    89  			wantProto3: &descriptorpb.DescriptorProto{
    90  				Name: proto.String("root"),
    91  				Field: []*descriptorpb.FieldDescriptorProto{
    92  					{
    93  						Name:     proto.String("foo"),
    94  						Number:   proto.Int32(1),
    95  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
    96  						TypeName: proto.String(".google.protobuf.StringValue"),
    97  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
    98  					{Name: proto.String("bar"), Number: proto.Int32(2), Type: descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
    99  					{Name: proto.String("baz"), Number: proto.Int32(3), Type: descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()},
   100  				},
   101  			},
   102  		},
   103  		{
   104  			// exercise construct of a submessage
   105  			description: "nested",
   106  			bq: &storagepb.TableSchema{
   107  				Fields: []*storagepb.TableFieldSchema{
   108  					{Name: "curdate", Type: storagepb.TableFieldSchema_DATE, Mode: storagepb.TableFieldSchema_NULLABLE},
   109  					{
   110  						Name: "rec",
   111  						Type: storagepb.TableFieldSchema_STRUCT,
   112  						Mode: storagepb.TableFieldSchema_NULLABLE,
   113  						Fields: []*storagepb.TableFieldSchema{
   114  							{Name: "userid", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_REQUIRED},
   115  							{Name: "location", Type: storagepb.TableFieldSchema_GEOGRAPHY, Mode: storagepb.TableFieldSchema_NULLABLE},
   116  						},
   117  					},
   118  				},
   119  			},
   120  			wantProto2: &descriptorpb.DescriptorProto{
   121  				Name: proto.String("root"),
   122  				Field: []*descriptorpb.FieldDescriptorProto{
   123  					{
   124  						Name:   proto.String("curdate"),
   125  						Number: proto.Int32(1),
   126  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
   127  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   128  					},
   129  					{
   130  						Name:     proto.String("rec"),
   131  						Number:   proto.Int32(2),
   132  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   133  						TypeName: proto.String(".root__rec"),
   134  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   135  					},
   136  				},
   137  			},
   138  			wantProto2Normalized: &descriptorpb.DescriptorProto{
   139  				Name: proto.String("root"),
   140  				Field: []*descriptorpb.FieldDescriptorProto{
   141  					{
   142  						Name:   proto.String("curdate"),
   143  						Number: proto.Int32(1),
   144  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
   145  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   146  					},
   147  					{
   148  						Name:     proto.String("rec"),
   149  						Number:   proto.Int32(2),
   150  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   151  						TypeName: proto.String("root__rec"),
   152  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   153  					},
   154  				},
   155  				NestedType: []*descriptorpb.DescriptorProto{
   156  					{
   157  						Name: proto.String("root__rec"),
   158  						Field: []*descriptorpb.FieldDescriptorProto{
   159  							{
   160  								Name:   proto.String("userid"),
   161  								Number: proto.Int32(1),
   162  								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   163  								Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   164  							},
   165  							{
   166  								Name:   proto.String("location"),
   167  								Number: proto.Int32(2),
   168  								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   169  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   170  							},
   171  						},
   172  					},
   173  				},
   174  			},
   175  			wantProto3: &descriptorpb.DescriptorProto{
   176  				Name: proto.String("root"),
   177  				Field: []*descriptorpb.FieldDescriptorProto{
   178  					{
   179  						Name:     proto.String("curdate"),
   180  						Number:   proto.Int32(1),
   181  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   182  						TypeName: proto.String(".google.protobuf.Int32Value"),
   183  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   184  					},
   185  					{
   186  						Name:     proto.String("rec"),
   187  						Number:   proto.Int32(2),
   188  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   189  						TypeName: proto.String(".root__rec"),
   190  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   191  					},
   192  				},
   193  			},
   194  		},
   195  		{
   196  			// exercise construct of a submessage
   197  			description: "range types",
   198  			bq: &storagepb.TableSchema{
   199  				Fields: []*storagepb.TableFieldSchema{
   200  					{
   201  						Name:             "rangedate",
   202  						Type:             storagepb.TableFieldSchema_RANGE,
   203  						Mode:             storagepb.TableFieldSchema_NULLABLE,
   204  						RangeElementType: &storagepb.TableFieldSchema_FieldElementType{Type: storagepb.TableFieldSchema_DATE},
   205  					},
   206  					{
   207  						Name:             "rangedatetime",
   208  						Type:             storagepb.TableFieldSchema_RANGE,
   209  						Mode:             storagepb.TableFieldSchema_NULLABLE,
   210  						RangeElementType: &storagepb.TableFieldSchema_FieldElementType{Type: storagepb.TableFieldSchema_DATETIME},
   211  					},
   212  					{
   213  						Name:             "rangetimestamp",
   214  						Type:             storagepb.TableFieldSchema_RANGE,
   215  						Mode:             storagepb.TableFieldSchema_NULLABLE,
   216  						RangeElementType: &storagepb.TableFieldSchema_FieldElementType{Type: storagepb.TableFieldSchema_TIMESTAMP},
   217  					},
   218  					{
   219  						Name:             "duplicate_rangedate",
   220  						Type:             storagepb.TableFieldSchema_RANGE,
   221  						Mode:             storagepb.TableFieldSchema_NULLABLE,
   222  						RangeElementType: &storagepb.TableFieldSchema_FieldElementType{Type: storagepb.TableFieldSchema_DATE},
   223  					},
   224  				},
   225  			},
   226  			wantProto2: &descriptorpb.DescriptorProto{
   227  				Name: proto.String("root"),
   228  				Field: []*descriptorpb.FieldDescriptorProto{
   229  					{
   230  						Name:     proto.String("rangedate"),
   231  						Number:   proto.Int32(1),
   232  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   233  						TypeName: proto.String(".rangemessage_range_date"),
   234  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   235  					},
   236  					{
   237  						Name:     proto.String("rangedatetime"),
   238  						Number:   proto.Int32(2),
   239  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   240  						TypeName: proto.String(".rangemessage_range_datetime"),
   241  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   242  					},
   243  					{
   244  						Name:     proto.String("rangetimestamp"),
   245  						Number:   proto.Int32(3),
   246  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   247  						TypeName: proto.String(".rangemessage_range_timestamp"),
   248  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   249  					},
   250  					{
   251  						Name:     proto.String("duplicate_rangedate"),
   252  						Number:   proto.Int32(4),
   253  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   254  						TypeName: proto.String(".rangemessage_range_date"),
   255  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   256  					},
   257  				},
   258  			},
   259  			wantProto2Normalized: &descriptorpb.DescriptorProto{
   260  				Name: proto.String("root"),
   261  				Field: []*descriptorpb.FieldDescriptorProto{
   262  					{
   263  						Name:     proto.String("rangedate"),
   264  						Number:   proto.Int32(1),
   265  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   266  						TypeName: proto.String("rangemessage_range_date"),
   267  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   268  					},
   269  					{
   270  						Name:     proto.String("rangedatetime"),
   271  						Number:   proto.Int32(2),
   272  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   273  						TypeName: proto.String("rangemessage_range_datetime"),
   274  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   275  					},
   276  					{
   277  						Name:     proto.String("rangetimestamp"),
   278  						Number:   proto.Int32(3),
   279  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   280  						TypeName: proto.String("rangemessage_range_timestamp"),
   281  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   282  					},
   283  					{
   284  						Name:     proto.String("duplicate_rangedate"),
   285  						Number:   proto.Int32(4),
   286  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   287  						TypeName: proto.String("rangemessage_range_date"),
   288  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   289  					},
   290  				},
   291  				NestedType: []*descriptorpb.DescriptorProto{
   292  					{
   293  						Name: proto.String("rangemessage_range_date"),
   294  						Field: []*descriptorpb.FieldDescriptorProto{
   295  							{
   296  								Name:   proto.String("start"),
   297  								Number: proto.Int32(1),
   298  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
   299  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   300  							},
   301  							{
   302  								Name:   proto.String("end"),
   303  								Number: proto.Int32(2),
   304  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
   305  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   306  							},
   307  						},
   308  					},
   309  					{
   310  						Name: proto.String("rangemessage_range_datetime"),
   311  						Field: []*descriptorpb.FieldDescriptorProto{
   312  							{
   313  								Name:   proto.String("start"),
   314  								Number: proto.Int32(1),
   315  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   316  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   317  							},
   318  							{
   319  								Name:   proto.String("end"),
   320  								Number: proto.Int32(2),
   321  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   322  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   323  							},
   324  						},
   325  					},
   326  					{
   327  						Name: proto.String("rangemessage_range_timestamp"),
   328  						Field: []*descriptorpb.FieldDescriptorProto{
   329  							{
   330  								Name:   proto.String("start"),
   331  								Number: proto.Int32(1),
   332  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   333  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   334  							},
   335  							{
   336  								Name:   proto.String("end"),
   337  								Number: proto.Int32(2),
   338  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   339  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   340  							},
   341  						},
   342  					},
   343  				},
   344  			},
   345  			wantProto3: &descriptorpb.DescriptorProto{
   346  				Name: proto.String("root"),
   347  				Field: []*descriptorpb.FieldDescriptorProto{
   348  					{
   349  						Name:     proto.String("rangedate"),
   350  						Number:   proto.Int32(1),
   351  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   352  						TypeName: proto.String(".rangemessage_range_date"),
   353  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   354  					},
   355  					{
   356  						Name:     proto.String("rangedatetime"),
   357  						Number:   proto.Int32(2),
   358  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   359  						TypeName: proto.String(".rangemessage_range_datetime"),
   360  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   361  					},
   362  					{
   363  						Name:     proto.String("rangetimestamp"),
   364  						Number:   proto.Int32(3),
   365  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   366  						TypeName: proto.String(".rangemessage_range_timestamp"),
   367  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   368  					},
   369  					{
   370  						Name:     proto.String("duplicate_rangedate"),
   371  						Number:   proto.Int32(4),
   372  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   373  						TypeName: proto.String(".rangemessage_range_date"),
   374  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   375  					},
   376  				},
   377  			},
   378  		},
   379  		{
   380  			description: "nested-uppercase",
   381  			bq: &storagepb.TableSchema{
   382  				Fields: []*storagepb.TableFieldSchema{
   383  					{Name: "recordID", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_REQUIRED},
   384  					{
   385  						Name: "recordDetails",
   386  						Type: storagepb.TableFieldSchema_STRUCT,
   387  						Mode: storagepb.TableFieldSchema_REPEATED,
   388  						Fields: []*storagepb.TableFieldSchema{
   389  							{Name: "key", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_REQUIRED},
   390  							{Name: "value", Type: storagepb.TableFieldSchema_BYTES, Mode: storagepb.TableFieldSchema_NULLABLE},
   391  						},
   392  					},
   393  				},
   394  			},
   395  			wantProto2: &descriptorpb.DescriptorProto{
   396  				Name: proto.String("root"),
   397  				Field: []*descriptorpb.FieldDescriptorProto{
   398  					{
   399  						Name:   proto.String("recordID"),
   400  						Number: proto.Int32(1),
   401  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   402  						Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   403  					},
   404  					{
   405  						Name:     proto.String("recordDetails"),
   406  						Number:   proto.Int32(2),
   407  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   408  						TypeName: proto.String(".root__recordDetails"),
   409  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
   410  					},
   411  				},
   412  			},
   413  			wantProto2Normalized: &descriptorpb.DescriptorProto{
   414  				Name: proto.String("root"),
   415  				Field: []*descriptorpb.FieldDescriptorProto{
   416  					{
   417  						Name:   proto.String("recordID"),
   418  						Number: proto.Int32(1),
   419  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   420  						Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   421  					},
   422  					{
   423  						Name:     proto.String("recordDetails"),
   424  						Number:   proto.Int32(2),
   425  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   426  						TypeName: proto.String("root__recordDetails"),
   427  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
   428  					},
   429  				},
   430  				NestedType: []*descriptorpb.DescriptorProto{
   431  					{
   432  						Name: proto.String("root__recordDetails"),
   433  						Field: []*descriptorpb.FieldDescriptorProto{
   434  							{
   435  								Name:   proto.String("key"),
   436  								Number: proto.Int32(1),
   437  								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   438  								Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   439  							},
   440  							{
   441  								Name:   proto.String("value"),
   442  								Number: proto.Int32(2),
   443  								Type:   descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(),
   444  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   445  							},
   446  						},
   447  					},
   448  				},
   449  			},
   450  			wantProto3: &descriptorpb.DescriptorProto{
   451  				Name: proto.String("root"),
   452  				Field: []*descriptorpb.FieldDescriptorProto{
   453  					{
   454  						Name:   proto.String("recordID"),
   455  						Number: proto.Int32(1),
   456  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   457  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   458  					},
   459  					{
   460  						Name:     proto.String("recordDetails"),
   461  						Number:   proto.Int32(2),
   462  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   463  						TypeName: proto.String(".root__recordDetails"),
   464  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
   465  					},
   466  				},
   467  			},
   468  		},
   469  		{
   470  			// We expect to re-use the submessage twice, as the schema contains two identical structs.
   471  			description: "nested with duplicate submessage",
   472  			bq: &storagepb.TableSchema{
   473  				Fields: []*storagepb.TableFieldSchema{
   474  					{Name: "curdate", Type: storagepb.TableFieldSchema_DATE, Mode: storagepb.TableFieldSchema_NULLABLE},
   475  					{
   476  						Name: "rec1",
   477  						Type: storagepb.TableFieldSchema_STRUCT,
   478  						Mode: storagepb.TableFieldSchema_NULLABLE,
   479  						Fields: []*storagepb.TableFieldSchema{
   480  							{Name: "userid", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_REQUIRED},
   481  							{Name: "location", Type: storagepb.TableFieldSchema_GEOGRAPHY, Mode: storagepb.TableFieldSchema_NULLABLE},
   482  						},
   483  					},
   484  					{
   485  						Name: "rec2",
   486  						Type: storagepb.TableFieldSchema_STRUCT,
   487  						Mode: storagepb.TableFieldSchema_NULLABLE,
   488  						Fields: []*storagepb.TableFieldSchema{
   489  							{Name: "userid", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_REQUIRED},
   490  							{Name: "location", Type: storagepb.TableFieldSchema_GEOGRAPHY, Mode: storagepb.TableFieldSchema_NULLABLE},
   491  						},
   492  					},
   493  				},
   494  			},
   495  			wantProto2: &descriptorpb.DescriptorProto{
   496  				Name: proto.String("root"),
   497  				Field: []*descriptorpb.FieldDescriptorProto{
   498  					{
   499  						Name:   proto.String("curdate"),
   500  						Number: proto.Int32(1),
   501  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
   502  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   503  					},
   504  					{
   505  						Name:     proto.String("rec1"),
   506  						Number:   proto.Int32(2),
   507  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   508  						TypeName: proto.String(".root__rec1"),
   509  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   510  					},
   511  					{
   512  						Name:     proto.String("rec2"),
   513  						Number:   proto.Int32(3),
   514  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   515  						TypeName: proto.String(".root__rec1"),
   516  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   517  					},
   518  				},
   519  			},
   520  			wantProto3: &descriptorpb.DescriptorProto{
   521  				Name: proto.String("root"),
   522  				Field: []*descriptorpb.FieldDescriptorProto{
   523  					{
   524  						Name:     proto.String("curdate"),
   525  						Number:   proto.Int32(1),
   526  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   527  						TypeName: proto.String(".google.protobuf.Int32Value"),
   528  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   529  					},
   530  					{
   531  						Name:     proto.String("rec1"),
   532  						Number:   proto.Int32(2),
   533  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   534  						TypeName: proto.String(".root__rec1"),
   535  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   536  					},
   537  					{
   538  						Name:     proto.String("rec2"),
   539  						Number:   proto.Int32(3),
   540  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   541  						TypeName: proto.String(".root__rec1"),
   542  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   543  					},
   544  				},
   545  			},
   546  		},
   547  		{
   548  			description: "nested with reused submessage in different levels",
   549  			bq: &storagepb.TableSchema{
   550  				Fields: []*storagepb.TableFieldSchema{
   551  					{
   552  						Name: "reused_inner_struct",
   553  						Type: storagepb.TableFieldSchema_STRUCT,
   554  						Mode: storagepb.TableFieldSchema_REQUIRED,
   555  						Fields: []*storagepb.TableFieldSchema{
   556  							{
   557  								Name: "leaf",
   558  								Type: storagepb.TableFieldSchema_STRING,
   559  								Mode: storagepb.TableFieldSchema_REQUIRED,
   560  							},
   561  						},
   562  					},
   563  					{
   564  						Name: "outer_struct",
   565  						Type: storagepb.TableFieldSchema_STRUCT,
   566  						Mode: storagepb.TableFieldSchema_REQUIRED,
   567  						Fields: []*storagepb.TableFieldSchema{
   568  							{
   569  								Name: "another_inner_struct",
   570  								Type: storagepb.TableFieldSchema_STRUCT,
   571  								Mode: storagepb.TableFieldSchema_REQUIRED,
   572  								Fields: []*storagepb.TableFieldSchema{
   573  									{
   574  										Name: "another_leaf",
   575  										Type: storagepb.TableFieldSchema_STRING,
   576  										Mode: storagepb.TableFieldSchema_REQUIRED,
   577  									},
   578  								},
   579  							},
   580  							{
   581  								Name: "reused_inner_struct_one",
   582  								Type: storagepb.TableFieldSchema_STRUCT,
   583  								Mode: storagepb.TableFieldSchema_REQUIRED,
   584  								Fields: []*storagepb.TableFieldSchema{
   585  									{
   586  										Name: "leaf",
   587  										Type: storagepb.TableFieldSchema_STRING,
   588  										Mode: storagepb.TableFieldSchema_REQUIRED,
   589  									},
   590  								},
   591  							},
   592  							{
   593  								Name: "reused_inner_struct_two",
   594  								Type: storagepb.TableFieldSchema_STRUCT,
   595  								Mode: storagepb.TableFieldSchema_REQUIRED,
   596  								Fields: []*storagepb.TableFieldSchema{
   597  									{
   598  										Name: "leaf",
   599  										Type: storagepb.TableFieldSchema_STRING,
   600  										Mode: storagepb.TableFieldSchema_REQUIRED,
   601  									},
   602  								},
   603  							},
   604  						},
   605  					},
   606  				},
   607  			},
   608  			wantProto2: &descriptorpb.DescriptorProto{
   609  				Name: proto.String("root"),
   610  				Field: []*descriptorpb.FieldDescriptorProto{
   611  					{
   612  						Name:     proto.String("reused_inner_struct"),
   613  						Number:   proto.Int32(1),
   614  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   615  						TypeName: proto.String(".root__reused_inner_struct"),
   616  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   617  					},
   618  					{
   619  						Name:     proto.String("outer_struct"),
   620  						Number:   proto.Int32(2),
   621  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   622  						TypeName: proto.String(".root__outer_struct"),
   623  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   624  					},
   625  				},
   626  			},
   627  			wantProto2Normalized: &descriptorpb.DescriptorProto{
   628  				Name: proto.String("root"),
   629  				Field: []*descriptorpb.FieldDescriptorProto{
   630  					{
   631  						Name:     proto.String("reused_inner_struct"),
   632  						Number:   proto.Int32(1),
   633  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   634  						TypeName: proto.String("root__reused_inner_struct"),
   635  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   636  					},
   637  					{
   638  						Name:     proto.String("outer_struct"),
   639  						Number:   proto.Int32(2),
   640  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   641  						TypeName: proto.String("root__outer_struct"),
   642  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   643  					},
   644  				},
   645  				NestedType: []*descriptorpb.DescriptorProto{
   646  					{
   647  						Name: proto.String("root__outer_struct"),
   648  						Field: []*descriptorpb.FieldDescriptorProto{
   649  							{
   650  								Name:     proto.String("another_inner_struct"),
   651  								Number:   proto.Int32(1),
   652  								Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   653  								TypeName: proto.String("root__outer_struct__another_inner_struct"),
   654  								Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   655  							},
   656  							{
   657  								Name:     proto.String("reused_inner_struct_one"),
   658  								Number:   proto.Int32(2),
   659  								Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   660  								TypeName: proto.String("root__reused_inner_struct"),
   661  								Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   662  							},
   663  							{
   664  								Name:     proto.String("reused_inner_struct_two"),
   665  								Number:   proto.Int32(3),
   666  								Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   667  								TypeName: proto.String("root__reused_inner_struct"),
   668  								Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   669  							},
   670  						},
   671  					},
   672  					{
   673  						Name: proto.String("root__outer_struct__another_inner_struct"),
   674  						Field: []*descriptorpb.FieldDescriptorProto{
   675  							{
   676  								Name:   proto.String("another_leaf"),
   677  								Number: proto.Int32(1),
   678  								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   679  								Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   680  							},
   681  						},
   682  					},
   683  					{
   684  						Name: proto.String("root__reused_inner_struct"),
   685  						Field: []*descriptorpb.FieldDescriptorProto{
   686  							{
   687  								Name:   proto.String("leaf"),
   688  								Number: proto.Int32(1),
   689  								Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   690  								Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
   691  							},
   692  						},
   693  					},
   694  				},
   695  			},
   696  			wantProto3: &descriptorpb.DescriptorProto{
   697  				Name: proto.String("root"),
   698  				Field: []*descriptorpb.FieldDescriptorProto{
   699  					{
   700  						Name:     proto.String("reused_inner_struct"),
   701  						Number:   proto.Int32(1),
   702  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   703  						TypeName: proto.String(".root__reused_inner_struct"),
   704  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   705  					},
   706  					{
   707  						Name:     proto.String("outer_struct"),
   708  						Number:   proto.Int32(2),
   709  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   710  						TypeName: proto.String(".root__outer_struct"),
   711  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   712  					},
   713  				},
   714  			},
   715  		},
   716  		{
   717  			description: "multiple nesting levels",
   718  			bq: &storagepb.TableSchema{
   719  				Fields: []*storagepb.TableFieldSchema{
   720  					{
   721  						Name: "outer_struct",
   722  						Type: storagepb.TableFieldSchema_STRUCT,
   723  						Mode: storagepb.TableFieldSchema_NULLABLE,
   724  						Fields: []*storagepb.TableFieldSchema{
   725  							{
   726  								Name: "inner_struct",
   727  								Type: storagepb.TableFieldSchema_STRUCT,
   728  								Mode: storagepb.TableFieldSchema_NULLABLE,
   729  								Fields: []*storagepb.TableFieldSchema{
   730  									{Name: "leaf_one", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_NULLABLE},
   731  									{Name: "leaf_two", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_NULLABLE},
   732  								},
   733  							},
   734  						},
   735  					},
   736  					{
   737  						Name: "other_field",
   738  						Type: storagepb.TableFieldSchema_INT64,
   739  						Mode: storagepb.TableFieldSchema_NULLABLE,
   740  					},
   741  				},
   742  			},
   743  			wantProto2: &descriptorpb.DescriptorProto{
   744  				Name: proto.String("root"),
   745  				Field: []*descriptorpb.FieldDescriptorProto{
   746  					{
   747  						Name:     proto.String("outer_struct"),
   748  						Number:   proto.Int32(1),
   749  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   750  						TypeName: proto.String(".root__outer_struct"),
   751  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   752  					},
   753  					{
   754  						Name:   proto.String("other_field"),
   755  						Number: proto.Int32(2),
   756  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   757  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   758  					},
   759  				},
   760  			},
   761  			wantProto2Normalized: &descriptorpb.DescriptorProto{
   762  				Name: proto.String("root"),
   763  				Field: []*descriptorpb.FieldDescriptorProto{
   764  					{
   765  						Name:     proto.String("outer_struct"),
   766  						Number:   proto.Int32(1),
   767  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   768  						TypeName: proto.String("root__outer_struct"),
   769  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   770  					},
   771  					{
   772  						Name:   proto.String("other_field"),
   773  						Number: proto.Int32(2),
   774  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   775  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   776  					},
   777  				},
   778  				NestedType: []*descriptorpb.DescriptorProto{
   779  					{
   780  						Name: proto.String("root__outer_struct"),
   781  						Field: []*descriptorpb.FieldDescriptorProto{
   782  							{
   783  								Name:     proto.String("inner_struct"),
   784  								Number:   proto.Int32(1),
   785  								Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   786  								TypeName: proto.String("root__outer_struct__inner_struct"),
   787  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   788  							},
   789  						},
   790  					},
   791  					{
   792  						Name: proto.String("root__outer_struct__inner_struct"),
   793  						Field: []*descriptorpb.FieldDescriptorProto{
   794  							{
   795  								Name:   proto.String("leaf_one"),
   796  								Number: proto.Int32(1),
   797  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   798  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   799  							},
   800  							{
   801  								Name:   proto.String("leaf_two"),
   802  								Number: proto.Int32(2),
   803  								Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   804  								Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   805  							},
   806  						},
   807  					},
   808  				},
   809  			},
   810  			wantProto3: &descriptorpb.DescriptorProto{
   811  				Name: proto.String("root"),
   812  				Field: []*descriptorpb.FieldDescriptorProto{
   813  					{
   814  						Name:     proto.String("outer_struct"),
   815  						Number:   proto.Int32(1),
   816  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   817  						TypeName: proto.String(".root__outer_struct"),
   818  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   819  					},
   820  					{
   821  						Name:     proto.String("other_field"),
   822  						Number:   proto.Int32(2),
   823  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
   824  						TypeName: proto.String(".google.protobuf.Int64Value"),
   825  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
   826  					},
   827  				},
   828  			},
   829  		},
   830  		{
   831  			description: "repeated with packed",
   832  			bq: &storagepb.TableSchema{
   833  				Fields: []*storagepb.TableFieldSchema{
   834  					{Name: "name", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_NULLABLE},
   835  					{Name: "some_lengths", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_REPEATED},
   836  					{Name: "nicknames", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_REPEATED},
   837  				}},
   838  			wantProto2: &descriptorpb.DescriptorProto{
   839  				Name: proto.String("root"),
   840  				Field: []*descriptorpb.FieldDescriptorProto{
   841  					{
   842  						Name:   proto.String("name"),
   843  						Number: proto.Int32(1),
   844  						Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   845  						Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
   846  					{
   847  						Name:   proto.String("some_lengths"),
   848  						Number: proto.Int32(2),
   849  						Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   850  						Label:  descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
   851  						Options: &descriptorpb.FieldOptions{
   852  							Packed: proto.Bool(true),
   853  						},
   854  					},
   855  					{Name: proto.String("nicknames"), Number: proto.Int32(3), Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()},
   856  				},
   857  			},
   858  		},
   859  		{
   860  			description: "indirect names",
   861  			bq: &storagepb.TableSchema{
   862  				Fields: []*storagepb.TableFieldSchema{
   863  					{Name: "foo", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_NULLABLE},
   864  					{Name: "火", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_REQUIRED},
   865  					{Name: "水_addict", Type: storagepb.TableFieldSchema_BYTES, Mode: storagepb.TableFieldSchema_REPEATED},
   866  					{Name: "0col", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_NULLABLE},
   867  					{Name: "funny-name", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_NULLABLE},
   868  				}},
   869  			wantProto2: func() *descriptorpb.DescriptorProto {
   870  				dp := &descriptorpb.DescriptorProto{
   871  					Name: proto.String("root"),
   872  					Field: []*descriptorpb.FieldDescriptorProto{
   873  						{
   874  							Name:   proto.String("foo"),
   875  							Number: proto.Int32(1),
   876  							Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
   877  							Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
   878  						{
   879  							Name:    proto.String("col_54Gr"),
   880  							Number:  proto.Int32(2),
   881  							Type:    descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   882  							Options: &descriptorpb.FieldOptions{},
   883  							Label:   descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum()},
   884  						{
   885  							Name:    proto.String("col_5rC0X2FkZGljdA"),
   886  							Number:  proto.Int32(3),
   887  							Type:    descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(),
   888  							Options: &descriptorpb.FieldOptions{},
   889  							Label:   descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
   890  						},
   891  						{
   892  							Name:    proto.String("col_MGNvbA"),
   893  							Number:  proto.Int32(4),
   894  							Type:    descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   895  							Options: &descriptorpb.FieldOptions{},
   896  							Label:   descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
   897  						{
   898  							Name:    proto.String("col_ZnVubnktbmFtZQ"),
   899  							Number:  proto.Int32(5),
   900  							Type:    descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
   901  							Options: &descriptorpb.FieldOptions{},
   902  							Label:   descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()},
   903  					},
   904  				}
   905  				proto.SetExtension(dp.Field[1].Options, storagepb.E_ColumnName, "火")
   906  				proto.SetExtension(dp.Field[2].Options, storagepb.E_ColumnName, "水_addict")
   907  				proto.SetExtension(dp.Field[3].Options, storagepb.E_ColumnName, "0col")
   908  				proto.SetExtension(dp.Field[4].Options, storagepb.E_ColumnName, "funny-name")
   909  				return dp
   910  			}(),
   911  		},
   912  	}
   913  	for _, tc := range testCases {
   914  		t.Run(tc.description, func(T *testing.T) {
   915  			// Proto2
   916  			p2d, err := StorageSchemaToProto2Descriptor(tc.bq, "root")
   917  			if err != nil {
   918  				t.Fatalf("failed proto2 conversion: %v", err)
   919  			}
   920  
   921  			// Convert to MessageDescriptor.
   922  			mDesc, ok := p2d.(protoreflect.MessageDescriptor)
   923  			if !ok {
   924  				t.Error("couldn't convert proto2 to messagedescriptor")
   925  			}
   926  			// Check the non-normalized case.
   927  			if tc.wantProto2 != nil {
   928  				gotDP := protodesc.ToDescriptorProto(mDesc)
   929  				if diff := cmp.Diff(gotDP, tc.wantProto2, protocmp.Transform()); diff != "" {
   930  					t.Errorf("proto2: -got, +want:\n%s", diff)
   931  				}
   932  			}
   933  			// Check the normalized case.
   934  			if tc.wantProto2Normalized != nil {
   935  				gotDP, err := NormalizeDescriptor(mDesc)
   936  				if err != nil {
   937  					t.Errorf("failed to normalize: %v", err)
   938  				}
   939  				if diff := cmp.Diff(gotDP, tc.wantProto2Normalized, protocmp.Transform()); diff != "" {
   940  					t.Errorf("proto2normalized: -got, +want:\n%s", diff)
   941  				}
   942  			}
   943  
   944  			p3d, err := StorageSchemaToProto3Descriptor(tc.bq, "root")
   945  			if err != nil {
   946  				t.Fatalf("failed proto3 conversion: %v", err)
   947  			}
   948  			// Convert to MessageDescriptor.
   949  			mDesc, ok = p3d.(protoreflect.MessageDescriptor)
   950  			if !ok {
   951  				t.Error("couldn't convert proto3 to messagedescriptor")
   952  			}
   953  			// Check the non-normalized case.
   954  			if tc.wantProto3 != nil {
   955  				gotDP := protodesc.ToDescriptorProto(mDesc)
   956  				if diff := cmp.Diff(gotDP, tc.wantProto3, protocmp.Transform()); diff != "" {
   957  					t.Errorf("proto3: -got, +want:\n%s", diff)
   958  				}
   959  			}
   960  			// Check the normalized case.
   961  			if tc.wantProto3Normalized != nil {
   962  				gotDP, err := NormalizeDescriptor(mDesc)
   963  				if err != nil {
   964  					t.Errorf("failed to normalize: %v", err)
   965  				}
   966  				if diff := cmp.Diff(gotDP, tc.wantProto3Normalized, protocmp.Transform()); diff != "" {
   967  					t.Errorf("proto3normalized: -got, +want:\n%s", diff)
   968  				}
   969  			}
   970  		})
   971  	}
   972  }
   973  
   974  func TestProtoJSONSerialization(t *testing.T) {
   975  
   976  	sourceSchema := &storagepb.TableSchema{
   977  		Fields: []*storagepb.TableFieldSchema{
   978  			{Name: "record_id", Type: storagepb.TableFieldSchema_INT64, Mode: storagepb.TableFieldSchema_NULLABLE},
   979  			{
   980  				Name: "details",
   981  				Type: storagepb.TableFieldSchema_STRUCT,
   982  				Mode: storagepb.TableFieldSchema_REPEATED,
   983  				Fields: []*storagepb.TableFieldSchema{
   984  					{Name: "key", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_REQUIRED},
   985  					{Name: "value", Type: storagepb.TableFieldSchema_STRING, Mode: storagepb.TableFieldSchema_NULLABLE},
   986  				},
   987  			},
   988  		},
   989  	}
   990  
   991  	descriptor, err := StorageSchemaToProto2Descriptor(sourceSchema, "root")
   992  	if err != nil {
   993  		t.Fatalf("failed to construct descriptor")
   994  	}
   995  
   996  	sampleRecord := []byte(`{"record_id":"12345","details":[{"key":"name","value":"jimmy"},{"key":"title","value":"clown"}]}`)
   997  
   998  	messageDescriptor, ok := descriptor.(protoreflect.MessageDescriptor)
   999  	if !ok {
  1000  		t.Fatalf("StorageSchemaToDescriptor didn't yield a valid message descriptor, got %T", descriptor)
  1001  	}
  1002  
  1003  	// First, ensure we got the expected descriptors.  Check both outer and inner messages.
  1004  	gotOuterDP := protodesc.ToDescriptorProto(messageDescriptor)
  1005  
  1006  	innerField := messageDescriptor.Fields().ByName("details")
  1007  	if innerField == nil {
  1008  		t.Fatalf("couldn't get inner descriptor for details")
  1009  	}
  1010  	gotInnerDP := protodesc.ToDescriptorProto(innerField.Message())
  1011  
  1012  	wantOuterDP := &descriptorpb.DescriptorProto{
  1013  		Name: proto.String("root"),
  1014  		Field: []*descriptorpb.FieldDescriptorProto{
  1015  			{
  1016  				Name:   proto.String("record_id"),
  1017  				Number: proto.Int32(1),
  1018  				Type:   descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1019  				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1020  			},
  1021  			{
  1022  				Name:     proto.String("details"),
  1023  				Number:   proto.Int32(2),
  1024  				Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1025  				TypeName: proto.String(".root__details"),
  1026  				Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1027  			},
  1028  		},
  1029  	}
  1030  
  1031  	wantInnerDP := &descriptorpb.DescriptorProto{
  1032  		Name: proto.String("root__details"),
  1033  		Field: []*descriptorpb.FieldDescriptorProto{
  1034  			{
  1035  				Name:   proto.String("key"),
  1036  				Number: proto.Int32(1),
  1037  				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1038  				Label:  descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
  1039  			},
  1040  			{
  1041  				Name:   proto.String("value"),
  1042  				Number: proto.Int32(2),
  1043  				Type:   descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1044  				Label:  descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1045  			},
  1046  		},
  1047  	}
  1048  
  1049  	if outerDiff := cmp.Diff(gotOuterDP, wantOuterDP, protocmp.Transform()); outerDiff != "" {
  1050  		t.Fatalf("DescriptorProto for outer message differs.\n-got, +want:\n%s", outerDiff)
  1051  	}
  1052  	if innerDiff := cmp.Diff(gotInnerDP, wantInnerDP, protocmp.Transform()); innerDiff != "" {
  1053  		t.Fatalf("DescriptorProto for inner message differs.\n-got, +want:\n%s", innerDiff)
  1054  	}
  1055  
  1056  	message := dynamicpb.NewMessage(messageDescriptor)
  1057  
  1058  	// Attempt to serialize json record into proto message.
  1059  	err = protojson.Unmarshal(sampleRecord, message)
  1060  	if err != nil {
  1061  		t.Fatalf("failed to Unmarshal json message: %v", err)
  1062  	}
  1063  
  1064  	// Serialize message back to json bytes.  We must use options for idempotency, otherwise
  1065  	// we'll serialize using the Go name rather than the proto name (recordId vs record_id).
  1066  	options := protojson.MarshalOptions{
  1067  		UseProtoNames: true,
  1068  	}
  1069  	gotBytes, err := options.Marshal(message)
  1070  	if err != nil {
  1071  		t.Fatalf("failed to marshal message: %v", err)
  1072  	}
  1073  
  1074  	var got, want interface{}
  1075  	if err := json.Unmarshal(gotBytes, &got); err != nil {
  1076  		t.Fatalf("couldn't marshal gotBytes: %v", err)
  1077  	}
  1078  	if err := json.Unmarshal(sampleRecord, &want); err != nil {
  1079  		t.Fatalf("couldn't marshal sampleRecord: %v", err)
  1080  	}
  1081  	if !reflect.DeepEqual(got, want) {
  1082  		t.Fatalf("mismatched json: got\n%q\nwant\n%q", gotBytes, sampleRecord)
  1083  	}
  1084  
  1085  }
  1086  
  1087  func TestNormalizeDescriptor(t *testing.T) {
  1088  	testCases := []struct {
  1089  		description string
  1090  		in          protoreflect.MessageDescriptor
  1091  		wantErr     bool
  1092  		want        *descriptorpb.DescriptorProto
  1093  	}{
  1094  		{
  1095  			description: "nil",
  1096  			in:          nil,
  1097  			wantErr:     true,
  1098  		},
  1099  		{
  1100  			description: "AllSupportedTypes",
  1101  			in:          (&testdata.AllSupportedTypes{}).ProtoReflect().Descriptor(),
  1102  			want: &descriptorpb.DescriptorProto{
  1103  				Name: proto.String("testdata_AllSupportedTypes"),
  1104  				Field: []*descriptorpb.FieldDescriptorProto{
  1105  					{
  1106  						Name:     proto.String("int32_value"),
  1107  						JsonName: proto.String("int32Value"),
  1108  						Number:   proto.Int32(1),
  1109  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
  1110  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1111  					},
  1112  					{
  1113  						Name:     proto.String("int64_value"),
  1114  						JsonName: proto.String("int64Value"),
  1115  						Number:   proto.Int32(2),
  1116  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1117  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1118  					},
  1119  					{
  1120  						Name:     proto.String("uint32_value"),
  1121  						JsonName: proto.String("uint32Value"),
  1122  						Number:   proto.Int32(3),
  1123  						Type:     descriptorpb.FieldDescriptorProto_TYPE_UINT32.Enum(),
  1124  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1125  					},
  1126  					{
  1127  						Name:     proto.String("uint64_value"),
  1128  						JsonName: proto.String("uint64Value"),
  1129  						Number:   proto.Int32(4),
  1130  						Type:     descriptorpb.FieldDescriptorProto_TYPE_UINT64.Enum(),
  1131  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1132  					},
  1133  					{
  1134  						Name:     proto.String("float_value"),
  1135  						JsonName: proto.String("floatValue"),
  1136  						Number:   proto.Int32(5),
  1137  						Type:     descriptorpb.FieldDescriptorProto_TYPE_FLOAT.Enum(),
  1138  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1139  					},
  1140  					{
  1141  						Name:     proto.String("double_value"),
  1142  						JsonName: proto.String("doubleValue"),
  1143  						Number:   proto.Int32(6),
  1144  						Type:     descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
  1145  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1146  					},
  1147  					{
  1148  						Name:     proto.String("bool_value"),
  1149  						JsonName: proto.String("boolValue"),
  1150  						Number:   proto.Int32(7),
  1151  						Type:     descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
  1152  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1153  					},
  1154  					{
  1155  						Name:     proto.String("enum_value"),
  1156  						JsonName: proto.String("enumValue"),
  1157  						TypeName: proto.String("testdata_TestEnum_E.TestEnum"),
  1158  						Number:   proto.Int32(8),
  1159  						Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1160  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1161  					},
  1162  					{
  1163  						Name:     proto.String("string_value"),
  1164  						JsonName: proto.String("stringValue"),
  1165  						Number:   proto.Int32(9),
  1166  						Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1167  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum(),
  1168  					},
  1169  					{
  1170  						Name:     proto.String("fixed64_value"),
  1171  						JsonName: proto.String("fixed64Value"),
  1172  						Number:   proto.Int32(10),
  1173  						Type:     descriptorpb.FieldDescriptorProto_TYPE_FIXED64.Enum(),
  1174  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1175  					},
  1176  				},
  1177  				NestedType: []*descriptorpb.DescriptorProto{
  1178  					{
  1179  						Name: proto.String("testdata_TestEnum_E"),
  1180  						EnumType: []*descriptorpb.EnumDescriptorProto{
  1181  							{
  1182  								Name: proto.String("TestEnum"),
  1183  								Value: []*descriptorpb.EnumValueDescriptorProto{
  1184  									{
  1185  										Name:   proto.String("TestEnum0"),
  1186  										Number: proto.Int32(0),
  1187  									},
  1188  									{
  1189  										Name:   proto.String("TestEnum1"),
  1190  										Number: proto.Int32(1),
  1191  									},
  1192  								},
  1193  							},
  1194  						},
  1195  					},
  1196  				},
  1197  			},
  1198  		},
  1199  		{
  1200  			description: "ContainsRecursive",
  1201  			in:          (&testdata.ContainsRecursive{}).ProtoReflect().Descriptor(),
  1202  			wantErr:     true,
  1203  		},
  1204  		{
  1205  			description: "RecursiveTypeTopMessage",
  1206  			in:          (&testdata.RecursiveTypeTopMessage{}).ProtoReflect().Descriptor(),
  1207  			wantErr:     true,
  1208  		},
  1209  		{
  1210  			description: "ComplexType",
  1211  			in:          (&testdata.ComplexType{}).ProtoReflect().Descriptor(),
  1212  			want: &descriptorpb.DescriptorProto{
  1213  				Name: proto.String("testdata_ComplexType"),
  1214  				Field: []*descriptorpb.FieldDescriptorProto{
  1215  					{
  1216  						Name:     proto.String("nested_repeated_type"),
  1217  						JsonName: proto.String("nestedRepeatedType"),
  1218  						Number:   proto.Int32(1),
  1219  						TypeName: proto.String("testdata_NestedType"),
  1220  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1221  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1222  					},
  1223  					{
  1224  						Name:     proto.String("inner_type"),
  1225  						JsonName: proto.String("innerType"),
  1226  						Number:   proto.Int32(2),
  1227  						TypeName: proto.String("testdata_InnerType"),
  1228  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1229  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1230  					},
  1231  					{
  1232  						Name:     proto.String("range_type"),
  1233  						JsonName: proto.String("rangeType"),
  1234  						Number:   proto.Int32(3),
  1235  						TypeName: proto.String("testdata_RangeTypeTimestamp"),
  1236  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1237  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1238  					},
  1239  				},
  1240  				NestedType: []*descriptorpb.DescriptorProto{
  1241  					{
  1242  						Name: proto.String("testdata_InnerType"),
  1243  						Field: []*descriptorpb.FieldDescriptorProto{
  1244  							{
  1245  								Name:     proto.String("value"),
  1246  								JsonName: proto.String("value"),
  1247  								Number:   proto.Int32(1),
  1248  								Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1249  								Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1250  							},
  1251  						},
  1252  					},
  1253  					{
  1254  						Name: proto.String("testdata_NestedType"),
  1255  						Field: []*descriptorpb.FieldDescriptorProto{
  1256  							{
  1257  								Name:     proto.String("inner_type"),
  1258  								JsonName: proto.String("innerType"),
  1259  								Number:   proto.Int32(1),
  1260  								TypeName: proto.String("testdata_InnerType"),
  1261  								Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1262  								Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1263  							},
  1264  						},
  1265  					},
  1266  					{
  1267  						Name: proto.String("testdata_RangeTypeTimestamp"),
  1268  						Field: []*descriptorpb.FieldDescriptorProto{
  1269  							{
  1270  								Name:     proto.String("start"),
  1271  								JsonName: proto.String("start"),
  1272  								Number:   proto.Int32(1),
  1273  								Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1274  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1275  							},
  1276  							{
  1277  								Name:     proto.String("end"),
  1278  								JsonName: proto.String("end"),
  1279  								Number:   proto.Int32(2),
  1280  								Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1281  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1282  							},
  1283  						},
  1284  					},
  1285  				},
  1286  			},
  1287  		},
  1288  		{
  1289  			description: "WithWellKnownTypes",
  1290  			in:          (&testdata.WithWellKnownTypes{}).ProtoReflect().Descriptor(),
  1291  			want: &descriptorpb.DescriptorProto{
  1292  				Name: proto.String("testdata_WithWellKnownTypes"),
  1293  				Field: []*descriptorpb.FieldDescriptorProto{
  1294  					{
  1295  						Name:     proto.String("int64_value"),
  1296  						JsonName: proto.String("int64Value"),
  1297  						Number:   proto.Int32(1),
  1298  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1299  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1300  					},
  1301  					{
  1302  						Name:     proto.String("wrapped_int64"),
  1303  						JsonName: proto.String("wrappedInt64"),
  1304  						Number:   proto.Int32(2),
  1305  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1306  						TypeName: proto.String("google_protobuf_Int64Value"),
  1307  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1308  					},
  1309  					{
  1310  						Name:     proto.String("string_value"),
  1311  						JsonName: proto.String("stringValue"),
  1312  						Number:   proto.Int32(3),
  1313  						Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1314  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1315  					},
  1316  					{
  1317  						Name:     proto.String("wrapped_string"),
  1318  						JsonName: proto.String("wrappedString"),
  1319  						Number:   proto.Int32(4),
  1320  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1321  						TypeName: proto.String("google_protobuf_StringValue"),
  1322  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1323  					},
  1324  				},
  1325  				NestedType: []*descriptorpb.DescriptorProto{
  1326  					{
  1327  						Name: proto.String("google_protobuf_Int64Value"),
  1328  						Field: []*descriptorpb.FieldDescriptorProto{
  1329  							{
  1330  								Name:         proto.String("value"),
  1331  								JsonName:     proto.String("value"),
  1332  								Number:       proto.Int32(1),
  1333  								DefaultValue: proto.String("0"),
  1334  								Type:         descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1335  								Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1336  							},
  1337  						},
  1338  					},
  1339  					{
  1340  						Name: proto.String("google_protobuf_StringValue"),
  1341  						Field: []*descriptorpb.FieldDescriptorProto{
  1342  							{
  1343  								Name:         proto.String("value"),
  1344  								JsonName:     proto.String("value"),
  1345  								Number:       proto.Int32(1),
  1346  								DefaultValue: proto.String(""),
  1347  								Type:         descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1348  								Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1349  							},
  1350  						},
  1351  					},
  1352  				},
  1353  			},
  1354  		},
  1355  		{
  1356  			description: "WithOneOf",
  1357  			in:          (&testdata.WithOneOf{}).ProtoReflect().Descriptor(),
  1358  			want: &descriptorpb.DescriptorProto{
  1359  				Name: proto.String("testdata_WithOneOf"),
  1360  				Field: []*descriptorpb.FieldDescriptorProto{
  1361  					{
  1362  						Name:     proto.String("int32_value"),
  1363  						JsonName: proto.String("int32Value"),
  1364  						Number:   proto.Int32(1),
  1365  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
  1366  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1367  					},
  1368  					{
  1369  						Name:     proto.String("string_value"),
  1370  						JsonName: proto.String("stringValue"),
  1371  						Number:   proto.Int32(2),
  1372  						Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1373  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1374  					},
  1375  					{
  1376  						Name:     proto.String("double_value"),
  1377  						JsonName: proto.String("doubleValue"),
  1378  						Number:   proto.Int32(3),
  1379  						Type:     descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
  1380  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1381  					},
  1382  				},
  1383  			},
  1384  		},
  1385  		{
  1386  			description: "WithProto3Optional",
  1387  			in:          (&testdata.SimpleMessageProto3WithOptional{}).ProtoReflect().Descriptor(),
  1388  			want: &descriptorpb.DescriptorProto{
  1389  				Name: proto.String("testdata_SimpleMessageProto3WithOptional"),
  1390  				Field: []*descriptorpb.FieldDescriptorProto{
  1391  					{
  1392  						Name:         proto.String("name"),
  1393  						JsonName:     proto.String("name"),
  1394  						Number:       proto.Int32(1),
  1395  						DefaultValue: proto.String(""),
  1396  						Type:         descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1397  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1398  					},
  1399  					{
  1400  						Name:     proto.String("value"),
  1401  						JsonName: proto.String("value"),
  1402  						Number:   proto.Int32(2),
  1403  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1404  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1405  					},
  1406  				},
  1407  			},
  1408  		},
  1409  		{
  1410  			description: "WithProto3Defaults",
  1411  			in:          (&testdata.ValidationP3Defaults{}).ProtoReflect().Descriptor(),
  1412  			want: &descriptorpb.DescriptorProto{
  1413  				Name: proto.String("testdata_ValidationP3Defaults"),
  1414  				Field: []*descriptorpb.FieldDescriptorProto{
  1415  					{
  1416  						Name:         proto.String("double_field"),
  1417  						JsonName:     proto.String("doubleField"),
  1418  						Number:       proto.Int32(1),
  1419  						Type:         descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
  1420  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1421  						DefaultValue: proto.String("0"),
  1422  					},
  1423  					{
  1424  						Name:         proto.String("float_field"),
  1425  						JsonName:     proto.String("floatField"),
  1426  						Number:       proto.Int32(2),
  1427  						Type:         descriptorpb.FieldDescriptorProto_TYPE_FLOAT.Enum(),
  1428  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1429  						DefaultValue: proto.String("0"),
  1430  					},
  1431  					{
  1432  						Name:         proto.String("int32_field"),
  1433  						JsonName:     proto.String("int32Field"),
  1434  						Number:       proto.Int32(3),
  1435  						Type:         descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
  1436  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1437  						DefaultValue: proto.String("0"),
  1438  					},
  1439  					{
  1440  						Name:         proto.String("int64_field"),
  1441  						JsonName:     proto.String("int64Field"),
  1442  						Number:       proto.Int32(4),
  1443  						Type:         descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1444  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1445  						DefaultValue: proto.String("0"),
  1446  					},
  1447  					{
  1448  						Name:         proto.String("uint32_field"),
  1449  						JsonName:     proto.String("uint32Field"),
  1450  						Number:       proto.Int32(5),
  1451  						Type:         descriptorpb.FieldDescriptorProto_TYPE_UINT32.Enum(),
  1452  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1453  						DefaultValue: proto.String("0"),
  1454  					},
  1455  					{
  1456  						Name:         proto.String("sint32_field"),
  1457  						JsonName:     proto.String("sint32Field"),
  1458  						Number:       proto.Int32(7),
  1459  						Type:         descriptorpb.FieldDescriptorProto_TYPE_SINT32.Enum(),
  1460  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1461  						DefaultValue: proto.String("0"),
  1462  					},
  1463  					{
  1464  						Name:         proto.String("sint64_field"),
  1465  						JsonName:     proto.String("sint64Field"),
  1466  						Number:       proto.Int32(8),
  1467  						Type:         descriptorpb.FieldDescriptorProto_TYPE_SINT64.Enum(),
  1468  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1469  						DefaultValue: proto.String("0"),
  1470  					},
  1471  					{
  1472  						Name:         proto.String("fixed32_field"),
  1473  						JsonName:     proto.String("fixed32Field"),
  1474  						Number:       proto.Int32(9),
  1475  						Type:         descriptorpb.FieldDescriptorProto_TYPE_FIXED32.Enum(),
  1476  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1477  						DefaultValue: proto.String("0"),
  1478  					},
  1479  					{
  1480  						Name:         proto.String("sfixed32_field"),
  1481  						JsonName:     proto.String("sfixed32Field"),
  1482  						Number:       proto.Int32(11),
  1483  						Type:         descriptorpb.FieldDescriptorProto_TYPE_SFIXED32.Enum(),
  1484  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1485  						DefaultValue: proto.String("0"),
  1486  					},
  1487  					{
  1488  						Name:         proto.String("sfixed64_field"),
  1489  						JsonName:     proto.String("sfixed64Field"),
  1490  						Number:       proto.Int32(12),
  1491  						Type:         descriptorpb.FieldDescriptorProto_TYPE_SFIXED64.Enum(),
  1492  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1493  						DefaultValue: proto.String("0"),
  1494  					},
  1495  					{
  1496  						Name:         proto.String("bool_field"),
  1497  						JsonName:     proto.String("boolField"),
  1498  						Number:       proto.Int32(13),
  1499  						Type:         descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
  1500  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1501  						DefaultValue: proto.String("false"),
  1502  					},
  1503  					{
  1504  						Name:         proto.String("string_field"),
  1505  						JsonName:     proto.String("stringField"),
  1506  						Number:       proto.Int32(14),
  1507  						Type:         descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1508  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1509  						DefaultValue: proto.String(""),
  1510  					},
  1511  					{
  1512  						Name:         proto.String("bytes_field"),
  1513  						JsonName:     proto.String("bytesField"),
  1514  						Number:       proto.Int32(15),
  1515  						Type:         descriptorpb.FieldDescriptorProto_TYPE_BYTES.Enum(),
  1516  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1517  						DefaultValue: proto.String(""),
  1518  					},
  1519  					{
  1520  						Name:         proto.String("enum_field"),
  1521  						JsonName:     proto.String("enumField"),
  1522  						Number:       proto.Int32(16),
  1523  						Type:         descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1524  						TypeName:     proto.String("testdata_Proto3ExampleEnum_E.Proto3ExampleEnum"),
  1525  						Label:        descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1526  						DefaultValue: proto.String("P3_UNDEFINED"),
  1527  					},
  1528  				},
  1529  				NestedType: []*descriptorpb.DescriptorProto{
  1530  					{
  1531  						Name: proto.String("testdata_Proto3ExampleEnum_E"),
  1532  						EnumType: []*descriptorpb.EnumDescriptorProto{
  1533  							{
  1534  								Name: proto.String("Proto3ExampleEnum"),
  1535  								Value: []*descriptorpb.EnumValueDescriptorProto{
  1536  									{
  1537  										Name:   proto.String("P3_UNDEFINED"),
  1538  										Number: proto.Int32(0),
  1539  									},
  1540  									{
  1541  										Name:   proto.String("P3_THING"),
  1542  										Number: proto.Int32(1),
  1543  									},
  1544  									{
  1545  										Name:   proto.String("P3_OTHER_THING"),
  1546  										Number: proto.Int32(2),
  1547  									},
  1548  									{
  1549  										Name:   proto.String("P3_THIRD_THING"),
  1550  										Number: proto.Int32(3),
  1551  									},
  1552  								},
  1553  							},
  1554  						},
  1555  					},
  1556  				},
  1557  			},
  1558  		},
  1559  		{
  1560  			description: "WithExternalEnum",
  1561  			in:          (&testdata.ExternalEnumMessage{}).ProtoReflect().Descriptor(),
  1562  			want: &descriptorpb.DescriptorProto{
  1563  				Name: proto.String("testdata_ExternalEnumMessage"),
  1564  				Field: []*descriptorpb.FieldDescriptorProto{
  1565  					{
  1566  						Name:     proto.String("msg_a"),
  1567  						JsonName: proto.String("msgA"),
  1568  						Number:   proto.Int32(1),
  1569  						TypeName: proto.String("testdata_EnumMsgA"),
  1570  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1571  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1572  					},
  1573  					{
  1574  						Name:     proto.String("msg_b"),
  1575  						JsonName: proto.String("msgB"),
  1576  						Number:   proto.Int32(2),
  1577  						TypeName: proto.String("testdata_EnumMsgB"),
  1578  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1579  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1580  					},
  1581  				},
  1582  				NestedType: []*descriptorpb.DescriptorProto{
  1583  					{
  1584  						Name: proto.String("testdata_EnumMsgA"),
  1585  						Field: []*descriptorpb.FieldDescriptorProto{
  1586  							{
  1587  								Name:     proto.String("foo"),
  1588  								JsonName: proto.String("foo"),
  1589  								Number:   proto.Int32(1),
  1590  								Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1591  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1592  							},
  1593  							{
  1594  								Name:     proto.String("bar"),
  1595  								JsonName: proto.String("bar"),
  1596  								Number:   proto.Int32(2),
  1597  								Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1598  								TypeName: proto.String("testdata_ExtEnum_E.ExtEnum"),
  1599  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1600  							},
  1601  						},
  1602  					},
  1603  					{
  1604  						Name: proto.String("testdata_EnumMsgB"),
  1605  						Field: []*descriptorpb.FieldDescriptorProto{
  1606  							{
  1607  								Name:     proto.String("baz"),
  1608  								JsonName: proto.String("baz"),
  1609  								Number:   proto.Int32(1),
  1610  								Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1611  								TypeName: proto.String("testdata_ExtEnum_E.ExtEnum"),
  1612  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1613  							},
  1614  						},
  1615  					},
  1616  					{
  1617  						Name: proto.String("testdata_ExtEnum_E"),
  1618  						EnumType: []*descriptorpb.EnumDescriptorProto{
  1619  							{
  1620  								Name: proto.String("ExtEnum"),
  1621  								Value: []*descriptorpb.EnumValueDescriptorProto{
  1622  									{
  1623  										Name:   proto.String("UNDEFINED"),
  1624  										Number: proto.Int32(0),
  1625  									},
  1626  									{
  1627  										Name:   proto.String("THING"),
  1628  										Number: proto.Int32(1),
  1629  									},
  1630  									{
  1631  										Name:   proto.String("OTHER_THING"),
  1632  										Number: proto.Int32(2),
  1633  									},
  1634  								},
  1635  							},
  1636  						},
  1637  					},
  1638  				},
  1639  			},
  1640  		},
  1641  		{
  1642  			description: "OutOfOrderDefinitionProto2",
  1643  			in:          (&testdata.OutOfOrderDefinitionProto2{}).ProtoReflect().Descriptor(),
  1644  			want: &descriptorpb.DescriptorProto{
  1645  				Name: proto.String("testdata_OutOfOrderDefinitionProto2"),
  1646  				Field: []*descriptorpb.FieldDescriptorProto{
  1647  					{
  1648  						Name:     proto.String("s1"),
  1649  						JsonName: proto.String("s1"),
  1650  						Number:   proto.Int32(1),
  1651  						Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1652  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1653  					},
  1654  					{
  1655  						Name:     proto.String("s2"),
  1656  						JsonName: proto.String("s2"),
  1657  						Number:   proto.Int32(2),
  1658  						Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1659  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1660  					},
  1661  					{
  1662  						Name:     proto.String("s3"),
  1663  						JsonName: proto.String("s3"),
  1664  						Number:   proto.Int32(3),
  1665  						Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1666  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1667  					},
  1668  					{
  1669  						Name:     proto.String("enum1"),
  1670  						JsonName: proto.String("enum1"),
  1671  						Number:   proto.Int32(4),
  1672  						Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1673  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1674  						TypeName: proto.String("testdata_OutOfOrderDefinitionProto2_OutOfOrderEnum_E.OutOfOrderEnum"),
  1675  					},
  1676  					{
  1677  						Name:     proto.String("enum2"),
  1678  						JsonName: proto.String("enum2"),
  1679  						Number:   proto.Int32(5),
  1680  						Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1681  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1682  						TypeName: proto.String("testdata_OutOfOrderDefinitionProto2_OutOfOrderEnum_E.OutOfOrderEnum"),
  1683  					},
  1684  					{
  1685  						Name:     proto.String("msg6"),
  1686  						JsonName: proto.String("msg6"),
  1687  						Number:   proto.Int32(6),
  1688  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1689  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1690  						TypeName: proto.String("testdata_SimpleMessageProto2"),
  1691  					},
  1692  					{
  1693  						Name:     proto.String("msg7"),
  1694  						JsonName: proto.String("msg7"),
  1695  						Number:   proto.Int32(7),
  1696  						Type:     descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(),
  1697  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1698  						TypeName: proto.String("testdata_SimpleMessageProto2"),
  1699  					},
  1700  				},
  1701  				NestedType: []*descriptorpb.DescriptorProto{
  1702  					{
  1703  						Name: proto.String("testdata_OutOfOrderDefinitionProto2_OutOfOrderEnum_E"),
  1704  						EnumType: []*descriptorpb.EnumDescriptorProto{
  1705  							{
  1706  								Name: proto.String("OutOfOrderEnum"),
  1707  								Value: []*descriptorpb.EnumValueDescriptorProto{
  1708  									{
  1709  										Name:   proto.String("E1"),
  1710  										Number: proto.Int32(1),
  1711  									},
  1712  									{
  1713  										Name:   proto.String("E2"),
  1714  										Number: proto.Int32(2),
  1715  									},
  1716  									{
  1717  										Name:   proto.String("E3"),
  1718  										Number: proto.Int32(3),
  1719  									},
  1720  								},
  1721  							},
  1722  						},
  1723  					},
  1724  					{
  1725  						Name: proto.String("testdata_SimpleMessageProto2"),
  1726  						Field: []*descriptorpb.FieldDescriptorProto{
  1727  							{
  1728  								Name:     proto.String("name"),
  1729  								JsonName: proto.String("name"),
  1730  								Number:   proto.Int32(1),
  1731  								Type:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),
  1732  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1733  							},
  1734  							{
  1735  								Name:     proto.String("value"),
  1736  								JsonName: proto.String("value"),
  1737  								Number:   proto.Int32(2),
  1738  								Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1739  								Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1740  							},
  1741  						},
  1742  					},
  1743  				},
  1744  			},
  1745  		},
  1746  		{
  1747  			description: "ValidationP3PackedRepeated",
  1748  			in:          (&testdata.ValidationP3PackedRepeated{}).ProtoReflect().Descriptor(),
  1749  			want: &descriptorpb.DescriptorProto{
  1750  				Name: proto.String("testdata_ValidationP3PackedRepeated"),
  1751  				Field: []*descriptorpb.FieldDescriptorProto{
  1752  					{
  1753  						Name:     proto.String("id"),
  1754  						JsonName: proto.String("id"),
  1755  						Number:   proto.Int32(1),
  1756  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1757  						Label:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
  1758  					},
  1759  					{
  1760  						Name:     proto.String("double_repeated"),
  1761  						JsonName: proto.String("doubleRepeated"),
  1762  						Number:   proto.Int32(2),
  1763  						Type:     descriptorpb.FieldDescriptorProto_TYPE_DOUBLE.Enum(),
  1764  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1765  					},
  1766  					{
  1767  						Name:     proto.String("float_repeated"),
  1768  						JsonName: proto.String("floatRepeated"),
  1769  						Number:   proto.Int32(3),
  1770  						Type:     descriptorpb.FieldDescriptorProto_TYPE_FLOAT.Enum(),
  1771  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1772  					},
  1773  					{
  1774  						Name:     proto.String("int32_repeated"),
  1775  						JsonName: proto.String("int32Repeated"),
  1776  						Number:   proto.Int32(4),
  1777  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT32.Enum(),
  1778  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1779  					},
  1780  					{
  1781  						Name:     proto.String("int64_repeated"),
  1782  						JsonName: proto.String("int64Repeated"),
  1783  						Number:   proto.Int32(5),
  1784  						Type:     descriptorpb.FieldDescriptorProto_TYPE_INT64.Enum(),
  1785  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1786  					},
  1787  					{
  1788  						Name:     proto.String("uint32_repeated"),
  1789  						JsonName: proto.String("uint32Repeated"),
  1790  						Number:   proto.Int32(6),
  1791  						Type:     descriptorpb.FieldDescriptorProto_TYPE_UINT32.Enum(),
  1792  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1793  					},
  1794  					{
  1795  						Name:     proto.String("sint32_repeated"),
  1796  						JsonName: proto.String("sint32Repeated"),
  1797  						Number:   proto.Int32(7),
  1798  						Type:     descriptorpb.FieldDescriptorProto_TYPE_SINT32.Enum(),
  1799  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1800  					},
  1801  					{
  1802  						Name:     proto.String("sint64_repeated"),
  1803  						JsonName: proto.String("sint64Repeated"),
  1804  						Number:   proto.Int32(8),
  1805  						Type:     descriptorpb.FieldDescriptorProto_TYPE_SINT64.Enum(),
  1806  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1807  					},
  1808  					{
  1809  						Name:     proto.String("fixed32_repeated"),
  1810  						JsonName: proto.String("fixed32Repeated"),
  1811  						Number:   proto.Int32(9),
  1812  						Type:     descriptorpb.FieldDescriptorProto_TYPE_FIXED32.Enum(),
  1813  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1814  					},
  1815  					{
  1816  						Name:     proto.String("sfixed32_repeated"),
  1817  						JsonName: proto.String("sfixed32Repeated"),
  1818  						Number:   proto.Int32(10),
  1819  						Type:     descriptorpb.FieldDescriptorProto_TYPE_SFIXED32.Enum(),
  1820  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1821  					},
  1822  					{
  1823  						Name:     proto.String("sfixed64_repeated"),
  1824  						JsonName: proto.String("sfixed64Repeated"),
  1825  						Number:   proto.Int32(11),
  1826  						Type:     descriptorpb.FieldDescriptorProto_TYPE_SFIXED64.Enum(),
  1827  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1828  					},
  1829  
  1830  					{
  1831  						Name:     proto.String("bool_repeated"),
  1832  						JsonName: proto.String("boolRepeated"),
  1833  						Number:   proto.Int32(12),
  1834  						Type:     descriptorpb.FieldDescriptorProto_TYPE_BOOL.Enum(),
  1835  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1836  					},
  1837  					{
  1838  						Name:     proto.String("enum_repeated"),
  1839  						JsonName: proto.String("enumRepeated"),
  1840  						Number:   proto.Int32(13),
  1841  						Type:     descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum(),
  1842  						TypeName: proto.String("testdata_Proto3ExampleEnum_E.Proto3ExampleEnum"),
  1843  						Label:    descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(),
  1844  					},
  1845  				},
  1846  				NestedType: []*descriptorpb.DescriptorProto{
  1847  					{
  1848  						Name: proto.String("testdata_Proto3ExampleEnum_E"),
  1849  						EnumType: []*descriptorpb.EnumDescriptorProto{
  1850  							{
  1851  								Name: proto.String("Proto3ExampleEnum"),
  1852  								Value: []*descriptorpb.EnumValueDescriptorProto{
  1853  									{
  1854  										Name:   proto.String("P3_UNDEFINED"),
  1855  										Number: proto.Int32(0),
  1856  									},
  1857  									{
  1858  										Name:   proto.String("P3_THING"),
  1859  										Number: proto.Int32(1),
  1860  									},
  1861  									{
  1862  										Name:   proto.String("P3_OTHER_THING"),
  1863  										Number: proto.Int32(2),
  1864  									},
  1865  									{
  1866  										Name:   proto.String("P3_THIRD_THING"),
  1867  										Number: proto.Int32(3),
  1868  									},
  1869  								},
  1870  							},
  1871  						},
  1872  					},
  1873  				},
  1874  			},
  1875  		},
  1876  	}
  1877  
  1878  	for _, tc := range testCases {
  1879  		gotDP, err := NormalizeDescriptor(tc.in)
  1880  
  1881  		if tc.wantErr && err == nil {
  1882  			t.Errorf("%s: wanted err but got success", tc.description)
  1883  			continue
  1884  		}
  1885  		if !tc.wantErr && err != nil {
  1886  			t.Errorf("%s: wanted success, got err: %v", tc.description, err)
  1887  			continue
  1888  		}
  1889  		if diff := cmp.Diff(gotDP, tc.want, protocmp.Transform()); diff != "" {
  1890  			t.Errorf("%s: -got, +want:\n%s", tc.description, diff)
  1891  		}
  1892  	}
  1893  }
  1894  

View as plain text