diff --git a/testing/protocmp/xform.go b/testing/protocmp/xform.go index d69bfb8d..5a47d0f8 100644 --- a/testing/protocmp/xform.go +++ b/testing/protocmp/xform.go @@ -296,6 +296,14 @@ func transformSingular(fd protoreflect.FieldDescriptor, v protoreflect.Value) in return Enum{num: v.Enum(), ed: fd.Enum()} case protoreflect.MessageKind, protoreflect.GroupKind: return transformMessage(v.Message()) + case protoreflect.BytesKind: + // The protoreflect API does not specify whether an empty bytes is + // guaranteed to be nil or not. Always return non-nil bytes to avoid + // leaking information about the concrete proto.Message implementation. + if len(v.Bytes()) == 0 { + return []byte{} + } + return v.Bytes() default: return v.Interface() } diff --git a/testing/protocmp/xform_test.go b/testing/protocmp/xform_test.go index 7fc3f687..c6355d7f 100644 --- a/testing/protocmp/xform_test.go +++ b/testing/protocmp/xform_test.go @@ -102,8 +102,8 @@ func TestTransform(t *testing.T) { MapUint64Uint64: map[uint64]uint64{0: 64}, MapInt32Float: map[int32]float32{32: 32.32}, MapInt32Double: map[int32]float64{64: 64.64}, - MapStringString: map[string]string{"k": "v"}, - MapStringBytes: map[string][]byte{"k": []byte("v")}, + MapStringString: map[string]string{"k": "v", "empty": ""}, + MapStringBytes: map[string][]byte{"k": []byte("v"), "empty": nil}, MapStringNestedEnum: map[string]testpb.TestAllTypes_NestedEnum{ "k": testpb.TestAllTypes_FOO, }, @@ -120,8 +120,8 @@ func TestTransform(t *testing.T) { "map_uint64_uint64": map[uint64]uint64{0: 64}, "map_int32_float": map[int32]float32{32: 32.32}, "map_int32_double": map[int32]float64{64: 64.64}, - "map_string_string": map[string]string{"k": "v"}, - "map_string_bytes": map[string][]byte{"k": []byte("v")}, + "map_string_string": map[string]string{"k": "v", "empty": ""}, + "map_string_bytes": map[string][]byte{"k": []byte("v"), "empty": []byte{}}, "map_string_nested_enum": map[string]Enum{ "k": enumOf(testpb.TestAllTypes_FOO), },