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