internal/impl: implement Vector fields
Generate functions for wrapping []T to implement protoreflect.Vector.
This implementation uses Go reflection instead to provide a single implementation
that can handle all Go slice types.
The test harness was greatly expanded to be able to test vectors (in addition
to messages and maps in the near future).
Change-Id: I0106c175f84a1e7e0a0a5b0e02e2489b70b0d177
Reviewed-on: https://go-review.googlesource.com/c/135339
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/message_test.go b/internal/impl/message_test.go
index c21c40e..c24fb04 100644
--- a/internal/impl/message_test.go
+++ b/internal/impl/message_test.go
@@ -5,10 +5,13 @@
package impl
import (
- "reflect"
+ "fmt"
+ "math"
+ "strings"
"testing"
"github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
ptype "github.com/golang/protobuf/v2/reflect/prototype"
@@ -22,6 +25,8 @@
return md
}
+var V = pref.ValueOf
+
type (
MyBool bool
MyInt32 int32
@@ -32,266 +37,487 @@
MyFloat64 float64
MyString string
MyBytes []byte
+
+ NamedStrings []MyString
+ NamedBytes []MyBytes
)
-type ScalarProto2 struct {
- Bool *bool `protobuf:"1"`
- Int32 *int32 `protobuf:"2"`
- Int64 *int64 `protobuf:"3"`
- Uint32 *uint32 `protobuf:"4"`
- Uint64 *uint64 `protobuf:"5"`
- Float32 *float32 `protobuf:"6"`
- Float64 *float64 `protobuf:"7"`
- String *string `protobuf:"8"`
- StringA []byte `protobuf:"9"`
- Bytes []byte `protobuf:"10"`
- BytesA *string `protobuf:"11"`
+// List of test operations to perform on messages, vectors, or maps.
+type (
+ messageOp interface{} // equalMessage | hasFields | getFields | setFields | clearFields | vectorFields | mapFields
+ messageOps []messageOp
- MyBool *MyBool `protobuf:"12"`
- MyInt32 *MyInt32 `protobuf:"13"`
- MyInt64 *MyInt64 `protobuf:"14"`
- MyUint32 *MyUint32 `protobuf:"15"`
- MyUint64 *MyUint64 `protobuf:"16"`
- MyFloat32 *MyFloat32 `protobuf:"17"`
- MyFloat64 *MyFloat64 `protobuf:"18"`
- MyString *MyString `protobuf:"19"`
- MyStringA MyBytes `protobuf:"20"`
- MyBytes MyBytes `protobuf:"21"`
- MyBytesA *MyString `protobuf:"22"`
+ vectorOp interface{} // equalVector | lenVector | getVector | setVector | appendVector | truncVector
+ vectorOps []vectorOp
+
+ mapOp interface{} // TODO
+ mapOps []mapOp // TODO
+)
+
+// Test operations performed on a message.
+type (
+ equalMessage pref.Message
+ hasFields map[pref.FieldNumber]bool
+ getFields map[pref.FieldNumber]pref.Value
+ setFields map[pref.FieldNumber]pref.Value
+ clearFields map[pref.FieldNumber]bool
+ vectorFields map[pref.FieldNumber]vectorOps
+ mapFields map[pref.FieldNumber]mapOps
+ messageFields map[pref.FieldNumber]messageOps
+ // TODO: Mutable, Range, ExtensionTypes
+)
+
+// Test operations performed on a vector.
+type (
+ equalVector pref.Vector
+ lenVector int
+ getVector map[int]pref.Value
+ setVector map[int]pref.Value
+ appendVector []pref.Value
+ truncVector int
+ // TODO: Mutable, MutableAppend
+)
+
+func TestScalarProto2(t *testing.T) {
+ type ScalarProto2 struct {
+ Bool *bool `protobuf:"1"`
+ Int32 *int32 `protobuf:"2"`
+ Int64 *int64 `protobuf:"3"`
+ Uint32 *uint32 `protobuf:"4"`
+ Uint64 *uint64 `protobuf:"5"`
+ Float32 *float32 `protobuf:"6"`
+ Float64 *float64 `protobuf:"7"`
+ String *string `protobuf:"8"`
+ StringA []byte `protobuf:"9"`
+ Bytes []byte `protobuf:"10"`
+ BytesA *string `protobuf:"11"`
+
+ MyBool *MyBool `protobuf:"12"`
+ MyInt32 *MyInt32 `protobuf:"13"`
+ MyInt64 *MyInt64 `protobuf:"14"`
+ MyUint32 *MyUint32 `protobuf:"15"`
+ MyUint64 *MyUint64 `protobuf:"16"`
+ MyFloat32 *MyFloat32 `protobuf:"17"`
+ MyFloat64 *MyFloat64 `protobuf:"18"`
+ MyString *MyString `protobuf:"19"`
+ MyStringA MyBytes `protobuf:"20"`
+ MyBytes MyBytes `protobuf:"21"`
+ MyBytesA *MyString `protobuf:"22"`
+ }
+
+ mi := MessageType{Desc: mustMakeMessageDesc(ptype.StandaloneMessage{
+ Syntax: pref.Proto2,
+ FullName: "ScalarProto2",
+ Fields: []ptype.Field{
+ {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true))},
+ {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(2))},
+ {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(3))},
+ {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(4))},
+ {Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(5))},
+ {Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(6))},
+ {Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(7))},
+ {Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("8"))},
+ {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("9"))},
+ {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("10"))},
+ {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("11"))},
+
+ {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true))},
+ {Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(13))},
+ {Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(14))},
+ {Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(15))},
+ {Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(16))},
+ {Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(17))},
+ {Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(18))},
+ {Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("19"))},
+ {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("20"))},
+ {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("21"))},
+ {Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("22"))},
+ },
+ })}
+
+ testMessage(t, nil, mi.MessageOf(&ScalarProto2{}), messageOps{
+ hasFields{
+ 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
+ 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
+ },
+ getFields{
+ 1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")),
+ 12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")),
+ },
+ setFields{
+ 1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
+ 12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
+ },
+ hasFields{
+ 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
+ 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
+ },
+ equalMessage(mi.MessageOf(&ScalarProto2{
+ new(bool), new(int32), new(int64), new(uint32), new(uint64), new(float32), new(float64), new(string), []byte{}, []byte{}, new(string),
+ new(MyBool), new(MyInt32), new(MyInt64), new(MyUint32), new(MyUint64), new(MyFloat32), new(MyFloat64), new(MyString), MyBytes{}, MyBytes{}, new(MyString),
+ })),
+ clearFields{
+ 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
+ 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
+ },
+ equalMessage(mi.MessageOf(&ScalarProto2{})),
+ })
}
-var scalarProto2Desc = mustMakeMessageDesc(ptype.StandaloneMessage{
- Syntax: pref.Proto2,
- FullName: "ScalarProto2",
- Fields: []ptype.Field{
- {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: pref.ValueOf(bool(true))},
- {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: pref.ValueOf(int32(2))},
- {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: pref.ValueOf(int64(3))},
- {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: pref.ValueOf(uint32(4))},
- {Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: pref.ValueOf(uint64(5))},
- {Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: pref.ValueOf(float32(6))},
- {Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: pref.ValueOf(float64(7))},
- {Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind, Default: pref.ValueOf(string("8"))},
- {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind, Default: pref.ValueOf(string("9"))},
- {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("10"))},
- {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("11"))},
+func TestScalarProto3(t *testing.T) {
+ type ScalarProto3 struct {
+ Bool bool `protobuf:"1"`
+ Int32 int32 `protobuf:"2"`
+ Int64 int64 `protobuf:"3"`
+ Uint32 uint32 `protobuf:"4"`
+ Uint64 uint64 `protobuf:"5"`
+ Float32 float32 `protobuf:"6"`
+ Float64 float64 `protobuf:"7"`
+ String string `protobuf:"8"`
+ StringA []byte `protobuf:"9"`
+ Bytes []byte `protobuf:"10"`
+ BytesA string `protobuf:"11"`
- {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: pref.ValueOf(bool(true))},
- {Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: pref.ValueOf(int32(13))},
- {Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: pref.ValueOf(int64(14))},
- {Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: pref.ValueOf(uint32(15))},
- {Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: pref.ValueOf(uint64(16))},
- {Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: pref.ValueOf(float32(17))},
- {Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: pref.ValueOf(float64(18))},
- {Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind, Default: pref.ValueOf(string("19"))},
- {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind, Default: pref.ValueOf(string("20"))},
- {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("21"))},
- {Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: pref.ValueOf([]byte("22"))},
- },
-})
+ MyBool MyBool `protobuf:"12"`
+ MyInt32 MyInt32 `protobuf:"13"`
+ MyInt64 MyInt64 `protobuf:"14"`
+ MyUint32 MyUint32 `protobuf:"15"`
+ MyUint64 MyUint64 `protobuf:"16"`
+ MyFloat32 MyFloat32 `protobuf:"17"`
+ MyFloat64 MyFloat64 `protobuf:"18"`
+ MyString MyString `protobuf:"19"`
+ MyStringA MyBytes `protobuf:"20"`
+ MyBytes MyBytes `protobuf:"21"`
+ MyBytesA MyString `protobuf:"22"`
+ }
-type ScalarProto3 struct {
- Bool bool `protobuf:"1"`
- Int32 int32 `protobuf:"2"`
- Int64 int64 `protobuf:"3"`
- Uint32 uint32 `protobuf:"4"`
- Uint64 uint64 `protobuf:"5"`
- Float32 float32 `protobuf:"6"`
- Float64 float64 `protobuf:"7"`
- String string `protobuf:"8"`
- StringA []byte `protobuf:"9"`
- Bytes []byte `protobuf:"10"`
- BytesA string `protobuf:"11"`
+ mi := MessageType{Desc: mustMakeMessageDesc(ptype.StandaloneMessage{
+ Syntax: pref.Proto3,
+ FullName: "ScalarProto3",
+ Fields: []ptype.Field{
+ {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind},
+ {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind},
+ {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind},
+ {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind},
+ {Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind},
+ {Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind},
+ {Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind},
+ {Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind},
+ {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind},
+ {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind},
+ {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind},
- MyBool MyBool `protobuf:"12"`
- MyInt32 MyInt32 `protobuf:"13"`
- MyInt64 MyInt64 `protobuf:"14"`
- MyUint32 MyUint32 `protobuf:"15"`
- MyUint64 MyUint64 `protobuf:"16"`
- MyFloat32 MyFloat32 `protobuf:"17"`
- MyFloat64 MyFloat64 `protobuf:"18"`
- MyString MyString `protobuf:"19"`
- MyStringA MyBytes `protobuf:"20"`
- MyBytes MyBytes `protobuf:"21"`
- MyBytesA MyString `protobuf:"22"`
+ {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind},
+ {Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind},
+ {Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind},
+ {Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind},
+ {Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind},
+ {Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind},
+ {Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind},
+ {Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind},
+ {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind},
+ {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind},
+ {Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind},
+ },
+ })}
+
+ testMessage(t, nil, mi.MessageOf(&ScalarProto3{}), messageOps{
+ hasFields{
+ 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
+ 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
+ },
+ getFields{
+ 1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
+ 12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
+ },
+ setFields{
+ 1: V(bool(false)), 2: V(int32(0)), 3: V(int64(0)), 4: V(uint32(0)), 5: V(uint64(0)), 6: V(float32(0)), 7: V(float64(0)), 8: V(string("")), 9: V(string("")), 10: V([]byte(nil)), 11: V([]byte(nil)),
+ 12: V(bool(false)), 13: V(int32(0)), 14: V(int64(0)), 15: V(uint32(0)), 16: V(uint64(0)), 17: V(float32(0)), 18: V(float64(0)), 19: V(string("")), 20: V(string("")), 21: V([]byte(nil)), 22: V([]byte(nil)),
+ },
+ hasFields{
+ 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false,
+ 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false,
+ },
+ equalMessage(mi.MessageOf(&ScalarProto3{})),
+ setFields{
+ 1: V(bool(true)), 2: V(int32(2)), 3: V(int64(3)), 4: V(uint32(4)), 5: V(uint64(5)), 6: V(float32(6)), 7: V(float64(7)), 8: V(string("8")), 9: V(string("9")), 10: V([]byte("10")), 11: V([]byte("11")),
+ 12: V(bool(true)), 13: V(int32(13)), 14: V(int64(14)), 15: V(uint32(15)), 16: V(uint64(16)), 17: V(float32(17)), 18: V(float64(18)), 19: V(string("19")), 20: V(string("20")), 21: V([]byte("21")), 22: V([]byte("22")),
+ },
+ hasFields{
+ 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
+ 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
+ },
+ equalMessage(mi.MessageOf(&ScalarProto3{
+ true, 2, 3, 4, 5, 6, 7, "8", []byte("9"), []byte("10"), "11",
+ true, 13, 14, 15, 16, 17, 18, "19", []byte("20"), []byte("21"), "22",
+ })),
+ clearFields{
+ 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true,
+ 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 21: true, 22: true,
+ },
+ equalMessage(mi.MessageOf(&ScalarProto3{})),
+ })
}
-var scalarProto3Desc = mustMakeMessageDesc(ptype.StandaloneMessage{
- Syntax: pref.Proto3,
- FullName: "ScalarProto3",
- Fields: []ptype.Field{
- {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind},
- {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind},
- {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind},
- {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind},
- {Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind},
- {Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind},
- {Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind},
- {Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind},
- {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind},
- {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind},
- {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind},
+func TestRepeatedScalars(t *testing.T) {
+ type RepeatedScalars struct {
+ Bools []bool `protobuf:"1"`
+ Int32s []int32 `protobuf:"2"`
+ Int64s []int64 `protobuf:"3"`
+ Uint32s []uint32 `protobuf:"4"`
+ Uint64s []uint64 `protobuf:"5"`
+ Float32s []float32 `protobuf:"6"`
+ Float64s []float64 `protobuf:"7"`
+ Strings []string `protobuf:"8"`
+ StringsA [][]byte `protobuf:"9"`
+ Bytes [][]byte `protobuf:"10"`
+ BytesA []string `protobuf:"11"`
- {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind},
- {Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind},
- {Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind},
- {Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind},
- {Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind},
- {Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind},
- {Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind},
- {Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind},
- {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind},
- {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind},
- {Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind},
- },
-})
+ MyStrings1 []MyString `protobuf:"12"`
+ MyStrings2 []MyBytes `protobuf:"13"`
+ MyBytes1 []MyBytes `protobuf:"14"`
+ MyBytes2 []MyString `protobuf:"15"`
-func TestKnownFields(t *testing.T) {
- V := pref.ValueOf
- type (
- // has checks that each field matches the list.
- hasOp []bool
- // get checks that each field returns values matching the list.
- getOp []pref.Value
- // set calls set on each field with the given value in the list.
- setOp []pref.Value
- // clear calls clear on each field.
- clearOp []bool
- // equal checks that the current message equals the provided value.
- equalOp struct{ want interface{} }
+ MyStrings3 NamedStrings `protobuf:"16"`
+ MyStrings4 NamedBytes `protobuf:"17"`
+ MyBytes3 NamedBytes `protobuf:"18"`
+ MyBytes4 NamedStrings `protobuf:"19"`
+ }
- testOp interface{} // has | get | set | clear | equal
- )
+ mi := MessageType{Desc: mustMakeMessageDesc(ptype.StandaloneMessage{
+ Syntax: pref.Proto2,
+ FullName: "RepeatedScalars",
+ Fields: []ptype.Field{
+ {Name: "f1", Number: 1, Cardinality: pref.Repeated, Kind: pref.BoolKind},
+ {Name: "f2", Number: 2, Cardinality: pref.Repeated, Kind: pref.Int32Kind},
+ {Name: "f3", Number: 3, Cardinality: pref.Repeated, Kind: pref.Int64Kind},
+ {Name: "f4", Number: 4, Cardinality: pref.Repeated, Kind: pref.Uint32Kind},
+ {Name: "f5", Number: 5, Cardinality: pref.Repeated, Kind: pref.Uint64Kind},
+ {Name: "f6", Number: 6, Cardinality: pref.Repeated, Kind: pref.FloatKind},
+ {Name: "f7", Number: 7, Cardinality: pref.Repeated, Kind: pref.DoubleKind},
+ {Name: "f8", Number: 8, Cardinality: pref.Repeated, Kind: pref.StringKind},
+ {Name: "f9", Number: 9, Cardinality: pref.Repeated, Kind: pref.StringKind},
+ {Name: "f10", Number: 10, Cardinality: pref.Repeated, Kind: pref.BytesKind},
+ {Name: "f11", Number: 11, Cardinality: pref.Repeated, Kind: pref.BytesKind},
- tests := []struct {
- structType reflect.Type
- messageDesc pref.MessageDescriptor
- testOps []testOp
- }{{
- structType: reflect.TypeOf(ScalarProto2{}),
- messageDesc: scalarProto2Desc,
- testOps: []testOp{
- hasOp([]bool{
- false, false, false, false, false, false, false, false, false, false, false,
- false, false, false, false, false, false, false, false, false, false, false,
- }),
- getOp([]pref.Value{
- V(bool(true)), V(int32(2)), V(int64(3)), V(uint32(4)), V(uint64(5)), V(float32(6)), V(float64(7)), V(string("8")), V(string("9")), V([]byte("10")), V([]byte("11")),
- V(bool(true)), V(int32(13)), V(int64(14)), V(uint32(15)), V(uint64(16)), V(float32(17)), V(float64(18)), V(string("19")), V(string("20")), V([]byte("21")), V([]byte("22")),
- }),
- setOp([]pref.Value{
- V(bool(false)), V(int32(0)), V(int64(0)), V(uint32(0)), V(uint64(0)), V(float32(0)), V(float64(0)), V(string("")), V(string("")), V([]byte(nil)), V([]byte(nil)),
- V(bool(false)), V(int32(0)), V(int64(0)), V(uint32(0)), V(uint64(0)), V(float32(0)), V(float64(0)), V(string("")), V(string("")), V([]byte(nil)), V([]byte(nil)),
- }),
- hasOp([]bool{
- true, true, true, true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true, true, true, true,
- }),
- equalOp{&ScalarProto2{
- new(bool), new(int32), new(int64), new(uint32), new(uint64), new(float32), new(float64), new(string), []byte{}, []byte{}, new(string),
- new(MyBool), new(MyInt32), new(MyInt64), new(MyUint32), new(MyUint64), new(MyFloat32), new(MyFloat64), new(MyString), MyBytes{}, MyBytes{}, new(MyString),
- }},
- clearOp([]bool{
- true, true, true, true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true, true, true, true,
- }),
- equalOp{&ScalarProto2{}},
+ {Name: "f12", Number: 12, Cardinality: pref.Repeated, Kind: pref.StringKind},
+ {Name: "f13", Number: 13, Cardinality: pref.Repeated, Kind: pref.StringKind},
+ {Name: "f14", Number: 14, Cardinality: pref.Repeated, Kind: pref.BytesKind},
+ {Name: "f15", Number: 15, Cardinality: pref.Repeated, Kind: pref.BytesKind},
+
+ {Name: "f16", Number: 16, Cardinality: pref.Repeated, Kind: pref.StringKind},
+ {Name: "f17", Number: 17, Cardinality: pref.Repeated, Kind: pref.StringKind},
+ {Name: "f18", Number: 18, Cardinality: pref.Repeated, Kind: pref.BytesKind},
+ {Name: "f19", Number: 19, Cardinality: pref.Repeated, Kind: pref.BytesKind},
},
- }, {
- structType: reflect.TypeOf(ScalarProto3{}),
- messageDesc: scalarProto3Desc,
- testOps: []testOp{
- hasOp([]bool{
- false, false, false, false, false, false, false, false, false, false, false,
- false, false, false, false, false, false, false, false, false, false, false,
- }),
- getOp([]pref.Value{
- V(bool(false)), V(int32(0)), V(int64(0)), V(uint32(0)), V(uint64(0)), V(float32(0)), V(float64(0)), V(string("")), V(string("")), V([]byte(nil)), V([]byte(nil)),
- V(bool(false)), V(int32(0)), V(int64(0)), V(uint32(0)), V(uint64(0)), V(float32(0)), V(float64(0)), V(string("")), V(string("")), V([]byte(nil)), V([]byte(nil)),
- }),
- setOp([]pref.Value{
- V(bool(false)), V(int32(0)), V(int64(0)), V(uint32(0)), V(uint64(0)), V(float32(0)), V(float64(0)), V(string("")), V(string("")), V([]byte(nil)), V([]byte(nil)),
- V(bool(false)), V(int32(0)), V(int64(0)), V(uint32(0)), V(uint64(0)), V(float32(0)), V(float64(0)), V(string("")), V(string("")), V([]byte(nil)), V([]byte(nil)),
- }),
- hasOp([]bool{
- false, false, false, false, false, false, false, false, false, false, false,
- false, false, false, false, false, false, false, false, false, false, false,
- }),
- equalOp{&ScalarProto3{}},
- setOp([]pref.Value{
- V(bool(true)), V(int32(2)), V(int64(3)), V(uint32(4)), V(uint64(5)), V(float32(6)), V(float64(7)), V(string("8")), V(string("9")), V([]byte("10")), V([]byte("11")),
- V(bool(true)), V(int32(13)), V(int64(14)), V(uint32(15)), V(uint64(16)), V(float32(17)), V(float64(18)), V(string("19")), V(string("20")), V([]byte("21")), V([]byte("22")),
- }),
- hasOp([]bool{
- true, true, true, true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true, true, true, true,
- }),
- equalOp{&ScalarProto3{
- true, 2, 3, 4, 5, 6, 7, "8", []byte("9"), []byte("10"), "11",
- true, 13, 14, 15, 16, 17, 18, "19", []byte("20"), []byte("21"), "22",
- }},
- clearOp([]bool{
- true, true, true, true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true, true, true, true,
- }),
- equalOp{&ScalarProto3{}},
+ })}
+
+ empty := mi.MessageOf(&RepeatedScalars{})
+ emptyFS := empty.KnownFields()
+
+ want := mi.MessageOf(&RepeatedScalars{
+ Bools: []bool{true, false, true},
+ Int32s: []int32{2, math.MinInt32, math.MaxInt32},
+ Int64s: []int64{3, math.MinInt64, math.MaxInt64},
+ Uint32s: []uint32{4, math.MaxUint32 / 2, math.MaxUint32},
+ Uint64s: []uint64{5, math.MaxUint64 / 2, math.MaxUint64},
+ Float32s: []float32{6, math.SmallestNonzeroFloat32, float32(math.NaN()), math.MaxFloat32},
+ Float64s: []float64{7, math.SmallestNonzeroFloat64, float64(math.NaN()), math.MaxFloat64},
+ Strings: []string{"8", "", "eight"},
+ StringsA: [][]byte{[]byte("9"), nil, []byte("nine")},
+ Bytes: [][]byte{[]byte("10"), nil, []byte("ten")},
+ BytesA: []string{"11", "", "eleven"},
+
+ MyStrings1: []MyString{"12", "", "twelve"},
+ MyStrings2: []MyBytes{[]byte("13"), nil, []byte("thirteen")},
+ MyBytes1: []MyBytes{[]byte("14"), nil, []byte("fourteen")},
+ MyBytes2: []MyString{"15", "", "fifteen"},
+
+ MyStrings3: NamedStrings{"16", "", "sixteen"},
+ MyStrings4: NamedBytes{[]byte("17"), nil, []byte("seventeen")},
+ MyBytes3: NamedBytes{[]byte("18"), nil, []byte("eighteen")},
+ MyBytes4: NamedStrings{"19", "", "nineteen"},
+ })
+ wantFS := want.KnownFields()
+
+ testMessage(t, nil, mi.MessageOf(&RepeatedScalars{}), messageOps{
+ hasFields{1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 10: false, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false},
+ getFields{1: emptyFS.Get(1), 3: emptyFS.Get(3), 5: emptyFS.Get(5), 7: emptyFS.Get(7), 9: emptyFS.Get(9), 11: emptyFS.Get(11), 13: emptyFS.Get(13), 15: emptyFS.Get(15), 17: emptyFS.Get(17), 19: emptyFS.Get(19)},
+ setFields{1: wantFS.Get(1), 3: wantFS.Get(3), 5: wantFS.Get(5), 7: wantFS.Get(7), 9: wantFS.Get(9), 11: wantFS.Get(11), 13: wantFS.Get(13), 15: wantFS.Get(15), 17: wantFS.Get(17), 19: wantFS.Get(19)},
+ vectorFields{
+ 2: {
+ lenVector(0),
+ appendVector{V(int32(2)), V(int32(math.MinInt32)), V(int32(math.MaxInt32))},
+ getVector{0: V(int32(2)), 1: V(int32(math.MinInt32)), 2: V(int32(math.MaxInt32))},
+ equalVector(wantFS.Get(2).Vector()),
+ },
+ 4: {
+ appendVector{V(uint32(0)), V(uint32(0)), V(uint32(0))},
+ setVector{0: V(uint32(4)), 1: V(uint32(math.MaxUint32 / 2)), 2: V(uint32(math.MaxUint32))},
+ lenVector(3),
+ },
+ 6: {
+ appendVector{V(float32(6)), V(float32(math.SmallestNonzeroFloat32)), V(float32(math.NaN())), V(float32(math.MaxFloat32))},
+ equalVector(wantFS.Get(6).Vector()),
+ },
+ 8: {
+ appendVector{V(""), V(""), V(""), V(""), V(""), V("")},
+ lenVector(6),
+ setVector{0: V("8"), 2: V("eight")},
+ truncVector(3),
+ equalVector(wantFS.Get(8).Vector()),
+ },
+ 10: {
+ appendVector{V([]byte(nil)), V([]byte(nil))},
+ setVector{0: V([]byte("10"))},
+ appendVector{V([]byte("wrong"))},
+ setVector{2: V([]byte("ten"))},
+ equalVector(wantFS.Get(10).Vector()),
+ },
+ 12: {
+ appendVector{V("12"), V("wrong"), V("twelve")},
+ setVector{1: V("")},
+ equalVector(wantFS.Get(12).Vector()),
+ },
+ 14: {
+ appendVector{V([]byte("14")), V([]byte(nil)), V([]byte("fourteen"))},
+ equalVector(wantFS.Get(14).Vector()),
+ },
+ 16: {
+ appendVector{V("16"), V(""), V("sixteen"), V("extra")},
+ truncVector(3),
+ equalVector(wantFS.Get(16).Vector()),
+ },
+ 18: {
+ appendVector{V([]byte("18")), V([]byte(nil)), V([]byte("eighteen"))},
+ equalVector(wantFS.Get(18).Vector()),
+ },
},
- }}
+ hasFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true},
+ equalMessage(want),
+ clearFields{1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true},
+ equalMessage(mi.MessageOf(&RepeatedScalars{})),
+ })
+}
- for _, tt := range tests {
- t.Run(tt.structType.Name(), func(t *testing.T) {
- mi := MessageType{Desc: tt.messageDesc}
+// TODO: Need to test singular and repeated messages
- // Test the field functions.
- p := reflect.New(tt.structType).Interface()
- m := mi.MessageOf(p)
- fs := m.KnownFields()
- for i, op := range tt.testOps {
- switch op := op.(type) {
- case hasOp:
- got := map[pref.FieldNumber]bool{}
- want := map[pref.FieldNumber]bool{}
- for j, ok := range op {
- n := pref.FieldNumber(j + 1)
- got[n] = fs.Has(n)
- want[n] = ok
- }
- if diff := cmp.Diff(want, got); diff != "" {
- t.Errorf("operation %d, has mismatch (-want, +got):\n%s", i, diff)
- }
- case getOp:
- got := map[pref.FieldNumber]pref.Value{}
- want := map[pref.FieldNumber]pref.Value{}
- for j, v := range op {
- n := pref.FieldNumber(j + 1)
- got[n] = fs.Get(n)
- want[n] = v
- }
- xformValue := cmp.Transformer("", func(v pref.Value) interface{} {
- return v.Interface()
- })
- if diff := cmp.Diff(want, got, xformValue); diff != "" {
- t.Errorf("operation %d, get mismatch (-want, +got):\n%s", i, diff)
- }
- case setOp:
- for j, v := range op {
- n := pref.FieldNumber(j + 1)
- fs.Set(n, v)
- }
- case clearOp:
- for j, ok := range op {
- n := pref.FieldNumber(j + 1)
- if ok {
- fs.Clear(n)
- }
- }
- case equalOp:
- got := m.(interface{ Unwrap() interface{} }).Unwrap()
- if diff := cmp.Diff(op.want, got); diff != "" {
- t.Errorf("operation %d, equal mismatch (-want, +got):\n%s", i, diff)
- }
+var cmpOpts = cmp.Options{
+ cmp.Transformer("UnwrapValue", func(v pref.Value) interface{} {
+ return v.Interface()
+ }),
+ cmp.Transformer("UnwrapMessage", func(m pref.Message) interface{} {
+ v := m.Interface()
+ if v, ok := v.(interface{ Unwrap() interface{} }); ok {
+ return v.Unwrap()
+ }
+ return v
+ }),
+ cmp.Transformer("UnwrapVector", func(v pref.Vector) interface{} {
+ return v.(interface{ Unwrap() interface{} }).Unwrap()
+ }),
+ cmp.Transformer("UnwrapMap", func(m pref.Map) interface{} {
+ return m.(interface{ Unwrap() interface{} }).Unwrap()
+ }),
+ cmpopts.EquateNaNs(),
+}
+
+func testMessage(t *testing.T, p path, m pref.Message, tt messageOps) {
+ fs := m.KnownFields()
+ for i, op := range tt {
+ p.Push(i)
+ switch op := op.(type) {
+ case equalMessage:
+ if diff := cmp.Diff(op, m, cmpOpts); diff != "" {
+ t.Errorf("operation %v, message mismatch (-want, +got):\n%s", p, diff)
+ }
+ case hasFields:
+ got := map[pref.FieldNumber]bool{}
+ want := map[pref.FieldNumber]bool(op)
+ for n := range want {
+ got[n] = fs.Has(n)
+ }
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Errorf("operation %v, KnownFields.Has mismatch (-want, +got):\n%s", p, diff)
+ }
+ case getFields:
+ got := map[pref.FieldNumber]pref.Value{}
+ want := map[pref.FieldNumber]pref.Value(op)
+ for n := range want {
+ got[n] = fs.Get(n)
+ }
+ if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
+ t.Errorf("operation %v, KnownFields.Get mismatch (-want, +got):\n%s", p, diff)
+ }
+ case setFields:
+ for n, v := range op {
+ fs.Set(n, v)
+ }
+ case clearFields:
+ for n, ok := range op {
+ if ok {
+ fs.Clear(n)
}
}
- })
+ case vectorFields:
+ for n, tt := range op {
+ p.Push(int(n))
+ testVectors(t, p, fs.Mutable(n).(pref.Vector), tt)
+ p.Pop()
+ }
+ default:
+ t.Fatalf("operation %v, invalid operation: %T", p, op)
+ }
+ p.Pop()
}
}
+
+func testVectors(t *testing.T, p path, v pref.Vector, tt vectorOps) {
+ for i, op := range tt {
+ p.Push(i)
+ switch op := op.(type) {
+ case equalVector:
+ if diff := cmp.Diff(op, v, cmpOpts); diff != "" {
+ t.Errorf("operation %v, vector mismatch (-want, +got):\n%s", p, diff)
+ }
+ case lenVector:
+ if got, want := v.Len(), int(op); got != want {
+ t.Errorf("operation %v, Vector.Len = %d, want %d", p, got, want)
+ }
+ case getVector:
+ got := map[int]pref.Value{}
+ want := map[int]pref.Value(op)
+ for n := range want {
+ got[n] = v.Get(n)
+ }
+ if diff := cmp.Diff(want, got, cmpOpts); diff != "" {
+ t.Errorf("operation %v, Vector.Get mismatch (-want, +got):\n%s", p, diff)
+ }
+ case setVector:
+ for n, e := range op {
+ v.Set(n, e)
+ }
+ case appendVector:
+ for _, e := range op {
+ v.Append(e)
+ }
+ case truncVector:
+ v.Truncate(int(op))
+ default:
+ t.Fatalf("operation %v, invalid operation: %T", p, op)
+ }
+ p.Pop()
+ }
+}
+
+type path []int
+
+func (p *path) Push(i int) { *p = append(*p, i) }
+func (p *path) Pop() { *p = (*p)[:len(*p)-1] }
+func (p path) String() string {
+ var ss []string
+ for _, i := range p {
+ ss = append(ss, fmt.Sprint(i))
+ }
+ return strings.Join(ss, ".")
+}