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