...

Source file src/google.golang.org/protobuf/testing/protocmp/util_test.go

Documentation: google.golang.org/protobuf/testing/protocmp

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package protocmp
     6  
     7  import (
     8  	"math"
     9  	"math/rand"
    10  	"sort"
    11  	"testing"
    12  
    13  	"github.com/google/go-cmp/cmp"
    14  
    15  	"google.golang.org/protobuf/proto"
    16  	"google.golang.org/protobuf/reflect/protoreflect"
    17  	"google.golang.org/protobuf/testing/protopack"
    18  	"google.golang.org/protobuf/types/dynamicpb"
    19  
    20  	testpb "google.golang.org/protobuf/internal/testprotos/test"
    21  )
    22  
    23  func TestEqual(t *testing.T) {
    24  	type test struct {
    25  		x, y interface{}
    26  		opts cmp.Options
    27  		want bool
    28  	}
    29  	var tests []test
    30  
    31  	allTypesDesc := (*testpb.TestAllTypes)(nil).ProtoReflect().Descriptor()
    32  
    33  	// Test nil and empty messages of differing types.
    34  	tests = append(tests, []test{{
    35  		x:    (*testpb.TestAllTypes)(nil),
    36  		y:    (*testpb.TestAllTypes)(nil),
    37  		opts: cmp.Options{Transform()},
    38  		want: true,
    39  	}, {
    40  		x:    (*testpb.TestAllTypes)(nil),
    41  		y:    (*testpb.TestAllExtensions)(nil),
    42  		opts: cmp.Options{Transform()},
    43  		want: false,
    44  	}, {
    45  		x:    (*testpb.TestAllTypes)(nil),
    46  		y:    new(testpb.TestAllTypes),
    47  		opts: cmp.Options{Transform()},
    48  		want: false,
    49  	}, {
    50  		x:    (*testpb.TestAllTypes)(nil),
    51  		y:    dynamicpb.NewMessage(allTypesDesc),
    52  		opts: cmp.Options{Transform()},
    53  		want: false,
    54  	}, {
    55  		x:    (*testpb.TestAllTypes)(nil),
    56  		y:    new(testpb.TestAllTypes),
    57  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
    58  		want: true,
    59  	}, {
    60  		x:    (*testpb.TestAllTypes)(nil),
    61  		y:    dynamicpb.NewMessage(allTypesDesc),
    62  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
    63  		want: true,
    64  	}, {
    65  		x:    new(testpb.TestAllTypes),
    66  		y:    new(testpb.TestAllTypes),
    67  		opts: cmp.Options{Transform()},
    68  		want: true,
    69  	}, {
    70  		x:    new(testpb.TestAllTypes),
    71  		y:    dynamicpb.NewMessage(allTypesDesc),
    72  		opts: cmp.Options{Transform()},
    73  		want: true,
    74  	}, {
    75  		x:    new(testpb.TestAllTypes),
    76  		y:    new(testpb.TestAllExtensions),
    77  		opts: cmp.Options{Transform()},
    78  		want: false,
    79  	}, {
    80  		x:    struct{ I interface{} }{(*testpb.TestAllTypes)(nil)},
    81  		y:    struct{ I interface{} }{(*testpb.TestAllTypes)(nil)},
    82  		opts: cmp.Options{Transform()},
    83  		want: true,
    84  	}, {
    85  		x:    struct{ I interface{} }{(*testpb.TestAllTypes)(nil)},
    86  		y:    struct{ I interface{} }{new(testpb.TestAllTypes)},
    87  		opts: cmp.Options{Transform()},
    88  		want: false,
    89  	}, {
    90  		x:    struct{ I interface{} }{(*testpb.TestAllTypes)(nil)},
    91  		y:    struct{ I interface{} }{dynamicpb.NewMessage(allTypesDesc)},
    92  		opts: cmp.Options{Transform()},
    93  		want: false,
    94  	}, {
    95  		x:    struct{ I interface{} }{(*testpb.TestAllTypes)(nil)},
    96  		y:    struct{ I interface{} }{new(testpb.TestAllTypes)},
    97  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
    98  		want: true,
    99  	}, {
   100  		x:    struct{ I interface{} }{(*testpb.TestAllTypes)(nil)},
   101  		y:    struct{ I interface{} }{dynamicpb.NewMessage(allTypesDesc)},
   102  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   103  		want: true,
   104  	}, {
   105  		x:    struct{ I interface{} }{new(testpb.TestAllTypes)},
   106  		y:    struct{ I interface{} }{new(testpb.TestAllTypes)},
   107  		opts: cmp.Options{Transform()},
   108  		want: true,
   109  	}, {
   110  		x:    struct{ I interface{} }{new(testpb.TestAllTypes)},
   111  		y:    struct{ I interface{} }{dynamicpb.NewMessage(allTypesDesc)},
   112  		opts: cmp.Options{Transform()},
   113  		want: true,
   114  	}, {
   115  		x:    struct{ M proto.Message }{(*testpb.TestAllTypes)(nil)},
   116  		y:    struct{ M proto.Message }{(*testpb.TestAllTypes)(nil)},
   117  		opts: cmp.Options{Transform()},
   118  		want: true,
   119  	}, {
   120  		x:    struct{ M proto.Message }{(*testpb.TestAllTypes)(nil)},
   121  		y:    struct{ M proto.Message }{new(testpb.TestAllTypes)},
   122  		opts: cmp.Options{Transform()},
   123  		want: false,
   124  	}, {
   125  		x:    struct{ M proto.Message }{(*testpb.TestAllTypes)(nil)},
   126  		y:    struct{ M proto.Message }{dynamicpb.NewMessage(allTypesDesc)},
   127  		opts: cmp.Options{Transform()},
   128  		want: false,
   129  	}, {
   130  		x:    struct{ M proto.Message }{(*testpb.TestAllTypes)(nil)},
   131  		y:    struct{ M proto.Message }{new(testpb.TestAllTypes)},
   132  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   133  		want: true,
   134  	}, {
   135  		x:    struct{ M proto.Message }{(*testpb.TestAllTypes)(nil)},
   136  		y:    struct{ M proto.Message }{dynamicpb.NewMessage(allTypesDesc)},
   137  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   138  		want: true,
   139  	}, {
   140  		x:    struct{ M proto.Message }{new(testpb.TestAllTypes)},
   141  		y:    struct{ M proto.Message }{new(testpb.TestAllTypes)},
   142  		opts: cmp.Options{Transform()},
   143  		want: true,
   144  	}, {
   145  		x:    struct{ M proto.Message }{new(testpb.TestAllTypes)},
   146  		y:    struct{ M proto.Message }{dynamicpb.NewMessage(allTypesDesc)},
   147  		opts: cmp.Options{Transform()},
   148  		want: true,
   149  	}}...)
   150  
   151  	// Test message values.
   152  	tests = append(tests, []test{{
   153  		x:    testpb.TestAllTypes{OptionalSint64: proto.Int64(1)},
   154  		y:    testpb.TestAllTypes{OptionalSint64: proto.Int64(1)},
   155  		opts: cmp.Options{Transform()},
   156  		want: true,
   157  	}, {
   158  		x:    testpb.TestAllTypes{OptionalSint64: proto.Int64(1)},
   159  		y:    testpb.TestAllTypes{OptionalSint64: proto.Int64(2)},
   160  		opts: cmp.Options{Transform()},
   161  		want: false,
   162  	}, {
   163  		x:    struct{ M testpb.TestAllTypes }{M: testpb.TestAllTypes{OptionalSint64: proto.Int64(1)}},
   164  		y:    struct{ M testpb.TestAllTypes }{M: testpb.TestAllTypes{OptionalSint64: proto.Int64(1)}},
   165  		opts: cmp.Options{Transform()},
   166  		want: true,
   167  	}, {
   168  		x:    struct{ M testpb.TestAllTypes }{M: testpb.TestAllTypes{OptionalSint64: proto.Int64(1)}},
   169  		y:    struct{ M testpb.TestAllTypes }{M: testpb.TestAllTypes{OptionalSint64: proto.Int64(2)}},
   170  		opts: cmp.Options{Transform()},
   171  		want: false,
   172  	}, {
   173  		x:    struct{ M []testpb.TestAllTypes }{M: []testpb.TestAllTypes{{OptionalSint64: proto.Int64(1)}}},
   174  		y:    struct{ M []testpb.TestAllTypes }{M: []testpb.TestAllTypes{{OptionalSint64: proto.Int64(1)}}},
   175  		opts: cmp.Options{Transform()},
   176  		want: true,
   177  	}, {
   178  		x:    struct{ M []testpb.TestAllTypes }{M: []testpb.TestAllTypes{{OptionalSint64: proto.Int64(1)}}},
   179  		y:    struct{ M []testpb.TestAllTypes }{M: []testpb.TestAllTypes{{OptionalSint64: proto.Int64(2)}}},
   180  		opts: cmp.Options{Transform()},
   181  		want: false,
   182  	}, {
   183  		x: struct {
   184  			M map[string]testpb.TestAllTypes
   185  		}{
   186  			M: map[string]testpb.TestAllTypes{"k": {OptionalSint64: proto.Int64(1)}},
   187  		},
   188  		y: struct {
   189  			M map[string]testpb.TestAllTypes
   190  		}{
   191  			M: map[string]testpb.TestAllTypes{"k": {OptionalSint64: proto.Int64(1)}},
   192  		},
   193  		opts: cmp.Options{Transform()},
   194  		want: true,
   195  	}, {
   196  		x: struct {
   197  			M map[string]testpb.TestAllTypes
   198  		}{
   199  			M: map[string]testpb.TestAllTypes{"k": {OptionalSint64: proto.Int64(1)}},
   200  		},
   201  		y: struct {
   202  			M map[string]testpb.TestAllTypes
   203  		}{
   204  			M: map[string]testpb.TestAllTypes{"k": {OptionalSint64: proto.Int64(2)}},
   205  		},
   206  		opts: cmp.Options{Transform()},
   207  		want: false,
   208  	}}...)
   209  
   210  	// Test IgnoreUnknown.
   211  	raw := protopack.Message{
   212  		protopack.Tag{1, protopack.BytesType}, protopack.String("Hello, goodbye!"),
   213  	}.Marshal()
   214  	tests = append(tests, []test{{
   215  		x:    apply(&testpb.TestAllTypes{OptionalSint64: proto.Int64(5)}, setUnknown{raw}),
   216  		y:    &testpb.TestAllTypes{OptionalSint64: proto.Int64(5)},
   217  		opts: cmp.Options{Transform()},
   218  		want: false,
   219  	}, {
   220  		x:    apply(&testpb.TestAllTypes{OptionalSint64: proto.Int64(5)}, setUnknown{raw}),
   221  		y:    &testpb.TestAllTypes{OptionalSint64: proto.Int64(5)},
   222  		opts: cmp.Options{Transform(), IgnoreUnknown()},
   223  		want: true,
   224  	}, {
   225  		x:    apply(&testpb.TestAllTypes{OptionalSint64: proto.Int64(5)}, setUnknown{raw}),
   226  		y:    &testpb.TestAllTypes{OptionalSint64: proto.Int64(6)},
   227  		opts: cmp.Options{Transform(), IgnoreUnknown()},
   228  		want: false,
   229  	}, {
   230  		x:    apply(&testpb.TestAllTypes{OptionalSint64: proto.Int64(5)}, setUnknown{raw}),
   231  		y:    apply(dynamicpb.NewMessage(allTypesDesc), setField{6, int64(5)}),
   232  		opts: cmp.Options{Transform()},
   233  		want: false,
   234  	}, {
   235  		x:    apply(&testpb.TestAllTypes{OptionalSint64: proto.Int64(5)}, setUnknown{raw}),
   236  		y:    apply(dynamicpb.NewMessage(allTypesDesc), setField{6, int64(5)}),
   237  		opts: cmp.Options{Transform(), IgnoreUnknown()},
   238  		want: true,
   239  	}}...)
   240  
   241  	// Test IgnoreDefaultScalars.
   242  	tests = append(tests, []test{{
   243  		x: &testpb.TestAllTypes{
   244  			DefaultInt32:  proto.Int32(81),
   245  			DefaultUint32: proto.Uint32(83),
   246  			DefaultFloat:  proto.Float32(91.5),
   247  			DefaultBool:   proto.Bool(true),
   248  			DefaultBytes:  []byte("world"),
   249  		},
   250  		y: &testpb.TestAllTypes{
   251  			DefaultInt64:       proto.Int64(82),
   252  			DefaultUint64:      proto.Uint64(84),
   253  			DefaultDouble:      proto.Float64(92e3),
   254  			DefaultString:      proto.String("hello"),
   255  			DefaultForeignEnum: testpb.ForeignEnum_FOREIGN_BAR.Enum(),
   256  		},
   257  		opts: cmp.Options{Transform()},
   258  		want: false,
   259  	}, {
   260  		x: &testpb.TestAllTypes{
   261  			DefaultInt32:  proto.Int32(81),
   262  			DefaultUint32: proto.Uint32(83),
   263  			DefaultFloat:  proto.Float32(91.5),
   264  			DefaultBool:   proto.Bool(true),
   265  			DefaultBytes:  []byte("world"),
   266  		},
   267  		y: &testpb.TestAllTypes{
   268  			DefaultInt64:       proto.Int64(82),
   269  			DefaultUint64:      proto.Uint64(84),
   270  			DefaultDouble:      proto.Float64(92e3),
   271  			DefaultString:      proto.String("hello"),
   272  			DefaultForeignEnum: testpb.ForeignEnum_FOREIGN_BAR.Enum(),
   273  		},
   274  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   275  		want: true,
   276  	}, {
   277  		x: &testpb.TestAllTypes{
   278  			OptionalInt32:  proto.Int32(81),
   279  			OptionalUint32: proto.Uint32(83),
   280  			OptionalFloat:  proto.Float32(91.5),
   281  			OptionalBool:   proto.Bool(true),
   282  			OptionalBytes:  []byte("world"),
   283  		},
   284  		y: &testpb.TestAllTypes{
   285  			OptionalInt64:       proto.Int64(82),
   286  			OptionalUint64:      proto.Uint64(84),
   287  			OptionalDouble:      proto.Float64(92e3),
   288  			OptionalString:      proto.String("hello"),
   289  			OptionalForeignEnum: testpb.ForeignEnum_FOREIGN_BAR.Enum(),
   290  		},
   291  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   292  		want: false,
   293  	}, {
   294  		x: &testpb.TestAllTypes{
   295  			OptionalInt32:  proto.Int32(0),
   296  			OptionalUint32: proto.Uint32(0),
   297  			OptionalFloat:  proto.Float32(0),
   298  			OptionalBool:   proto.Bool(false),
   299  			OptionalBytes:  []byte(""),
   300  		},
   301  		y: &testpb.TestAllTypes{
   302  			OptionalInt64:       proto.Int64(0),
   303  			OptionalUint64:      proto.Uint64(0),
   304  			OptionalDouble:      proto.Float64(0),
   305  			OptionalString:      proto.String(""),
   306  			OptionalForeignEnum: testpb.ForeignEnum_FOREIGN_FOO.Enum(),
   307  		},
   308  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   309  		want: true,
   310  	}, {
   311  		x: apply(new(testpb.TestAllExtensions),
   312  			setExtension{testpb.E_DefaultInt32, int32(81)},
   313  			setExtension{testpb.E_DefaultUint32, uint32(83)},
   314  			setExtension{testpb.E_DefaultFloat, float32(91.5)},
   315  			setExtension{testpb.E_DefaultBool, bool(true)},
   316  			setExtension{testpb.E_DefaultBytes, []byte("world")}),
   317  		y: apply(new(testpb.TestAllExtensions),
   318  			setExtension{testpb.E_DefaultInt64, int64(82)},
   319  			setExtension{testpb.E_DefaultUint64, uint64(84)},
   320  			setExtension{testpb.E_DefaultDouble, float64(92e3)},
   321  			setExtension{testpb.E_DefaultString, string("hello")}),
   322  		opts: cmp.Options{Transform()},
   323  		want: false,
   324  	}, {
   325  		x: apply(new(testpb.TestAllExtensions),
   326  			setExtension{testpb.E_DefaultInt32, int32(81)},
   327  			setExtension{testpb.E_DefaultUint32, uint32(83)},
   328  			setExtension{testpb.E_DefaultFloat, float32(91.5)},
   329  			setExtension{testpb.E_DefaultBool, bool(true)},
   330  			setExtension{testpb.E_DefaultBytes, []byte("world")}),
   331  		y: apply(new(testpb.TestAllExtensions),
   332  			setExtension{testpb.E_DefaultInt64, int64(82)},
   333  			setExtension{testpb.E_DefaultUint64, uint64(84)},
   334  			setExtension{testpb.E_DefaultDouble, float64(92e3)},
   335  			setExtension{testpb.E_DefaultString, string("hello")}),
   336  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   337  		want: true,
   338  	}, {
   339  		x: apply(new(testpb.TestAllExtensions),
   340  			setExtension{testpb.E_OptionalInt32, int32(0)},
   341  			setExtension{testpb.E_OptionalUint32, uint32(0)},
   342  			setExtension{testpb.E_OptionalFloat, float32(0)},
   343  			setExtension{testpb.E_OptionalBool, bool(false)},
   344  			setExtension{testpb.E_OptionalBytes, []byte("")}),
   345  		y: apply(new(testpb.TestAllExtensions),
   346  			setExtension{testpb.E_OptionalInt64, int64(0)},
   347  			setExtension{testpb.E_OptionalUint64, uint64(0)},
   348  			setExtension{testpb.E_OptionalDouble, float64(0)},
   349  			setExtension{testpb.E_OptionalString, string("")}),
   350  		opts: cmp.Options{Transform()},
   351  		want: false,
   352  	}, {
   353  		x: apply(new(testpb.TestAllExtensions),
   354  			setExtension{testpb.E_OptionalInt32, int32(0)},
   355  			setExtension{testpb.E_OptionalUint32, uint32(0)},
   356  			setExtension{testpb.E_OptionalFloat, float32(0)},
   357  			setExtension{testpb.E_OptionalBool, bool(false)},
   358  			setExtension{testpb.E_OptionalBytes, []byte("")}),
   359  		y: apply(new(testpb.TestAllExtensions),
   360  			setExtension{testpb.E_OptionalInt64, int64(0)},
   361  			setExtension{testpb.E_OptionalUint64, uint64(0)},
   362  			setExtension{testpb.E_OptionalDouble, float64(0)},
   363  			setExtension{testpb.E_OptionalString, string("")}),
   364  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   365  		want: true,
   366  	}, {
   367  		x: &testpb.TestAllTypes{
   368  			DefaultFloat: proto.Float32(91.6),
   369  		},
   370  		y:    &testpb.TestAllTypes{},
   371  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   372  		want: false,
   373  	}, {
   374  		x: &testpb.TestAllTypes{
   375  			OptionalForeignMessage: &testpb.ForeignMessage{},
   376  		},
   377  		y:    &testpb.TestAllTypes{},
   378  		opts: cmp.Options{Transform(), IgnoreDefaultScalars()},
   379  		want: false,
   380  	}}...)
   381  
   382  	// Test IgnoreEmptyMessages.
   383  	tests = append(tests, []test{{
   384  		x:    []*testpb.TestAllTypes{nil, {}, {OptionalInt32: proto.Int32(5)}},
   385  		y:    []*testpb.TestAllTypes{nil, {}, {OptionalInt32: proto.Int32(5)}},
   386  		opts: cmp.Options{Transform()},
   387  		want: true,
   388  	}, {
   389  		x:    []*testpb.TestAllTypes{nil, {}, {OptionalInt32: proto.Int32(5)}},
   390  		y:    []*testpb.TestAllTypes{{OptionalInt32: proto.Int32(5)}},
   391  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   392  		want: false,
   393  	}, {
   394  		x:    &testpb.TestAllTypes{OptionalForeignMessage: &testpb.ForeignMessage{}},
   395  		y:    &testpb.TestAllTypes{OptionalForeignMessage: nil},
   396  		opts: cmp.Options{Transform()},
   397  		want: false,
   398  	}, {
   399  		x:    &testpb.TestAllTypes{OptionalForeignMessage: &testpb.ForeignMessage{}},
   400  		y:    &testpb.TestAllTypes{OptionalForeignMessage: nil},
   401  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   402  		want: true,
   403  	}, {
   404  		x:    &testpb.TestAllTypes{OptionalForeignMessage: &testpb.ForeignMessage{C: proto.Int32(5)}},
   405  		y:    &testpb.TestAllTypes{OptionalForeignMessage: nil},
   406  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   407  		want: false,
   408  	}, {
   409  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{}},
   410  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: nil},
   411  		opts: cmp.Options{Transform()},
   412  		want: true,
   413  	}, {
   414  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {}}},
   415  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: nil},
   416  		opts: cmp.Options{Transform()},
   417  		want: false,
   418  	}, {
   419  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {}}},
   420  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: nil},
   421  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   422  		want: true,
   423  	}, {
   424  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(5)}, {}}},
   425  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: nil},
   426  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   427  		want: false,
   428  	}, {
   429  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(5)}, {}}},
   430  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {}, nil, {}, {C: proto.Int32(5)}, {}}},
   431  		opts: cmp.Options{Transform()},
   432  		want: false,
   433  	}, {
   434  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(5)}, {}}},
   435  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {}, nil, {}, {C: proto.Int32(5)}, {}}},
   436  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   437  		want: true,
   438  	}, {
   439  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{}},
   440  		y:    &testpb.TestAllTypes{MapStringNestedMessage: nil},
   441  		opts: cmp.Options{Transform()},
   442  		want: true,
   443  	}, {
   444  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": nil, "2": {}}},
   445  		y:    &testpb.TestAllTypes{MapStringNestedMessage: nil},
   446  		opts: cmp.Options{Transform()},
   447  		want: false,
   448  	}, {
   449  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": nil, "2": {}}},
   450  		y:    &testpb.TestAllTypes{MapStringNestedMessage: nil},
   451  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   452  		want: true,
   453  	}, {
   454  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": nil, "2": {A: proto.Int32(5)}, "3": {}}},
   455  		y:    &testpb.TestAllTypes{MapStringNestedMessage: nil},
   456  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   457  		want: false,
   458  	}, {
   459  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": nil, "2": {A: proto.Int32(5)}, "3": {}}},
   460  		y:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": {}, "1a": {}, "1b": nil, "2": {A: proto.Int32(5)}, "4": {}}},
   461  		opts: cmp.Options{Transform()},
   462  		want: false,
   463  	}, {
   464  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": nil, "2": {A: proto.Int32(5)}, "3": {}}},
   465  		y:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"1": {}, "1a": {}, "1b": nil, "2": {A: proto.Int32(5)}, "4": {}}},
   466  		opts: cmp.Options{Transform(), IgnoreEmptyMessages()},
   467  		want: true,
   468  	}}...)
   469  
   470  	// Test IgnoreEnums and IgnoreMessages.
   471  	tests = append(tests, []test{{
   472  		x: &testpb.TestAllTypes{
   473  			OptionalNestedMessage:  &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)},
   474  			RepeatedNestedMessage:  []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}},
   475  			MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"3": {A: proto.Int32(3)}},
   476  		},
   477  		y:    &testpb.TestAllTypes{},
   478  		opts: cmp.Options{Transform()},
   479  		want: false,
   480  	}, {
   481  		x: &testpb.TestAllTypes{
   482  			OptionalNestedMessage:  &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)},
   483  			RepeatedNestedMessage:  []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}},
   484  			MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"3": {A: proto.Int32(3)}},
   485  		},
   486  		y:    &testpb.TestAllTypes{},
   487  		opts: cmp.Options{Transform(), IgnoreMessages(&testpb.TestAllTypes{})},
   488  		want: true,
   489  	}, {
   490  		x: &testpb.TestAllTypes{
   491  			OptionalNestedEnum:  testpb.TestAllTypes_FOO.Enum(),
   492  			RepeatedNestedEnum:  []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR},
   493  			MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"baz": testpb.TestAllTypes_BAZ},
   494  		},
   495  		y:    &testpb.TestAllTypes{},
   496  		opts: cmp.Options{Transform()},
   497  		want: false,
   498  	}, {
   499  		x: &testpb.TestAllTypes{
   500  			OptionalNestedEnum:  testpb.TestAllTypes_FOO.Enum(),
   501  			RepeatedNestedEnum:  []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR},
   502  			MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"baz": testpb.TestAllTypes_BAZ},
   503  		},
   504  		y:    &testpb.TestAllTypes{},
   505  		opts: cmp.Options{Transform(), IgnoreEnums(testpb.TestAllTypes_NestedEnum(0))},
   506  		want: true,
   507  	}, {
   508  		x: &testpb.TestAllTypes{
   509  			OptionalNestedEnum:  testpb.TestAllTypes_FOO.Enum(),
   510  			RepeatedNestedEnum:  []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR},
   511  			MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"baz": testpb.TestAllTypes_BAZ},
   512  
   513  			OptionalNestedMessage:  &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)},
   514  			RepeatedNestedMessage:  []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}},
   515  			MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"3": {A: proto.Int32(3)}},
   516  		},
   517  		y: &testpb.TestAllTypes{},
   518  		opts: cmp.Options{Transform(),
   519  			IgnoreMessages(&testpb.TestAllExtensions{}),
   520  			IgnoreEnums(testpb.ForeignEnum(0)),
   521  		},
   522  		want: false,
   523  	}}...)
   524  
   525  	// Test IgnoreFields and IgnoreOneofs.
   526  	tests = append(tests, []test{{
   527  		x:    &testpb.TestAllTypes{OptionalInt32: proto.Int32(5)},
   528  		y:    &testpb.TestAllTypes{OptionalInt32: proto.Int32(6)},
   529  		opts: cmp.Options{Transform()},
   530  		want: false,
   531  	}, {
   532  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(5)},
   533  		y: &testpb.TestAllTypes{},
   534  		opts: cmp.Options{Transform(),
   535  			IgnoreFields(&testpb.TestAllTypes{}, "optional_int32")},
   536  		want: true,
   537  	}, {
   538  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(5)},
   539  		y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(6)},
   540  		opts: cmp.Options{Transform(),
   541  			IgnoreFields(&testpb.TestAllTypes{}, "optional_int32")},
   542  		want: true,
   543  	}, {
   544  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(5)},
   545  		y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(6)},
   546  		opts: cmp.Options{Transform(),
   547  			IgnoreFields(&testpb.TestAllTypes{}, "optional_int64")},
   548  		want: false,
   549  	}, {
   550  		x:    &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{5}},
   551  		y:    &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofString{"5"}},
   552  		opts: cmp.Options{Transform()},
   553  		want: false,
   554  	}, {
   555  		x: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{5}},
   556  		y: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofString{"5"}},
   557  		opts: cmp.Options{Transform(),
   558  			IgnoreFields(&testpb.TestAllTypes{}, "oneof_uint32"),
   559  			IgnoreFields(&testpb.TestAllTypes{}, "oneof_string")},
   560  		want: true,
   561  	}, {
   562  		x: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{5}},
   563  		y: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofString{"5"}},
   564  		opts: cmp.Options{Transform(),
   565  			IgnoreOneofs(&testpb.TestAllTypes{}, "oneof_field")},
   566  		want: true,
   567  	}, {
   568  		x: apply(new(testpb.TestAllExtensions),
   569  			setExtension{testpb.E_OptionalString, "hello"}),
   570  		y: apply(new(testpb.TestAllExtensions),
   571  			setExtension{testpb.E_OptionalString, "goodbye"}),
   572  		opts: cmp.Options{Transform()},
   573  		want: false,
   574  	}, {
   575  		x: apply(new(testpb.TestAllExtensions),
   576  			setExtension{testpb.E_OptionalString, "hello"}),
   577  		y: new(testpb.TestAllExtensions),
   578  		opts: cmp.Options{Transform(),
   579  			IgnoreDescriptors(testpb.E_OptionalString.TypeDescriptor())},
   580  		want: true,
   581  	}, {
   582  		x: apply(new(testpb.TestAllExtensions),
   583  			setExtension{testpb.E_OptionalString, "hello"}),
   584  		y: apply(new(testpb.TestAllExtensions),
   585  			setExtension{testpb.E_OptionalString, "goodbye"}),
   586  		opts: cmp.Options{Transform(),
   587  			IgnoreDescriptors(testpb.E_OptionalString.TypeDescriptor())},
   588  		want: true,
   589  	}, {
   590  		x: apply(new(testpb.TestAllExtensions),
   591  			setExtension{testpb.E_OptionalString, "hello"}),
   592  		y: apply(new(testpb.TestAllExtensions),
   593  			setExtension{testpb.E_OptionalString, "goodbye"}),
   594  		opts: cmp.Options{Transform(),
   595  			IgnoreDescriptors(testpb.E_OptionalInt32.TypeDescriptor())},
   596  		want: false,
   597  	}}...)
   598  
   599  	// Test FilterEnum.
   600  	tests = append(tests, []test{{
   601  		x:    &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
   602  		y:    &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
   603  		opts: cmp.Options{Transform()},
   604  		want: false,
   605  	}, {
   606  		x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
   607  		y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
   608  		opts: cmp.Options{
   609  			Transform(),
   610  			FilterEnum(testpb.ForeignEnum(0), cmp.Comparer(func(x, y interface{}) bool { return true })),
   611  		},
   612  		want: false, // mismatching filter type
   613  	}, {
   614  		x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
   615  		y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
   616  		opts: cmp.Options{
   617  			Transform(),
   618  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y int) bool { return true })),
   619  		},
   620  		want: false, // matching filter type, but mismatching comparer type
   621  	}, {
   622  		x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
   623  		y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
   624  		opts: cmp.Options{
   625  			Transform(),
   626  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y testpb.TestAllTypes_NestedEnum) bool { return true })),
   627  		},
   628  		want: false, // matching filter type, but mismatching comparer type
   629  	}, {
   630  		x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
   631  		y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
   632  		opts: cmp.Options{
   633  			Transform(),
   634  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y interface{}) bool { return true })),
   635  		},
   636  		want: true,
   637  	}, {
   638  		x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
   639  		y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
   640  		opts: cmp.Options{
   641  			Transform(),
   642  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y Enum) bool { return true })),
   643  		},
   644  		want: true,
   645  	}, {
   646  		x:    &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
   647  		y:    &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
   648  		opts: cmp.Options{Transform()},
   649  		want: false,
   650  	}, {
   651  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
   652  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
   653  		opts: cmp.Options{
   654  			Transform(),
   655  			FilterEnum(testpb.ForeignEnum(0), cmp.Comparer(func(x, y interface{}) bool { return true })),
   656  		},
   657  		want: false, // mismatching filter type
   658  	}, {
   659  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
   660  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
   661  		opts: cmp.Options{
   662  			Transform(),
   663  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y int) bool { return true })),
   664  		},
   665  		want: false, // matching filter type, but mismatching comparer type
   666  	}, {
   667  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
   668  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
   669  		opts: cmp.Options{
   670  			Transform(),
   671  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y []testpb.TestAllTypes_NestedEnum) bool { return true })),
   672  		},
   673  		want: false, // matching filter type, but mismatching comparer type
   674  	}, {
   675  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
   676  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
   677  		opts: cmp.Options{
   678  			Transform(),
   679  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y interface{}) bool { return true })),
   680  		},
   681  		want: true,
   682  	}, {
   683  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO}},
   684  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR}},
   685  		opts: cmp.Options{
   686  			Transform(),
   687  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y []Enum) bool { return true })),
   688  		},
   689  		want: true,
   690  	}, {
   691  		x:    &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_FOO}},
   692  		y:    &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_BAR}},
   693  		opts: cmp.Options{Transform()},
   694  		want: false,
   695  	}, {
   696  		x: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_FOO}},
   697  		y: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_BAR}},
   698  		opts: cmp.Options{
   699  			Transform(),
   700  			FilterEnum(testpb.ForeignEnum(0), cmp.Comparer(func(x, y interface{}) bool { return true })),
   701  		},
   702  		want: false, // mismatching filter type
   703  	}, {
   704  		x: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_FOO}},
   705  		y: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_BAR}},
   706  		opts: cmp.Options{
   707  			Transform(),
   708  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y int) bool { return true })),
   709  		},
   710  		want: false, // matching filter type, but mismatching comparer type
   711  	}, {
   712  		x: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_FOO}},
   713  		y: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_BAR}},
   714  		opts: cmp.Options{
   715  			Transform(),
   716  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y map[string]testpb.TestAllTypes_NestedEnum) bool { return true })),
   717  		},
   718  		want: false, // matching filter type, but mismatching comparer type
   719  	}, {
   720  		x: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_FOO}},
   721  		y: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_BAR}},
   722  		opts: cmp.Options{
   723  			Transform(),
   724  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y interface{}) bool { return true })),
   725  		},
   726  		want: true,
   727  	}, {
   728  		x: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_FOO}},
   729  		y: &testpb.TestAllTypes{MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{"k": testpb.TestAllTypes_BAR}},
   730  		opts: cmp.Options{
   731  			Transform(),
   732  			FilterEnum(testpb.TestAllTypes_NestedEnum(0), cmp.Comparer(func(x, y map[string]Enum) bool { return true })),
   733  		},
   734  		want: true,
   735  	}}...)
   736  
   737  	// Test FilterMessage.
   738  	tests = append(tests, []test{{
   739  		x:    &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)}},
   740  		y:    &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(2)}},
   741  		opts: cmp.Options{Transform()},
   742  		want: false,
   743  	}, {
   744  		x: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)}},
   745  		y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(2)}},
   746  		opts: cmp.Options{
   747  			Transform(),
   748  			FilterMessage(new(testpb.TestAllExtensions), cmp.Comparer(func(x, y interface{}) bool { return true })),
   749  		},
   750  		want: false, // mismatching filter type
   751  	}, {
   752  		x: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)}},
   753  		y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(2)}},
   754  		opts: cmp.Options{
   755  			Transform(),
   756  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y int) bool { return true })),
   757  		},
   758  		want: false, // matching filter type, but mismatching comparer type
   759  	}, {
   760  		x: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)}},
   761  		y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(2)}},
   762  		opts: cmp.Options{
   763  			Transform(),
   764  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y *testpb.TestAllTypes_NestedMessage) bool { return true })),
   765  		},
   766  		want: false, // matching filter type, but mismatching comparer type
   767  	}, {
   768  		x: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)}},
   769  		y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(2)}},
   770  		opts: cmp.Options{
   771  			Transform(),
   772  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y interface{}) bool { return true })),
   773  		},
   774  		want: true,
   775  	}, {
   776  		x: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(1)}},
   777  		y: &testpb.TestAllTypes{OptionalNestedMessage: &testpb.TestAllTypes_NestedMessage{A: proto.Int32(2)}},
   778  		opts: cmp.Options{
   779  			Transform(),
   780  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y Message) bool { return true })),
   781  		},
   782  		want: true,
   783  	}, {
   784  		x:    &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(1)}}},
   785  		y:    &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}}},
   786  		opts: cmp.Options{Transform()},
   787  		want: false,
   788  	}, {
   789  		x: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(1)}}},
   790  		y: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}}},
   791  		opts: cmp.Options{
   792  			Transform(),
   793  			FilterMessage(new(testpb.TestAllExtensions), cmp.Comparer(func(x, y interface{}) bool { return true })),
   794  		},
   795  		want: false, // mismatching filter type
   796  	}, {
   797  		x: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(1)}}},
   798  		y: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}}},
   799  		opts: cmp.Options{
   800  			Transform(),
   801  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y int) bool { return true })),
   802  		},
   803  		want: false, // matching filter type, but mismatching comparer type
   804  	}, {
   805  		x: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(1)}}},
   806  		y: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}}},
   807  		opts: cmp.Options{
   808  			Transform(),
   809  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y []*testpb.TestAllTypes_NestedMessage) bool { return true })),
   810  		},
   811  		want: false, // matching filter type, but mismatching comparer type
   812  	}, {
   813  		x: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(1)}}},
   814  		y: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}}},
   815  		opts: cmp.Options{
   816  			Transform(),
   817  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y interface{}) bool { return true })),
   818  		},
   819  		want: true,
   820  	}, {
   821  		x: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(1)}}},
   822  		y: &testpb.TestAllTypes{RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{{A: proto.Int32(2)}}},
   823  		opts: cmp.Options{
   824  			Transform(),
   825  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y []Message) bool { return true })),
   826  		},
   827  		want: true,
   828  	}, {
   829  		x:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(1)}}},
   830  		y:    &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(2)}}},
   831  		opts: cmp.Options{Transform()},
   832  		want: false,
   833  	}, {
   834  		x: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(1)}}},
   835  		y: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(2)}}},
   836  		opts: cmp.Options{
   837  			Transform(),
   838  			FilterMessage(new(testpb.TestAllExtensions), cmp.Comparer(func(x, y interface{}) bool { return true })),
   839  		},
   840  		want: false, // mismatching filter type
   841  	}, {
   842  		x: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(1)}}},
   843  		y: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(2)}}},
   844  		opts: cmp.Options{
   845  			Transform(),
   846  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y int) bool { return true })),
   847  		},
   848  		want: false, // matching filter type, but mismatching comparer type
   849  	}, {
   850  		x: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(1)}}},
   851  		y: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(2)}}},
   852  		opts: cmp.Options{
   853  			Transform(),
   854  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y map[string]*testpb.TestAllTypes_NestedMessage) bool { return true })),
   855  		},
   856  		want: false, // matching filter type, but mismatching comparer type
   857  	}, {
   858  		x: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(1)}}},
   859  		y: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(2)}}},
   860  		opts: cmp.Options{
   861  			Transform(),
   862  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y interface{}) bool { return true })),
   863  		},
   864  		want: true,
   865  	}, {
   866  		x: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(1)}}},
   867  		y: &testpb.TestAllTypes{MapStringNestedMessage: map[string]*testpb.TestAllTypes_NestedMessage{"k": {A: proto.Int32(2)}}},
   868  		opts: cmp.Options{
   869  			Transform(),
   870  			FilterMessage(new(testpb.TestAllTypes_NestedMessage), cmp.Comparer(func(x, y map[string]Message) bool { return true })),
   871  		},
   872  		want: true,
   873  	}}...)
   874  
   875  	// Test FilterField.
   876  	tests = append(tests, []test{{
   877  		x:    &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
   878  		y:    &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
   879  		opts: cmp.Options{Transform()},
   880  		want: false,
   881  	}, {
   882  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
   883  		y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
   884  		opts: cmp.Options{
   885  			Transform(),
   886  			FilterField(new(testpb.TestAllTypes), "optional_int64", cmp.Comparer(func(x, y interface{}) bool { return true })),
   887  		},
   888  		want: false, // mismatching filter name
   889  	}, {
   890  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
   891  		y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
   892  		opts: cmp.Options{
   893  			Transform(),
   894  			FilterField(new(testpb.TestAllTypes), "optional_int32", cmp.Comparer(func(x, y int64) bool { return true })),
   895  		},
   896  		want: false, // matching filter name, but mismatching comparer type
   897  	}, {
   898  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
   899  		y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
   900  		opts: cmp.Options{
   901  			Transform(),
   902  			FilterField(new(testpb.TestAllTypes), "optional_int32", cmp.Comparer(func(x, y interface{}) bool { return true })),
   903  		},
   904  		want: true,
   905  	}, {
   906  		x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(1)},
   907  		y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
   908  		opts: cmp.Options{
   909  			Transform(),
   910  			FilterField(new(testpb.TestAllTypes), "optional_int32", cmp.Comparer(func(x, y int32) bool { return true })),
   911  		},
   912  		want: true,
   913  	}, {
   914  		x:    &testpb.TestAllTypes{RepeatedInt32: []int32{1}},
   915  		y:    &testpb.TestAllTypes{RepeatedInt32: []int32{2}},
   916  		opts: cmp.Options{Transform()},
   917  		want: false,
   918  	}, {
   919  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{1}},
   920  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2}},
   921  		opts: cmp.Options{
   922  			Transform(),
   923  			FilterField(new(testpb.TestAllTypes), "repeated_int64", cmp.Comparer(func(x, y interface{}) bool { return true })),
   924  		},
   925  		want: false, // mismatching filter name
   926  	}, {
   927  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{1}},
   928  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2}},
   929  		opts: cmp.Options{
   930  			Transform(),
   931  			FilterField(new(testpb.TestAllTypes), "repeated_int32", cmp.Comparer(func(x, y []int64) bool { return true })),
   932  		},
   933  		want: false, // matching filter name, but mismatching comparer type
   934  	}, {
   935  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{1}},
   936  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2}},
   937  		opts: cmp.Options{
   938  			Transform(),
   939  			FilterField(new(testpb.TestAllTypes), "repeated_int32", cmp.Comparer(func(x, y interface{}) bool { return true })),
   940  		},
   941  		want: true,
   942  	}, {
   943  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{1}},
   944  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2}},
   945  		opts: cmp.Options{
   946  			Transform(),
   947  			FilterField(new(testpb.TestAllTypes), "repeated_int32", cmp.Comparer(func(x, y []int32) bool { return true })),
   948  		},
   949  		want: true,
   950  	}, {
   951  		x:    &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 1}},
   952  		y:    &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{2: 2}},
   953  		opts: cmp.Options{Transform()},
   954  		want: false,
   955  	}, {
   956  		x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 1}},
   957  		y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{2: 2}},
   958  		opts: cmp.Options{
   959  			Transform(),
   960  			FilterField(new(testpb.TestAllTypes), "map_int64_int64", cmp.Comparer(func(x, y interface{}) bool { return true })),
   961  		},
   962  		want: false, // mismatching filter name
   963  	}, {
   964  		x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 1}},
   965  		y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{2: 2}},
   966  		opts: cmp.Options{
   967  			Transform(),
   968  			FilterField(new(testpb.TestAllTypes), "map_int32_int32", cmp.Comparer(func(x, y map[int64]int64) bool { return true })),
   969  		},
   970  		want: false, // matching filter name, but mismatching comparer type
   971  	}, {
   972  		x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 1}},
   973  		y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{2: 2}},
   974  		opts: cmp.Options{
   975  			Transform(),
   976  			FilterField(new(testpb.TestAllTypes), "map_int32_int32", cmp.Comparer(func(x, y interface{}) bool { return true })),
   977  		},
   978  		want: true,
   979  	}, {
   980  		x: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{1: 1}},
   981  		y: &testpb.TestAllTypes{MapInt32Int32: map[int32]int32{2: 2}},
   982  		opts: cmp.Options{
   983  			Transform(),
   984  			FilterField(new(testpb.TestAllTypes), "map_int32_int32", cmp.Comparer(func(x, y map[int32]int32) bool { return true })),
   985  		},
   986  		want: true,
   987  	}}...)
   988  
   989  	// Test FilterOneof
   990  	tests = append(tests, []test{{
   991  		x:    &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{1}},
   992  		y:    &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{2}},
   993  		opts: cmp.Options{Transform()},
   994  		want: false,
   995  	}, {
   996  		x: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{1}},
   997  		y: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{2}},
   998  		opts: cmp.Options{
   999  			Transform(),
  1000  			FilterOneof(new(testpb.TestAllTypes), "oneof_optional", cmp.Comparer(func(x, y interface{}) bool { return true })),
  1001  		},
  1002  		want: false, // mismatching filter name
  1003  	}, {
  1004  		x: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{1}},
  1005  		y: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{2}},
  1006  		opts: cmp.Options{
  1007  			Transform(),
  1008  			FilterOneof(new(testpb.TestAllTypes), "oneof_field", cmp.Comparer(func(x, y string) bool { return true })),
  1009  		},
  1010  		want: false, // matching filter name, but mismatching comparer type
  1011  	}, {
  1012  		x: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{1}},
  1013  		y: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{2}},
  1014  		opts: cmp.Options{
  1015  			Transform(),
  1016  			FilterOneof(new(testpb.TestAllTypes), "oneof_field", cmp.Comparer(func(x, y uint32) bool { return true })),
  1017  		},
  1018  		want: true,
  1019  	}, {
  1020  		x: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{1}},
  1021  		y: &testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint32{2}},
  1022  		opts: cmp.Options{
  1023  			Transform(),
  1024  			FilterOneof(new(testpb.TestAllTypes), "oneof_field", cmp.Comparer(func(x, y interface{}) bool { return true })),
  1025  		},
  1026  		want: true,
  1027  	}}...)
  1028  
  1029  	// Test SortRepeated.
  1030  	type higherOrderType struct {
  1031  		M    *testpb.TestAllTypes
  1032  		I32s []int32
  1033  		Es   []testpb.TestAllTypes_NestedEnum
  1034  		Ms   []*testpb.ForeignMessage
  1035  	}
  1036  	tests = append(tests, []test{{
  1037  		x:    &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1038  		y:    &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1039  		opts: cmp.Options{Transform()},
  1040  		want: false,
  1041  	}, {
  1042  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1043  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1044  		opts: cmp.Options{
  1045  			Transform(),
  1046  			SortRepeated(func(x, y int32) bool { return x < y }),
  1047  		},
  1048  		want: true,
  1049  	}, {
  1050  		x: higherOrderType{
  1051  			M:    &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1052  			I32s: []int32{3, 2, 1, 2, 3, 3},
  1053  		},
  1054  		y: higherOrderType{
  1055  			M:    &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1056  			I32s: []int32{2, 3, 3, 2, 1, 3},
  1057  		},
  1058  		opts: cmp.Options{
  1059  			Transform(),
  1060  			SortRepeated(func(x, y int32) bool { return x < y }),
  1061  		},
  1062  		want: false, // sort does not apply to []int32 outside of a message
  1063  	}, {
  1064  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1065  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1066  		opts: cmp.Options{
  1067  			Transform(),
  1068  			SortRepeated(func(x, y int64) bool { return x < y }),
  1069  		},
  1070  		want: false, // wrong sort type: int32 != int64
  1071  	}, {
  1072  		x:    &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1073  		y:    &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1074  		opts: cmp.Options{Transform()},
  1075  		want: false,
  1076  	}, {
  1077  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1078  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1079  		opts: cmp.Options{
  1080  			Transform(),
  1081  			SortRepeated(func(x, y testpb.TestAllTypes_NestedEnum) bool { return x < y }),
  1082  		},
  1083  		want: true,
  1084  	}, {
  1085  		x: higherOrderType{
  1086  			M:  &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1087  			Es: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ},
  1088  		},
  1089  		y: higherOrderType{
  1090  			M:  &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1091  			Es: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ},
  1092  		},
  1093  		opts: cmp.Options{
  1094  			Transform(),
  1095  			SortRepeated(func(x, y testpb.TestAllTypes_NestedEnum) bool { return x < y }),
  1096  		},
  1097  		want: false, // sort does not apply to []testpb.TestAllTypes_NestedEnum outside of a message
  1098  	}, {
  1099  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1100  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1101  		opts: cmp.Options{
  1102  			Transform(),
  1103  			SortRepeated(func(x, y testpb.ForeignEnum) bool { return x < y }),
  1104  		},
  1105  		want: false, // wrong sort type: testpb.TestAllTypes_NestedEnum != testpb.ForeignEnum
  1106  	}, {
  1107  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1108  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1109  		opts: cmp.Options{Transform()},
  1110  		want: false,
  1111  	}, {
  1112  		x: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1113  		y: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1114  		opts: cmp.Options{
  1115  			Transform(),
  1116  			SortRepeated(func(x, y *testpb.ForeignMessage) bool { return x.GetC() < y.GetC() }),
  1117  		},
  1118  		want: true,
  1119  	}, {
  1120  		x: higherOrderType{
  1121  			M:  &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1122  			Ms: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}},
  1123  		},
  1124  		y: higherOrderType{
  1125  			M:  &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1126  			Ms: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}},
  1127  		},
  1128  		opts: cmp.Options{
  1129  			Transform(),
  1130  			SortRepeated(func(x, y *testpb.ForeignMessage) bool { return x.GetC() < y.GetC() }),
  1131  		},
  1132  		want: false, // sort does not apply to []*testpb.ForeignMessage outside of a message
  1133  	}, {
  1134  		x: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1135  		y: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1136  		opts: cmp.Options{
  1137  			Transform(),
  1138  			SortRepeated(func(x, y *testpb.TestAllTypes_NestedMessage) bool { return x.GetA() < y.GetA() }),
  1139  		},
  1140  		want: false, // wrong sort type: *testpb.ForeignMessage != *testpb.TestAllTypes_NestedMessage
  1141  	}, {
  1142  		x: &testpb.TestAllTypes{
  1143  			RepeatedInt32:    []int32{-32, +32},
  1144  			RepeatedSint32:   []int32{-32, +32},
  1145  			RepeatedSfixed32: []int32{-32, +32},
  1146  			RepeatedInt64:    []int64{-64, +64},
  1147  			RepeatedSint64:   []int64{-64, +64},
  1148  			RepeatedSfixed64: []int64{-64, +64},
  1149  			RepeatedUint32:   []uint32{0, 32},
  1150  			RepeatedFixed32:  []uint32{0, 32},
  1151  			RepeatedUint64:   []uint64{0, 64},
  1152  			RepeatedFixed64:  []uint64{0, 64},
  1153  		},
  1154  		y: &testpb.TestAllTypes{
  1155  			RepeatedInt32:    []int32{+32, -32},
  1156  			RepeatedSint32:   []int32{+32, -32},
  1157  			RepeatedSfixed32: []int32{+32, -32},
  1158  			RepeatedInt64:    []int64{+64, -64},
  1159  			RepeatedSint64:   []int64{+64, -64},
  1160  			RepeatedSfixed64: []int64{+64, -64},
  1161  			RepeatedUint32:   []uint32{32, 0},
  1162  			RepeatedFixed32:  []uint32{32, 0},
  1163  			RepeatedUint64:   []uint64{64, 0},
  1164  			RepeatedFixed64:  []uint64{64, 0},
  1165  		},
  1166  		opts: cmp.Options{
  1167  			Transform(),
  1168  			SortRepeated(func(x, y int32) bool { return x < y }),
  1169  			SortRepeated(func(x, y int64) bool { return x < y }),
  1170  			SortRepeated(func(x, y uint32) bool { return x < y }),
  1171  			SortRepeated(func(x, y uint64) bool { return x < y }),
  1172  		},
  1173  		want: true,
  1174  	}}...)
  1175  
  1176  	// Test SortRepeatedFields.
  1177  	tests = append(tests, []test{{
  1178  		x:    &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1179  		y:    &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1180  		opts: cmp.Options{Transform()},
  1181  		want: false,
  1182  	}, {
  1183  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1184  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1185  		opts: cmp.Options{
  1186  			Transform(),
  1187  			SortRepeatedFields(new(testpb.TestAllTypes), "repeated_int32"),
  1188  		},
  1189  		want: true,
  1190  	}, {
  1191  		x: &testpb.TestAllTypes{RepeatedInt32: []int32{3, 2, 1, 2, 3, 3}},
  1192  		y: &testpb.TestAllTypes{RepeatedInt32: []int32{2, 3, 3, 2, 1, 3}},
  1193  		opts: cmp.Options{
  1194  			Transform(),
  1195  			SortRepeatedFields(new(testpb.TestAllTypes), "repeated_int64"),
  1196  		},
  1197  		want: false, // wrong field: repeated_int32 != repeated_int64
  1198  	}, {
  1199  		x:    &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1200  		y:    &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1201  		opts: cmp.Options{Transform()},
  1202  		want: false,
  1203  	}, {
  1204  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1205  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1206  		opts: cmp.Options{
  1207  			Transform(),
  1208  			SortRepeatedFields(new(testpb.TestAllTypes), "repeated_nested_enum"),
  1209  		},
  1210  		want: true,
  1211  	}, {
  1212  		x: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAR, testpb.TestAllTypes_BAZ}},
  1213  		y: &testpb.TestAllTypes{RepeatedNestedEnum: []testpb.TestAllTypes_NestedEnum{testpb.TestAllTypes_BAR, testpb.TestAllTypes_FOO, testpb.TestAllTypes_BAZ}},
  1214  		opts: cmp.Options{
  1215  			Transform(),
  1216  			SortRepeatedFields(new(testpb.TestAllTypes), "repeated_foreign_enum"),
  1217  		},
  1218  		want: false, // wrong field: repeated_nested_enum != repeated_foreign_enum
  1219  	}, {
  1220  		x:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1221  		y:    &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1222  		opts: cmp.Options{Transform()},
  1223  		want: false,
  1224  	}, {
  1225  		x: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1226  		y: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1227  		opts: cmp.Options{
  1228  			Transform(),
  1229  			SortRepeatedFields(new(testpb.TestAllTypes), "repeated_foreign_message"),
  1230  		},
  1231  		want: true,
  1232  	}, {
  1233  		x: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{{}, {C: proto.Int32(3)}, nil, {C: proto.Int32(3)}, {C: proto.Int32(5)}, {C: proto.Int32(4)}}},
  1234  		y: &testpb.TestAllTypes{RepeatedForeignMessage: []*testpb.ForeignMessage{nil, {C: proto.Int32(3)}, {}, {C: proto.Int32(4)}, {C: proto.Int32(3)}, {C: proto.Int32(5)}}},
  1235  		opts: cmp.Options{
  1236  			Transform(),
  1237  			SortRepeatedFields(new(testpb.TestAllTypes), "repeated_nested_message"),
  1238  		},
  1239  		want: false, // wrong field: repeated_foreign_message != repeated_nested_message
  1240  	}, {
  1241  		x: &testpb.TestAllTypes{
  1242  			RepeatedBool:           []bool{false, true},
  1243  			RepeatedInt32:          []int32{-32, +32},
  1244  			RepeatedInt64:          []int64{-64, +64},
  1245  			RepeatedUint32:         []uint32{0, 32},
  1246  			RepeatedUint64:         []uint64{0, 64},
  1247  			RepeatedFloat:          []float32{-32.32, +32.32},
  1248  			RepeatedDouble:         []float64{-64.64, +64.64},
  1249  			RepeatedString:         []string{"hello", "world"},
  1250  			RepeatedBytes:          [][]byte{[]byte("hello"), []byte("world")},
  1251  			RepeatedForeignEnum:    []testpb.ForeignEnum{testpb.ForeignEnum_FOREIGN_FOO, testpb.ForeignEnum_FOREIGN_BAR},
  1252  			RepeatedForeignMessage: []*testpb.ForeignMessage{{C: proto.Int32(-1)}, {C: proto.Int32(+1)}},
  1253  		},
  1254  		y: &testpb.TestAllTypes{
  1255  			RepeatedBool:           []bool{true, false},
  1256  			RepeatedInt32:          []int32{+32, -32},
  1257  			RepeatedInt64:          []int64{+64, -64},
  1258  			RepeatedUint32:         []uint32{32, 0},
  1259  			RepeatedUint64:         []uint64{64, 0},
  1260  			RepeatedFloat:          []float32{+32.32, -32.32},
  1261  			RepeatedDouble:         []float64{+64.64, -64.64},
  1262  			RepeatedString:         []string{"world", "hello"},
  1263  			RepeatedBytes:          [][]byte{[]byte("world"), []byte("hello")},
  1264  			RepeatedForeignEnum:    []testpb.ForeignEnum{testpb.ForeignEnum_FOREIGN_BAR, testpb.ForeignEnum_FOREIGN_FOO},
  1265  			RepeatedForeignMessage: []*testpb.ForeignMessage{{C: proto.Int32(+1)}, {C: proto.Int32(-1)}},
  1266  		},
  1267  		opts: cmp.Options{
  1268  			Transform(),
  1269  			SortRepeatedFields(new(testpb.TestAllTypes),
  1270  				"repeated_bool",
  1271  				"repeated_int32",
  1272  				"repeated_int64",
  1273  				"repeated_uint32",
  1274  				"repeated_uint64",
  1275  				"repeated_float",
  1276  				"repeated_double",
  1277  				"repeated_string",
  1278  				"repeated_bytes",
  1279  				"repeated_foreign_enum",
  1280  				"repeated_foreign_message",
  1281  			),
  1282  		},
  1283  		want: true,
  1284  	}}...)
  1285  
  1286  	for _, tt := range tests {
  1287  		t.Run("", func(t *testing.T) {
  1288  			got := cmp.Equal(tt.x, tt.y, tt.opts)
  1289  			if got != tt.want {
  1290  				if !got {
  1291  					t.Errorf("cmp.Equal = false, want true; diff:\n%v", cmp.Diff(tt.x, tt.y, tt.opts))
  1292  				} else {
  1293  					t.Errorf("cmp.Equal = true, want false")
  1294  				}
  1295  			}
  1296  		})
  1297  	}
  1298  }
  1299  
  1300  type setField struct {
  1301  	num protoreflect.FieldNumber
  1302  	val interface{}
  1303  }
  1304  type setUnknown struct {
  1305  	raw protoreflect.RawFields
  1306  }
  1307  type setExtension struct {
  1308  	typ protoreflect.ExtensionType
  1309  	val interface{}
  1310  }
  1311  
  1312  // apply applies a sequence of mutating operations to m.
  1313  func apply(m proto.Message, ops ...interface{}) proto.Message {
  1314  	mr := m.ProtoReflect()
  1315  	md := mr.Descriptor()
  1316  	for _, op := range ops {
  1317  		switch op := op.(type) {
  1318  		case setField:
  1319  			fd := md.Fields().ByNumber(op.num)
  1320  			mr.Set(fd, protoreflect.ValueOf(op.val))
  1321  		case setUnknown:
  1322  			mr.SetUnknown(op.raw)
  1323  		case setExtension:
  1324  			mr.Set(op.typ.TypeDescriptor(), protoreflect.ValueOf(op.val))
  1325  		}
  1326  	}
  1327  	return m
  1328  }
  1329  
  1330  func TestSort(t *testing.T) {
  1331  	t.Run("F32", func(t *testing.T) {
  1332  		want := []float32{
  1333  			float32(math.Float32frombits(0xffc00000)), // -NaN
  1334  			float32(math.Inf(-1)),
  1335  			float32(-math.MaxFloat32),
  1336  			float32(-123.456),
  1337  			float32(-math.SmallestNonzeroFloat32),
  1338  			float32(math.Copysign(0, -1)),
  1339  			float32(math.Copysign(0, +1)),
  1340  			float32(+math.SmallestNonzeroFloat32),
  1341  			float32(+123.456),
  1342  			float32(+math.MaxFloat32),
  1343  			float32(math.Inf(+1)),
  1344  			float32(math.Float32frombits(0x7fc00000)), // +NaN
  1345  		}
  1346  		for i := 0; i < 10; i++ {
  1347  			t.Run("", func(t *testing.T) {
  1348  				got := append([]float32(nil), want...)
  1349  				rn := rand.New(rand.NewSource(int64(i)))
  1350  				for i, j := range rn.Perm(len(got)) {
  1351  					got[i], got[j] = got[j], got[i]
  1352  				}
  1353  				sort.Slice(got, func(i, j int) bool {
  1354  					return lessF32(got[i], got[j])
  1355  				})
  1356  				cmpF32s := cmp.Comparer(func(x, y float32) bool {
  1357  					return math.Float32bits(x) == math.Float32bits(y)
  1358  				})
  1359  				if diff := cmp.Diff(want, got, cmpF32s); diff != "" {
  1360  					t.Errorf("Sort mismatch (-want +got):\n%s", diff)
  1361  				}
  1362  			})
  1363  		}
  1364  	})
  1365  	t.Run("F64", func(t *testing.T) {
  1366  		want := []float64{
  1367  			float64(math.Float64frombits(0xfff8000000000001)), // -NaN
  1368  			float64(math.Inf(-1)),
  1369  			float64(-math.MaxFloat64),
  1370  			float64(-123.456),
  1371  			float64(-math.SmallestNonzeroFloat64),
  1372  			float64(math.Copysign(0, -1)),
  1373  			float64(math.Copysign(0, +1)),
  1374  			float64(+math.SmallestNonzeroFloat64),
  1375  			float64(+123.456),
  1376  			float64(+math.MaxFloat64),
  1377  			float64(math.Inf(+1)),
  1378  			float64(math.Float64frombits(0x7ff8000000000001)), // +NaN
  1379  		}
  1380  		for i := 0; i < 10; i++ {
  1381  			t.Run("", func(t *testing.T) {
  1382  				got := append([]float64(nil), want...)
  1383  				rn := rand.New(rand.NewSource(int64(i)))
  1384  				for i, j := range rn.Perm(len(got)) {
  1385  					got[i], got[j] = got[j], got[i]
  1386  				}
  1387  				sort.Slice(got, func(i, j int) bool {
  1388  					return lessF64(got[i], got[j])
  1389  				})
  1390  				cmpF64s := cmp.Comparer(func(x, y float64) bool {
  1391  					return math.Float64bits(x) == math.Float64bits(y)
  1392  				})
  1393  				if diff := cmp.Diff(want, got, cmpF64s); diff != "" {
  1394  					t.Errorf("Sort mismatch (-want +got):\n%s", diff)
  1395  				}
  1396  			})
  1397  		}
  1398  	})
  1399  }
  1400  

View as plain text