Joe Tsai | fa02f4e | 2018-09-12 16:20:37 -0700 | [diff] [blame^] | 1 | // Copyright 2018 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 impl |
| 6 | |
| 7 | import ( |
| 8 | "reflect" |
| 9 | "testing" |
| 10 | |
| 11 | "github.com/google/go-cmp/cmp" |
| 12 | |
| 13 | pref "google.golang.org/proto/reflect/protoreflect" |
| 14 | ptype "google.golang.org/proto/reflect/prototype" |
| 15 | ) |
| 16 | |
| 17 | type ( |
| 18 | MyBool bool |
| 19 | MyInt32 int32 |
| 20 | MyInt64 int64 |
| 21 | MyUint32 uint32 |
| 22 | MyUint64 uint64 |
| 23 | MyFloat32 float32 |
| 24 | MyFloat64 float64 |
| 25 | MyString string |
| 26 | MyBytes []byte |
| 27 | ) |
| 28 | |
| 29 | type ScalarProto2 struct { |
| 30 | Bool *bool `protobuf:"1"` |
| 31 | Int32 *int32 `protobuf:"2"` |
| 32 | Int64 *int64 `protobuf:"3"` |
| 33 | Uint32 *uint32 `protobuf:"4"` |
| 34 | Uint64 *uint64 `protobuf:"5"` |
| 35 | Float32 *float32 `protobuf:"6"` |
| 36 | Float64 *float64 `protobuf:"7"` |
| 37 | String *string `protobuf:"8"` |
| 38 | StringA []byte `protobuf:"9"` |
| 39 | Bytes []byte `protobuf:"10"` |
| 40 | BytesA *string `protobuf:"11"` |
| 41 | |
| 42 | MyBool *MyBool `protobuf:"12"` |
| 43 | MyInt32 *MyInt32 `protobuf:"13"` |
| 44 | MyInt64 *MyInt64 `protobuf:"14"` |
| 45 | MyUint32 *MyUint32 `protobuf:"15"` |
| 46 | MyUint64 *MyUint64 `protobuf:"16"` |
| 47 | MyFloat32 *MyFloat32 `protobuf:"17"` |
| 48 | MyFloat64 *MyFloat64 `protobuf:"18"` |
| 49 | MyString *MyString `protobuf:"19"` |
| 50 | MyStringA MyBytes `protobuf:"20"` |
| 51 | MyBytes MyBytes `protobuf:"21"` |
| 52 | MyBytesA *MyString `protobuf:"22"` |
| 53 | } |
| 54 | |
| 55 | type ScalarProto3 struct { |
| 56 | Bool bool `protobuf:"1"` |
| 57 | Int32 int32 `protobuf:"2"` |
| 58 | Int64 int64 `protobuf:"3"` |
| 59 | Uint32 uint32 `protobuf:"4"` |
| 60 | Uint64 uint64 `protobuf:"5"` |
| 61 | Float32 float32 `protobuf:"6"` |
| 62 | Float64 float64 `protobuf:"7"` |
| 63 | String string `protobuf:"8"` |
| 64 | StringA []byte `protobuf:"9"` |
| 65 | Bytes []byte `protobuf:"10"` |
| 66 | BytesA string `protobuf:"11"` |
| 67 | |
| 68 | MyBool MyBool `protobuf:"12"` |
| 69 | MyInt32 MyInt32 `protobuf:"13"` |
| 70 | MyInt64 MyInt64 `protobuf:"14"` |
| 71 | MyUint32 MyUint32 `protobuf:"15"` |
| 72 | MyUint64 MyUint64 `protobuf:"16"` |
| 73 | MyFloat32 MyFloat32 `protobuf:"17"` |
| 74 | MyFloat64 MyFloat64 `protobuf:"18"` |
| 75 | MyString MyString `protobuf:"19"` |
| 76 | MyStringA MyBytes `protobuf:"20"` |
| 77 | MyBytes MyBytes `protobuf:"21"` |
| 78 | MyBytesA MyString `protobuf:"22"` |
| 79 | } |
| 80 | |
| 81 | func TestFieldFuncs(t *testing.T) { |
| 82 | V := pref.ValueOf |
| 83 | type ( |
| 84 | // has checks that each field matches the list. |
| 85 | hasOp []bool |
| 86 | // get checks that each field returns values matching the list. |
| 87 | getOp []pref.Value |
| 88 | // set calls set on each field with the given value in the list. |
| 89 | setOp []pref.Value |
| 90 | // clear calls clear on each field. |
| 91 | clearOp []bool |
| 92 | // equal checks that the current message equals the provided value. |
| 93 | equalOp struct{ want interface{} } |
| 94 | |
| 95 | testOp interface{} // has | get | set | clear | equal |
| 96 | ) |
| 97 | |
| 98 | tests := []struct { |
| 99 | structType reflect.Type |
| 100 | messageDesc ptype.StandaloneMessage |
| 101 | testOps []testOp |
| 102 | }{{ |
| 103 | structType: reflect.TypeOf(ScalarProto2{}), |
| 104 | messageDesc: ptype.StandaloneMessage{ |
| 105 | Syntax: pref.Proto2, |
| 106 | FullName: "ScalarProto2", |
| 107 | Fields: []ptype.Field{ |
| 108 | {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true))}, |
| 109 | {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(2))}, |
| 110 | {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(3))}, |
| 111 | {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(4))}, |
| 112 | {Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(5))}, |
| 113 | {Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(6))}, |
| 114 | {Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(7))}, |
| 115 | {Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("8"))}, |
| 116 | {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("9"))}, |
| 117 | {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("10"))}, |
| 118 | {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("11"))}, |
| 119 | |
| 120 | {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind, Default: V(bool(true))}, |
| 121 | {Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind, Default: V(int32(13))}, |
| 122 | {Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind, Default: V(int64(14))}, |
| 123 | {Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind, Default: V(uint32(15))}, |
| 124 | {Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind, Default: V(uint64(16))}, |
| 125 | {Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind, Default: V(float32(17))}, |
| 126 | {Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind, Default: V(float64(18))}, |
| 127 | {Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("19"))}, |
| 128 | {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind, Default: V(string("20"))}, |
| 129 | {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("21"))}, |
| 130 | {Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("22"))}, |
| 131 | }, |
| 132 | }, |
| 133 | testOps: []testOp{ |
| 134 | hasOp([]bool{ |
| 135 | false, false, false, false, false, false, false, false, false, false, false, |
| 136 | false, false, false, false, false, false, false, false, false, false, false, |
| 137 | }), |
| 138 | getOp([]pref.Value{ |
| 139 | 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")), |
| 140 | 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")), |
| 141 | }), |
| 142 | setOp([]pref.Value{ |
| 143 | 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)), |
| 144 | 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)), |
| 145 | }), |
| 146 | hasOp([]bool{ |
| 147 | true, true, true, true, true, true, true, true, true, true, true, |
| 148 | true, true, true, true, true, true, true, true, true, true, true, |
| 149 | }), |
| 150 | equalOp{&ScalarProto2{ |
| 151 | new(bool), new(int32), new(int64), new(uint32), new(uint64), new(float32), new(float64), new(string), []byte{}, []byte{}, new(string), |
| 152 | new(MyBool), new(MyInt32), new(MyInt64), new(MyUint32), new(MyUint64), new(MyFloat32), new(MyFloat64), new(MyString), MyBytes{}, MyBytes{}, new(MyString), |
| 153 | }}, |
| 154 | clearOp([]bool{ |
| 155 | true, true, true, true, true, true, true, true, true, true, true, |
| 156 | true, true, true, true, true, true, true, true, true, true, true, |
| 157 | }), |
| 158 | equalOp{&ScalarProto2{}}, |
| 159 | }, |
| 160 | }, { |
| 161 | structType: reflect.TypeOf(ScalarProto3{}), |
| 162 | messageDesc: ptype.StandaloneMessage{ |
| 163 | Syntax: pref.Proto3, |
| 164 | FullName: "ScalarProto3", |
| 165 | Fields: []ptype.Field{ |
| 166 | {Name: "f1", Number: 1, Cardinality: pref.Optional, Kind: pref.BoolKind}, |
| 167 | {Name: "f2", Number: 2, Cardinality: pref.Optional, Kind: pref.Int32Kind}, |
| 168 | {Name: "f3", Number: 3, Cardinality: pref.Optional, Kind: pref.Int64Kind}, |
| 169 | {Name: "f4", Number: 4, Cardinality: pref.Optional, Kind: pref.Uint32Kind}, |
| 170 | {Name: "f5", Number: 5, Cardinality: pref.Optional, Kind: pref.Uint64Kind}, |
| 171 | {Name: "f6", Number: 6, Cardinality: pref.Optional, Kind: pref.FloatKind}, |
| 172 | {Name: "f7", Number: 7, Cardinality: pref.Optional, Kind: pref.DoubleKind}, |
| 173 | {Name: "f8", Number: 8, Cardinality: pref.Optional, Kind: pref.StringKind}, |
| 174 | {Name: "f9", Number: 9, Cardinality: pref.Optional, Kind: pref.StringKind}, |
| 175 | {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.BytesKind}, |
| 176 | {Name: "f11", Number: 11, Cardinality: pref.Optional, Kind: pref.BytesKind}, |
| 177 | |
| 178 | {Name: "f12", Number: 12, Cardinality: pref.Optional, Kind: pref.BoolKind}, |
| 179 | {Name: "f13", Number: 13, Cardinality: pref.Optional, Kind: pref.Int32Kind}, |
| 180 | {Name: "f14", Number: 14, Cardinality: pref.Optional, Kind: pref.Int64Kind}, |
| 181 | {Name: "f15", Number: 15, Cardinality: pref.Optional, Kind: pref.Uint32Kind}, |
| 182 | {Name: "f16", Number: 16, Cardinality: pref.Optional, Kind: pref.Uint64Kind}, |
| 183 | {Name: "f17", Number: 17, Cardinality: pref.Optional, Kind: pref.FloatKind}, |
| 184 | {Name: "f18", Number: 18, Cardinality: pref.Optional, Kind: pref.DoubleKind}, |
| 185 | {Name: "f19", Number: 19, Cardinality: pref.Optional, Kind: pref.StringKind}, |
| 186 | {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.StringKind}, |
| 187 | {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.BytesKind}, |
| 188 | {Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind}, |
| 189 | }, |
| 190 | }, |
| 191 | testOps: []testOp{ |
| 192 | hasOp([]bool{ |
| 193 | false, false, false, false, false, false, false, false, false, false, false, |
| 194 | false, false, false, false, false, false, false, false, false, false, false, |
| 195 | }), |
| 196 | getOp([]pref.Value{ |
| 197 | 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)), |
| 198 | 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)), |
| 199 | }), |
| 200 | setOp([]pref.Value{ |
| 201 | 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)), |
| 202 | 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)), |
| 203 | }), |
| 204 | hasOp([]bool{ |
| 205 | false, false, false, false, false, false, false, false, false, false, false, |
| 206 | false, false, false, false, false, false, false, false, false, false, false, |
| 207 | }), |
| 208 | equalOp{&ScalarProto3{}}, |
| 209 | setOp([]pref.Value{ |
| 210 | 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")), |
| 211 | 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")), |
| 212 | }), |
| 213 | hasOp([]bool{ |
| 214 | true, true, true, true, true, true, true, true, true, true, true, |
| 215 | true, true, true, true, true, true, true, true, true, true, true, |
| 216 | }), |
| 217 | equalOp{&ScalarProto3{ |
| 218 | true, 2, 3, 4, 5, 6, 7, "8", []byte("9"), []byte("10"), "11", |
| 219 | true, 13, 14, 15, 16, 17, 18, "19", []byte("20"), []byte("21"), "22", |
| 220 | }}, |
| 221 | clearOp([]bool{ |
| 222 | true, true, true, true, true, true, true, true, true, true, true, |
| 223 | true, true, true, true, true, true, true, true, true, true, true, |
| 224 | }), |
| 225 | equalOp{&ScalarProto3{}}, |
| 226 | }, |
| 227 | }} |
| 228 | |
| 229 | for _, tt := range tests { |
| 230 | t.Run(tt.structType.Name(), func(t *testing.T) { |
| 231 | // Construct the message descriptor. |
| 232 | md, err := ptype.NewMessage(&tt.messageDesc) |
| 233 | if err != nil { |
| 234 | t.Fatalf("NewMessage error: %v", err) |
| 235 | } |
| 236 | |
| 237 | // Generate the field functions from the message descriptor. |
| 238 | var mi MessageInfo |
| 239 | mi.generateFieldFuncs(tt.structType, md) // must not panic |
| 240 | |
| 241 | // Test the field functions. |
| 242 | m := reflect.New(tt.structType) |
| 243 | p := pointerOfValue(m) |
| 244 | for i, op := range tt.testOps { |
| 245 | switch op := op.(type) { |
| 246 | case hasOp: |
| 247 | got := map[pref.FieldNumber]bool{} |
| 248 | want := map[pref.FieldNumber]bool{} |
| 249 | for j, ok := range op { |
| 250 | n := pref.FieldNumber(j + 1) |
| 251 | got[n] = mi.fields[n].has(p) |
| 252 | want[n] = ok |
| 253 | } |
| 254 | if diff := cmp.Diff(want, got); diff != "" { |
| 255 | t.Errorf("operation %d, has mismatch (-want, +got):\n%s", i, diff) |
| 256 | } |
| 257 | case getOp: |
| 258 | got := map[pref.FieldNumber]pref.Value{} |
| 259 | want := map[pref.FieldNumber]pref.Value{} |
| 260 | for j, v := range op { |
| 261 | n := pref.FieldNumber(j + 1) |
| 262 | got[n] = mi.fields[n].get(p) |
| 263 | want[n] = v |
| 264 | } |
| 265 | xformValue := cmp.Transformer("", func(v pref.Value) interface{} { |
| 266 | return v.Interface() |
| 267 | }) |
| 268 | if diff := cmp.Diff(want, got, xformValue); diff != "" { |
| 269 | t.Errorf("operation %d, get mismatch (-want, +got):\n%s", i, diff) |
| 270 | } |
| 271 | case setOp: |
| 272 | for j, v := range op { |
| 273 | n := pref.FieldNumber(j + 1) |
| 274 | mi.fields[n].set(p, v) |
| 275 | } |
| 276 | case clearOp: |
| 277 | for j, ok := range op { |
| 278 | n := pref.FieldNumber(j + 1) |
| 279 | if ok { |
| 280 | mi.fields[n].clear(p) |
| 281 | } |
| 282 | } |
| 283 | case equalOp: |
| 284 | got := m.Interface() |
| 285 | if diff := cmp.Diff(op.want, got); diff != "" { |
| 286 | t.Errorf("operation %d, equal mismatch (-want, +got):\n%s", i, diff) |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | }) |
| 291 | } |
| 292 | } |