1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2015 Google Inc. All rights reserved. 4 // 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file or at 7 // https://developers.google.com/open-source/licenses/bsd 8 #endregion 9 10 using Google.Protobuf.TestProtos; 11 using Proto2 = Google.Protobuf.TestProtos.Proto2; 12 using NUnit.Framework; 13 using System; 14 using System.Collections; 15 using System.Collections.Generic; 16 17 using static Google.Protobuf.TestProtos.Proto2.UnittestExtensions; 18 using ProtobufUnittest; 19 20 namespace Google.Protobuf.Reflection 21 { 22 public class FieldAccessTest 23 { 24 [Test] GetValue()25 public void GetValue() 26 { 27 var message = SampleMessages.CreateFullTestAllTypes(); 28 var fields = TestProtos.TestAllTypes.Descriptor.Fields; 29 Assert.AreEqual(message.SingleBool, fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.GetValue(message)); 30 Assert.AreEqual(message.SingleBytes, fields[TestProtos.TestAllTypes.SingleBytesFieldNumber].Accessor.GetValue(message)); 31 Assert.AreEqual(message.SingleDouble, fields[TestProtos.TestAllTypes.SingleDoubleFieldNumber].Accessor.GetValue(message)); 32 Assert.AreEqual(message.SingleFixed32, fields[TestProtos.TestAllTypes.SingleFixed32FieldNumber].Accessor.GetValue(message)); 33 Assert.AreEqual(message.SingleFixed64, fields[TestProtos.TestAllTypes.SingleFixed64FieldNumber].Accessor.GetValue(message)); 34 Assert.AreEqual(message.SingleFloat, fields[TestProtos.TestAllTypes.SingleFloatFieldNumber].Accessor.GetValue(message)); 35 Assert.AreEqual(message.SingleForeignEnum, fields[TestProtos.TestAllTypes.SingleForeignEnumFieldNumber].Accessor.GetValue(message)); 36 Assert.AreEqual(message.SingleForeignMessage, fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].Accessor.GetValue(message)); 37 Assert.AreEqual(message.SingleImportEnum, fields[TestProtos.TestAllTypes.SingleImportEnumFieldNumber].Accessor.GetValue(message)); 38 Assert.AreEqual(message.SingleImportMessage, fields[TestProtos.TestAllTypes.SingleImportMessageFieldNumber].Accessor.GetValue(message)); 39 Assert.AreEqual(message.SingleInt32, fields[TestProtos.TestAllTypes.SingleInt32FieldNumber].Accessor.GetValue(message)); 40 Assert.AreEqual(message.SingleInt64, fields[TestProtos.TestAllTypes.SingleInt64FieldNumber].Accessor.GetValue(message)); 41 Assert.AreEqual(message.SingleNestedEnum, fields[TestProtos.TestAllTypes.SingleNestedEnumFieldNumber].Accessor.GetValue(message)); 42 Assert.AreEqual(message.SingleNestedMessage, fields[TestProtos.TestAllTypes.SingleNestedMessageFieldNumber].Accessor.GetValue(message)); 43 Assert.AreEqual(message.SinglePublicImportMessage, fields[TestProtos.TestAllTypes.SinglePublicImportMessageFieldNumber].Accessor.GetValue(message)); 44 Assert.AreEqual(message.SingleSint32, fields[TestProtos.TestAllTypes.SingleSint32FieldNumber].Accessor.GetValue(message)); 45 Assert.AreEqual(message.SingleSint64, fields[TestProtos.TestAllTypes.SingleSint64FieldNumber].Accessor.GetValue(message)); 46 Assert.AreEqual(message.SingleString, fields[TestProtos.TestAllTypes.SingleStringFieldNumber].Accessor.GetValue(message)); 47 Assert.AreEqual(message.SingleSfixed32, fields[TestProtos.TestAllTypes.SingleSfixed32FieldNumber].Accessor.GetValue(message)); 48 Assert.AreEqual(message.SingleSfixed64, fields[TestProtos.TestAllTypes.SingleSfixed64FieldNumber].Accessor.GetValue(message)); 49 Assert.AreEqual(message.SingleUint32, fields[TestProtos.TestAllTypes.SingleUint32FieldNumber].Accessor.GetValue(message)); 50 Assert.AreEqual(message.SingleUint64, fields[TestProtos.TestAllTypes.SingleUint64FieldNumber].Accessor.GetValue(message)); 51 Assert.AreEqual(message.OneofBytes, fields[TestProtos.TestAllTypes.OneofBytesFieldNumber].Accessor.GetValue(message)); 52 Assert.AreEqual(message.OneofString, fields[TestProtos.TestAllTypes.OneofStringFieldNumber].Accessor.GetValue(message)); 53 Assert.AreEqual(message.OneofNestedMessage, fields[TestProtos.TestAllTypes.OneofNestedMessageFieldNumber].Accessor.GetValue(message)); 54 Assert.AreEqual(message.OneofUint32, fields[TestProtos.TestAllTypes.OneofUint32FieldNumber].Accessor.GetValue(message)); 55 56 // Just one example for repeated fields - they're all just returning the list 57 var list = (IList) fields[TestProtos.TestAllTypes.RepeatedInt32FieldNumber].Accessor.GetValue(message); 58 Assert.AreEqual(message.RepeatedInt32, list); 59 Assert.AreEqual(message.RepeatedInt32[0], list[0]); // Just in case there was any doubt... 60 61 // Just a single map field, for the same reason 62 var mapMessage = new TestMap { MapStringString = { { "key1", "value1" }, { "key2", "value2" } } }; 63 fields = TestMap.Descriptor.Fields; 64 var dictionary = (IDictionary) fields[TestMap.MapStringStringFieldNumber].Accessor.GetValue(mapMessage); 65 Assert.AreEqual(mapMessage.MapStringString, dictionary); 66 Assert.AreEqual("value1", dictionary["key1"]); 67 } 68 69 [Test] GetValue_IncorrectType()70 public void GetValue_IncorrectType() 71 { 72 IMessage message = SampleMessages.CreateFullTestAllTypes(); 73 var fields = message.Descriptor.Fields; 74 Assert.Throws<InvalidCastException>(() => fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.GetValue(new TestMap())); 75 } 76 77 [Test] HasValue_Proto3_Message()78 public void HasValue_Proto3_Message() 79 { 80 var message = new TestAllTypes(); 81 var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].Accessor; 82 Assert.False(accessor.HasValue(message)); 83 message.SingleForeignMessage = new ForeignMessage(); 84 Assert.True(accessor.HasValue(message)); 85 message.SingleForeignMessage = null; 86 Assert.False(accessor.HasValue(message)); 87 } 88 89 [Test] HasValue_Proto3_Oneof()90 public void HasValue_Proto3_Oneof() 91 { 92 TestAllTypes message = new TestAllTypes(); 93 var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.OneofStringFieldNumber].Accessor; 94 Assert.False(accessor.HasValue(message)); 95 // Even though it's the default value, we still have a value. 96 message.OneofString = ""; 97 Assert.True(accessor.HasValue(message)); 98 message.OneofString = "hello"; 99 Assert.True(accessor.HasValue(message)); 100 message.OneofUint32 = 10; 101 Assert.False(accessor.HasValue(message)); 102 } 103 104 [Test] HasValue_Proto3_Primitive_Optional()105 public void HasValue_Proto3_Primitive_Optional() 106 { 107 var message = new TestProto3Optional(); 108 var accessor = ((IMessage) message).Descriptor.Fields[TestProto3Optional.OptionalInt64FieldNumber].Accessor; 109 Assert.IsFalse(accessor.HasValue(message)); 110 message.OptionalInt64 = 5L; 111 Assert.IsTrue(accessor.HasValue(message)); 112 message.ClearOptionalInt64(); 113 Assert.IsFalse(accessor.HasValue(message)); 114 message.OptionalInt64 = 0L; 115 Assert.IsTrue(accessor.HasValue(message)); 116 } 117 118 [Test] HasValue_Proto3_Primitive_NotOptional()119 public void HasValue_Proto3_Primitive_NotOptional() 120 { 121 IMessage message = SampleMessages.CreateFullTestAllTypes(); 122 var fields = message.Descriptor.Fields; 123 Assert.Throws<InvalidOperationException>(() => fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.HasValue(message)); 124 } 125 126 [Test] HasValue_Proto3_Repeated()127 public void HasValue_Proto3_Repeated() 128 { 129 var message = new TestAllTypes(); 130 var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.RepeatedBoolFieldNumber].Accessor; 131 Assert.Throws<InvalidOperationException>(() => accessor.HasValue(message)); 132 } 133 134 [Test] HasValue_Proto2_Primitive()135 public void HasValue_Proto2_Primitive() 136 { 137 var message = new Proto2.TestAllTypes(); 138 var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OptionalInt64FieldNumber].Accessor; 139 140 Assert.IsFalse(accessor.HasValue(message)); 141 message.OptionalInt64 = 5L; 142 Assert.IsTrue(accessor.HasValue(message)); 143 message.ClearOptionalInt64(); 144 Assert.IsFalse(accessor.HasValue(message)); 145 message.OptionalInt64 = 0L; 146 Assert.IsTrue(accessor.HasValue(message)); 147 } 148 149 [Test] HasValue_Proto2_Message()150 public void HasValue_Proto2_Message() 151 { 152 var message = new Proto2.TestAllTypes(); 153 var field = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OptionalForeignMessageFieldNumber]; 154 Assert.False(field.Accessor.HasValue(message)); 155 message.OptionalForeignMessage = new Proto2.ForeignMessage(); 156 Assert.True(field.Accessor.HasValue(message)); 157 message.OptionalForeignMessage = null; 158 Assert.False(field.Accessor.HasValue(message)); 159 } 160 161 [Test] HasValue_Proto2_Oneof()162 public void HasValue_Proto2_Oneof() 163 { 164 var message = new Proto2.TestAllTypes(); 165 var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OneofStringFieldNumber].Accessor; 166 Assert.False(accessor.HasValue(message)); 167 // Even though it's the default value, we still have a value. 168 message.OneofString = ""; 169 Assert.True(accessor.HasValue(message)); 170 message.OneofString = "hello"; 171 Assert.True(accessor.HasValue(message)); 172 message.OneofUint32 = 10; 173 Assert.False(accessor.HasValue(message)); 174 } 175 176 [Test] HasValue_Proto2_Repeated()177 public void HasValue_Proto2_Repeated() 178 { 179 var message = new Proto2.TestAllTypes(); 180 var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.RepeatedBoolFieldNumber].Accessor; 181 Assert.Throws<InvalidOperationException>(() => accessor.HasValue(message)); 182 } 183 184 [Test] SetValue_SingleFields()185 public void SetValue_SingleFields() 186 { 187 // Just a sample (primitives, messages, enums, strings, byte strings) 188 var message = SampleMessages.CreateFullTestAllTypes(); 189 var fields = TestProtos.TestAllTypes.Descriptor.Fields; 190 fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.SetValue(message, false); 191 fields[TestProtos.TestAllTypes.SingleInt32FieldNumber].Accessor.SetValue(message, 500); 192 fields[TestProtos.TestAllTypes.SingleStringFieldNumber].Accessor.SetValue(message, "It's a string"); 193 fields[TestProtos.TestAllTypes.SingleBytesFieldNumber].Accessor.SetValue(message, ByteString.CopyFrom(99, 98, 97)); 194 fields[TestProtos.TestAllTypes.SingleForeignEnumFieldNumber].Accessor.SetValue(message, ForeignEnum.ForeignFoo); 195 fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].Accessor.SetValue(message, new ForeignMessage { C = 12345 }); 196 fields[TestProtos.TestAllTypes.SingleDoubleFieldNumber].Accessor.SetValue(message, 20150701.5); 197 198 var expected = new TestAllTypes(SampleMessages.CreateFullTestAllTypes()) 199 { 200 SingleBool = false, 201 SingleInt32 = 500, 202 SingleString = "It's a string", 203 SingleBytes = ByteString.CopyFrom(99, 98, 97), 204 SingleForeignEnum = ForeignEnum.ForeignFoo, 205 SingleForeignMessage = new ForeignMessage { C = 12345 }, 206 SingleDouble = 20150701.5 207 }; 208 209 Assert.AreEqual(expected, message); 210 } 211 212 [Test] SetValue_SingleFields_WrongType()213 public void SetValue_SingleFields_WrongType() 214 { 215 IMessage message = SampleMessages.CreateFullTestAllTypes(); 216 var fields = message.Descriptor.Fields; 217 Assert.Throws<InvalidCastException>(() => fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.SetValue(message, "This isn't a bool")); 218 } 219 220 [Test] SetValue_MapFields()221 public void SetValue_MapFields() 222 { 223 IMessage message = new TestMap(); 224 var fields = message.Descriptor.Fields; 225 Assert.Throws<InvalidOperationException>(() => fields[TestMap.MapStringStringFieldNumber].Accessor.SetValue(message, new Dictionary<string, string>())); 226 } 227 228 [Test] SetValue_RepeatedFields()229 public void SetValue_RepeatedFields() 230 { 231 IMessage message = SampleMessages.CreateFullTestAllTypes(); 232 var fields = message.Descriptor.Fields; 233 Assert.Throws<InvalidOperationException>(() => fields[TestProtos.TestAllTypes.RepeatedDoubleFieldNumber].Accessor.SetValue(message, new double[10])); 234 } 235 236 [Test] Oneof()237 public void Oneof() 238 { 239 var message = new TestAllTypes(); 240 var descriptor = TestProtos.TestAllTypes.Descriptor; 241 Assert.AreEqual(1, descriptor.Oneofs.Count); 242 var oneof = descriptor.Oneofs[0]; 243 Assert.AreEqual("oneof_field", oneof.Name); 244 Assert.IsNull(oneof.Accessor.GetCaseFieldDescriptor(message)); 245 246 message.OneofString = "foo"; 247 Assert.AreSame(descriptor.Fields[TestProtos.TestAllTypes.OneofStringFieldNumber], oneof.Accessor.GetCaseFieldDescriptor(message)); 248 249 message.OneofUint32 = 10; 250 Assert.AreSame(descriptor.Fields[TestProtos.TestAllTypes.OneofUint32FieldNumber], oneof.Accessor.GetCaseFieldDescriptor(message)); 251 252 oneof.Accessor.Clear(message); 253 Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 254 } 255 256 [Test] Clear()257 public void Clear() 258 { 259 var message = SampleMessages.CreateFullTestAllTypes(); 260 var fields = TestProtos.TestAllTypes.Descriptor.Fields; 261 fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].Accessor.Clear(message); 262 fields[TestProtos.TestAllTypes.SingleInt32FieldNumber].Accessor.Clear(message); 263 fields[TestProtos.TestAllTypes.SingleStringFieldNumber].Accessor.Clear(message); 264 fields[TestProtos.TestAllTypes.SingleBytesFieldNumber].Accessor.Clear(message); 265 fields[TestProtos.TestAllTypes.SingleForeignEnumFieldNumber].Accessor.Clear(message); 266 fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].Accessor.Clear(message); 267 fields[TestProtos.TestAllTypes.RepeatedDoubleFieldNumber].Accessor.Clear(message); 268 269 var expected = new TestAllTypes(SampleMessages.CreateFullTestAllTypes()) 270 { 271 SingleBool = false, 272 SingleInt32 = 0, 273 SingleString = "", 274 SingleBytes = ByteString.Empty, 275 SingleForeignEnum = 0, 276 SingleForeignMessage = null, 277 }; 278 expected.RepeatedDouble.Clear(); 279 280 Assert.AreEqual(expected, message); 281 282 // Separately, maps. 283 var mapMessage = new TestMap { MapStringString = { { "key1", "value1" }, { "key2", "value2" } } }; 284 fields = TestMap.Descriptor.Fields; 285 fields[TestMap.MapStringStringFieldNumber].Accessor.Clear(mapMessage); 286 Assert.AreEqual(0, mapMessage.MapStringString.Count); 287 } 288 289 [Test] Clear_Proto3Optional()290 public void Clear_Proto3Optional() 291 { 292 TestProto3Optional message = new TestProto3Optional 293 { 294 OptionalInt32 = 0, 295 OptionalNestedMessage = new TestProto3Optional.Types.NestedMessage() 296 }; 297 var primitiveField = TestProto3Optional.Descriptor.Fields[TestProto3Optional.OptionalInt32FieldNumber]; 298 var messageField = TestProto3Optional.Descriptor.Fields[TestProto3Optional.OptionalNestedMessageFieldNumber]; 299 300 Assert.True(message.HasOptionalInt32); 301 Assert.NotNull(message.OptionalNestedMessage); 302 303 primitiveField.Accessor.Clear(message); 304 messageField.Accessor.Clear(message); 305 306 Assert.False(message.HasOptionalInt32); 307 Assert.Null(message.OptionalNestedMessage); 308 } 309 310 [Test] Clear_Proto3_Oneof()311 public void Clear_Proto3_Oneof() 312 { 313 var message = new TestAllTypes(); 314 var accessor = ((IMessage) message).Descriptor.Fields[TestProtos.TestAllTypes.OneofUint32FieldNumber].Accessor; 315 316 // The field accessor Clear method only affects a oneof if the current case is the one being cleared. 317 message.OneofString = "hello"; 318 Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); 319 accessor.Clear(message); 320 Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); 321 322 message.OneofUint32 = 100; 323 Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); 324 accessor.Clear(message); 325 Assert.AreEqual(TestProtos.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 326 } 327 328 [Test] Clear_Proto2_Oneof()329 public void Clear_Proto2_Oneof() 330 { 331 var message = new Proto2.TestAllTypes(); 332 var accessor = ((IMessage) message).Descriptor.Fields[Proto2.TestAllTypes.OneofUint32FieldNumber].Accessor; 333 334 // The field accessor Clear method only affects a oneof if the current case is the one being cleared. 335 message.OneofString = "hello"; 336 Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); 337 accessor.Clear(message); 338 Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); 339 340 message.OneofUint32 = 100; 341 Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); 342 accessor.Clear(message); 343 Assert.AreEqual(Proto2.TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 344 } 345 346 [Test] FieldDescriptor_ByName()347 public void FieldDescriptor_ByName() 348 { 349 var descriptor = TestProtos.TestAllTypes.Descriptor; 350 Assert.AreSame( 351 descriptor.Fields[TestProtos.TestAllTypes.SingleBoolFieldNumber], 352 descriptor.Fields["single_bool"]); 353 } 354 355 [Test] FieldDescriptor_NotFound()356 public void FieldDescriptor_NotFound() 357 { 358 var descriptor = TestProtos.TestAllTypes.Descriptor; 359 Assert.Throws<KeyNotFoundException>(() => descriptor.Fields[999999].ToString()); 360 Assert.Throws<KeyNotFoundException>(() => descriptor.Fields["not found"].ToString()); 361 } 362 363 [Test] GetExtensionValue()364 public void GetExtensionValue() 365 { 366 var message = SampleMessages.CreateFullTestAllExtensions(); 367 368 // test that the reflector works, since the reflector just runs through IExtendableMessage 369 Assert.AreEqual(message.GetExtension(OptionalBoolExtension), Proto2.TestAllExtensions.Descriptor.FindFieldByNumber(OptionalBoolExtension.FieldNumber).Accessor.GetValue(message)); 370 } 371 372 [Test] GetRepeatedExtensionValue()373 public void GetRepeatedExtensionValue() 374 { 375 // check to make sure repeated accessor uses GetOrRegister 376 var message = new Proto2.TestAllExtensions(); 377 378 Assert.IsNull(message.GetExtension(RepeatedBoolExtension)); 379 Assert.IsNotNull(Proto2.TestAllExtensions.Descriptor.FindFieldByNumber(RepeatedBoolExtension.FieldNumber).Accessor.GetValue(message)); 380 Assert.IsNotNull(message.GetExtension(RepeatedBoolExtension)); 381 382 message.ClearExtension(RepeatedBoolExtension); 383 Assert.IsNull(message.GetExtension(RepeatedBoolExtension)); 384 } 385 386 [Test] HasPresence()387 public void HasPresence() 388 { 389 // Proto3 390 var fields = TestProtos.TestAllTypes.Descriptor.Fields; 391 Assert.IsFalse(fields[TestProtos.TestAllTypes.SingleBoolFieldNumber].HasPresence); 392 Assert.IsTrue(fields[TestProtos.TestAllTypes.OneofBytesFieldNumber].HasPresence); 393 Assert.IsTrue(fields[TestProtos.TestAllTypes.SingleForeignMessageFieldNumber].HasPresence); 394 Assert.IsFalse(fields[TestProtos.TestAllTypes.RepeatedBoolFieldNumber].HasPresence); 395 396 fields = TestMap.Descriptor.Fields; 397 Assert.IsFalse(fields[TestMap.MapBoolBoolFieldNumber].HasPresence); 398 399 fields = TestProto3Optional.Descriptor.Fields; 400 Assert.IsTrue(fields[TestProto3Optional.OptionalBoolFieldNumber].HasPresence); 401 402 // Proto2 403 fields = Proto2.TestAllTypes.Descriptor.Fields; 404 Assert.IsTrue(fields[Proto2.TestAllTypes.OptionalBoolFieldNumber].HasPresence); 405 Assert.IsTrue(fields[Proto2.TestAllTypes.OneofBytesFieldNumber].HasPresence); 406 Assert.IsTrue(fields[Proto2.TestAllTypes.OptionalForeignMessageFieldNumber].HasPresence); 407 Assert.IsFalse(fields[Proto2.TestAllTypes.RepeatedBoolFieldNumber].HasPresence); 408 409 fields = Proto2.TestRequired.Descriptor.Fields; 410 Assert.IsTrue(fields[Proto2.TestRequired.AFieldNumber].HasPresence); 411 } 412 } 413 } 414