all: make error messages unstable
Use internal/detrand in the construction of our error messages.
This alters whether there is one or two spaces following the "proto:" prefix.
While it is easy for users to still work around this mutation,
sit at least forces them to write test infrastructure to more fuzzily
match on error strings.
Change-Id: I4ddca717526ee3fc4dbb1e0b36cfca8c6e0df36d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/194038
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/cmd/pbdump/pbdump.go b/internal/cmd/pbdump/pbdump.go
index 71912b1..62e3a27 100644
--- a/internal/cmd/pbdump/pbdump.go
+++ b/internal/cmd/pbdump/pbdump.go
@@ -19,6 +19,7 @@
"google.golang.org/protobuf/internal/encoding/pack"
"google.golang.org/protobuf/internal/encoding/wire"
+ "google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
@@ -174,7 +175,7 @@
n, _ := strconv.ParseInt(s[:i], 10, 32)
num := wire.Number(n)
if num < wire.MinValidNumber || wire.MaxValidNumber < num {
- return fmt.Errorf("invalid field: %v", prefix)
+ return errors.New("invalid field: %v", prefix)
}
s = strings.TrimPrefix(s[i:], ".")
@@ -184,7 +185,7 @@
}
if len(s) == 0 {
if fs[num].kind.IsValid() {
- return fmt.Errorf("field %v already set as %v type", prefix, fs[num].kind)
+ return errors.New("field %v already set as %v type", prefix, fs[num].kind)
}
fs[num].kind = k
}
@@ -195,7 +196,7 @@
// Verify that only messages or groups can have sub-fields.
k2 := fs[num].kind
if k2 > 0 && k2 != protoreflect.MessageKind && k2 != protoreflect.GroupKind && len(fs[num].sub) > 0 {
- return fmt.Errorf("field %v of %v type cannot have sub-fields", prefix, k2)
+ return errors.New("field %v of %v type cannot have sub-fields", prefix, k2)
}
return nil
}
diff --git a/internal/errors/errors.go b/internal/errors/errors.go
index e22035e..db1005d 100644
--- a/internal/errors/errors.go
+++ b/internal/errors/errors.go
@@ -7,6 +7,8 @@
import (
"fmt"
+
+ "google.golang.org/protobuf/internal/detrand"
)
// New formats a string according to the format specifier and arguments and
@@ -22,7 +24,16 @@
type prefixError struct{ s string }
-func (e *prefixError) Error() string { return "proto: " + e.s }
+var prefix = func() string {
+ if detrand.Bool() {
+ return "proto: "
+ }
+ return "proto: "
+}()
+
+func (e *prefixError) Error() string {
+ return prefix + e.s
+}
func InvalidUTF8(name string) error {
return New("field %v contains invalid UTF-8", name)
diff --git a/internal/impl/codec_tables.go b/internal/impl/codec_tables.go
index 77fc4c0..f421c78 100644
--- a/internal/impl/codec_tables.go
+++ b/internal/impl/codec_tables.go
@@ -423,7 +423,7 @@
}
}
}
- panic(fmt.Errorf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft))
+ panic(fmt.Sprintf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft))
}
// encoderFuncsForValue returns value functions for a field, used for
@@ -547,5 +547,5 @@
return coderGroupValue
}
}
- panic(fmt.Errorf("invalid field: no encoder for %v %v %v", fd.FullName(), fd.Cardinality(), fd.Kind()))
+ panic(fmt.Sprintf("invalid field: no encoder for %v %v %v", fd.FullName(), fd.Cardinality(), fd.Kind()))
}
diff --git a/internal/impl/message_reflect.go b/internal/impl/message_reflect.go
index b34e479..04e8f7c 100644
--- a/internal/impl/message_reflect.go
+++ b/internal/impl/message_reflect.go
@@ -145,7 +145,7 @@
}
func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
if !xt.IsValidValue(v) {
- panic(fmt.Errorf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
+ panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
}
if *m == nil {
*m = make(map[int32]ExtensionField)
diff --git a/proto/isinit_test.go b/proto/isinit_test.go
index 72dd108..d935d3a 100644
--- a/proto/isinit_test.go
+++ b/proto/isinit_test.go
@@ -6,6 +6,7 @@
import (
"fmt"
+ "strings"
"testing"
"google.golang.org/protobuf/proto"
@@ -20,13 +21,13 @@
}{
{
&testpb.TestRequired{},
- `proto: required field goproto.proto.test.TestRequired.required_field not set`,
+ `goproto.proto.test.TestRequired.required_field`,
},
{
&testpb.TestRequiredForeign{
OptionalMessage: &testpb.TestRequired{},
},
- `proto: required field goproto.proto.test.TestRequired.required_field not set`,
+ `goproto.proto.test.TestRequired.required_field`,
},
{
&testpb.TestRequiredForeign{
@@ -35,7 +36,7 @@
{},
},
},
- `proto: required field goproto.proto.test.TestRequired.required_field not set`,
+ `goproto.proto.test.TestRequired.required_field`,
},
{
&testpb.TestRequiredForeign{
@@ -43,7 +44,7 @@
1: {},
},
},
- `proto: required field goproto.proto.test.TestRequired.required_field not set`,
+ `goproto.proto.test.TestRequired.required_field`,
},
} {
err := proto.IsInitialized(test.m)
@@ -51,9 +52,8 @@
if err != nil {
got = fmt.Sprintf("%q", err)
}
- want := fmt.Sprintf("%q", test.want)
- if got != want {
- t.Errorf("IsInitialized(m):\n got: %v\nwant: %v\nMessage:\n%v", got, want, marshalText(test.m))
+ if !strings.Contains(got, test.want) {
+ t.Errorf("IsInitialized(m):\n got: %v\nwant contains: %v\nMessage:\n%v", got, test.want, marshalText(test.m))
}
}
}
diff --git a/reflect/protodesc/file_test.go b/reflect/protodesc/file_test.go
index 5319b52..38e8b4c 100644
--- a/reflect/protodesc/file_test.go
+++ b/reflect/protodesc/file_test.go
@@ -819,7 +819,7 @@
]
}]}]
`),
- wantErr: `proto: message "M.M" using proto3 semantics has conflict: "baz" with "_b_a_z_"`,
+ wantErr: `message "M.M" using proto3 semantics has conflict: "baz" with "_b_a_z_"`,
}, {
label: "proto3 message fields",
inDesc: mustParseFile(`