@@ -75,6 +75,48 @@ func ObjectsAreEqual(expected, actual interface{}) bool {
75
75
return bytes .Equal (exp , act )
76
76
}
77
77
78
+ // ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two structs are considered equal.
79
+ // If the two objects are not of the same type, or if either of them are not a struct, they are not considered equal.
80
+ //
81
+ // This function does no assertion of any kind.
82
+ func ObjectsExportedFieldsAreEqual (expected , actual interface {}) bool {
83
+ if expected == nil || actual == nil {
84
+ return expected == actual
85
+ }
86
+
87
+ expectedType := reflect .TypeOf (expected )
88
+ actualType := reflect .TypeOf (actual )
89
+
90
+ if expectedType != actualType {
91
+ return false
92
+ }
93
+
94
+ if expectedType .Kind () != reflect .Struct || actualType .Kind () != reflect .Struct {
95
+ return false
96
+ }
97
+
98
+ expectedValue := reflect .ValueOf (expected )
99
+ actualValue := reflect .ValueOf (actual )
100
+
101
+ for i := 0 ; i < expectedType .NumField (); i ++ {
102
+ field := expectedType .Field (i )
103
+ isExported := field .PkgPath == "" // should use field.IsExported() but it's not available in Go 1.16.5
104
+ if isExported {
105
+ var equal bool
106
+ if field .Type .Kind () == reflect .Struct {
107
+ equal = ObjectsExportedFieldsAreEqual (expectedValue .Field (i ).Interface (), actualValue .Field (i ).Interface ())
108
+ } else {
109
+ equal = ObjectsAreEqualValues (expectedValue .Field (i ).Interface (), actualValue .Field (i ).Interface ())
110
+ }
111
+
112
+ if ! equal {
113
+ return false
114
+ }
115
+ }
116
+ }
117
+ return true
118
+ }
119
+
78
120
// ObjectsAreEqualValues gets whether two objects are equal, or if their
79
121
// values are equal.
80
122
func ObjectsAreEqualValues (expected , actual interface {}) bool {
@@ -473,6 +515,47 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa
473
515
474
516
}
475
517
518
+ // EqualExportedValues asserts that the types of two objects are equal and their public
519
+ // fields are also equal. This is useful for comparing structs that have private fields
520
+ // that could potentially differ.
521
+ //
522
+ // type S struct {
523
+ // Exported int
524
+ // notExported int
525
+ // }
526
+ // assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
527
+ // assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
528
+ func EqualExportedValues (t TestingT , expected , actual interface {}, msgAndArgs ... interface {}) bool {
529
+ if h , ok := t .(tHelper ); ok {
530
+ h .Helper ()
531
+ }
532
+
533
+ aType := reflect .TypeOf (expected )
534
+ bType := reflect .TypeOf (actual )
535
+
536
+ if aType != bType {
537
+ return Fail (t , fmt .Sprintf ("Types expected to match exactly\n \t %v != %v" , aType , bType ), msgAndArgs ... )
538
+ }
539
+
540
+ if aType .Kind () != reflect .Struct {
541
+ return Fail (t , fmt .Sprintf ("Types expected to both be struct \n \t %v != %v" , aType .Kind (), reflect .Struct ), msgAndArgs ... )
542
+ }
543
+
544
+ if bType .Kind () != reflect .Struct {
545
+ return Fail (t , fmt .Sprintf ("Types expected to both be struct \n \t %v != %v" , bType .Kind (), reflect .Struct ), msgAndArgs ... )
546
+ }
547
+
548
+ if ! ObjectsExportedFieldsAreEqual (expected , actual ) {
549
+ diff := diff (expected , actual )
550
+ expected , actual = formatUnequalValues (expected , actual )
551
+ return Fail (t , fmt .Sprintf ("Not equal (comparing only exported fields): \n " +
552
+ "expected: %s\n " +
553
+ "actual : %s%s" , expected , actual , diff ), msgAndArgs ... )
554
+ }
555
+
556
+ return true
557
+ }
558
+
476
559
// Exactly asserts that two objects are equal in value and type.
477
560
//
478
561
// assert.Exactly(t, int32(123), int64(123))
0 commit comments