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 System; 34 using Google.Protobuf.TestProtos; 35 using NUnit.Framework; 36 using System.Collections; 37 using System.IO; 38 39 namespace Google.Protobuf.WellKnownTypes 40 { 41 public class WrappersTest 42 { 43 [Test] NullIsDefault()44 public void NullIsDefault() 45 { 46 var message = new TestWellKnownTypes(); 47 Assert.IsNull(message.StringField); 48 Assert.IsNull(message.BytesField); 49 Assert.IsNull(message.BoolField); 50 Assert.IsNull(message.FloatField); 51 Assert.IsNull(message.DoubleField); 52 Assert.IsNull(message.Int32Field); 53 Assert.IsNull(message.Int64Field); 54 Assert.IsNull(message.Uint32Field); 55 Assert.IsNull(message.Uint64Field); 56 } 57 58 [Test] NonDefaultSingleValues()59 public void NonDefaultSingleValues() 60 { 61 var message = new TestWellKnownTypes 62 { 63 StringField = "x", 64 BytesField = ByteString.CopyFrom(1, 2, 3), 65 BoolField = true, 66 FloatField = 12.5f, 67 DoubleField = 12.25d, 68 Int32Field = 1, 69 Int64Field = 2, 70 Uint32Field = 3, 71 Uint64Field = 4 72 }; 73 74 MessageParsingHelpers.AssertWritingMessage(message); 75 76 MessageParsingHelpers.AssertRoundtrip(TestWellKnownTypes.Parser, message, parsed => 77 { 78 Assert.AreEqual("x", parsed.StringField); 79 Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), parsed.BytesField); 80 Assert.AreEqual(true, parsed.BoolField); 81 Assert.AreEqual(12.5f, parsed.FloatField); 82 Assert.AreEqual(12.25d, parsed.DoubleField); 83 Assert.AreEqual(1, parsed.Int32Field); 84 Assert.AreEqual(2L, parsed.Int64Field); 85 Assert.AreEqual(3U, parsed.Uint32Field); 86 Assert.AreEqual(4UL, parsed.Uint64Field); 87 }); 88 } 89 90 [Test] NegativeSingleValues()91 public void NegativeSingleValues() 92 { 93 var message = new TestWellKnownTypes 94 { 95 FloatField = -12.5f, 96 DoubleField = -12.25d, 97 Int32Field = -1, 98 Int64Field = -2 99 }; 100 101 MessageParsingHelpers.AssertWritingMessage(message); 102 103 MessageParsingHelpers.AssertRoundtrip(TestWellKnownTypes.Parser, message, parsed => 104 { 105 Assert.AreEqual(-12.5f, parsed.FloatField); 106 Assert.AreEqual(-12.25d, parsed.DoubleField); 107 Assert.AreEqual(-1, parsed.Int32Field); 108 Assert.AreEqual(-2L, parsed.Int64Field); 109 }); 110 } 111 112 [Test] NonNullDefaultIsPreservedThroughSerialization()113 public void NonNullDefaultIsPreservedThroughSerialization() 114 { 115 var message = new TestWellKnownTypes 116 { 117 StringField = "", 118 BytesField = ByteString.Empty, 119 BoolField = false, 120 FloatField = 0f, 121 DoubleField = 0d, 122 Int32Field = 0, 123 Int64Field = 0, 124 Uint32Field = 0, 125 Uint64Field = 0 126 }; 127 128 MessageParsingHelpers.AssertWritingMessage(message); 129 130 MessageParsingHelpers.AssertRoundtrip(TestWellKnownTypes.Parser, message, parsed => 131 { 132 Assert.AreEqual("", parsed.StringField); 133 Assert.AreEqual(ByteString.Empty, parsed.BytesField); 134 Assert.AreEqual(false, parsed.BoolField); 135 Assert.AreEqual(0f, parsed.FloatField); 136 Assert.AreEqual(0d, parsed.DoubleField); 137 Assert.AreEqual(0, parsed.Int32Field); 138 Assert.AreEqual(0L, parsed.Int64Field); 139 Assert.AreEqual(0U, parsed.Uint32Field); 140 Assert.AreEqual(0UL, parsed.Uint64Field); 141 }); 142 } 143 144 [Test] RepeatedWrappersProhibitNullItems()145 public void RepeatedWrappersProhibitNullItems() 146 { 147 var message = new RepeatedWellKnownTypes(); 148 Assert.Throws<ArgumentNullException>(() => message.BoolField.Add((bool?) null)); 149 Assert.Throws<ArgumentNullException>(() => message.Int32Field.Add((int?) null)); 150 Assert.Throws<ArgumentNullException>(() => message.StringField.Add((string) null)); 151 Assert.Throws<ArgumentNullException>(() => message.BytesField.Add((ByteString) null)); 152 } 153 154 [Test] RepeatedWrappersSerializeDeserialize()155 public void RepeatedWrappersSerializeDeserialize() 156 { 157 var message = new RepeatedWellKnownTypes 158 { 159 BoolField = { true, false }, 160 BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty }, 161 DoubleField = { 12.5, -1.5, 0d }, 162 FloatField = { 123.25f, -20f, 0f }, 163 Int32Field = { int.MaxValue, int.MinValue, 0 }, 164 Int64Field = { long.MaxValue, long.MinValue, 0L }, 165 StringField = { "First", "Second", "" }, 166 Uint32Field = { uint.MaxValue, uint.MinValue, 0U }, 167 Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL }, 168 }; 169 170 // Just to test a single value for sanity... 171 Assert.AreEqual("Second", message.StringField[1]); 172 173 MessageParsingHelpers.AssertWritingMessage(message); 174 175 MessageParsingHelpers.AssertRoundtrip(RepeatedWellKnownTypes.Parser, message); 176 } 177 178 [Test] RepeatedWrappersBinaryFormat()179 public void RepeatedWrappersBinaryFormat() 180 { 181 // At one point we accidentally used a packed format for repeated wrappers, which is wrong (and weird). 182 // This test is just to prove that we use the right format. 183 184 var rawOutput = new MemoryStream(); 185 var output = new CodedOutputStream(rawOutput); 186 // Write a value of 5 187 output.WriteTag(RepeatedWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited); 188 output.WriteLength(2); 189 output.WriteTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint); 190 output.WriteInt32(5); 191 // Write a value of 0 (empty message) 192 output.WriteTag(RepeatedWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited); 193 output.WriteLength(0); 194 output.Flush(); 195 var expectedBytes = rawOutput.ToArray(); 196 197 var message = new RepeatedWellKnownTypes { Int32Field = { 5, 0 } }; 198 var actualBytes = message.ToByteArray(); 199 Assert.AreEqual(expectedBytes, actualBytes); 200 201 MessageParsingHelpers.AssertWritingMessage(message); 202 } 203 204 [Test] MapWrappersSerializeDeserialize()205 public void MapWrappersSerializeDeserialize() 206 { 207 // Note: no null values here, as they are prohibited in map fields 208 // (despite being representable). 209 var message = new MapWellKnownTypes 210 { 211 BoolField = { { 10, false }, { 20, true } }, 212 BytesField = { 213 { -1, ByteString.CopyFrom(1, 2, 3) }, 214 { 10, ByteString.CopyFrom(4, 5, 6) }, 215 { 1000, ByteString.Empty }, 216 }, 217 DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } }, 218 FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } }, 219 Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } }, 220 Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } }, 221 StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" } }, 222 Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } }, 223 Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } }, 224 }; 225 226 // Just to test a single value for sanity... 227 Assert.AreEqual("Second", message.StringField[12]); 228 229 MessageParsingHelpers.AssertWritingMessage(message); 230 231 MessageParsingHelpers.AssertRoundtrip(MapWellKnownTypes.Parser, message); 232 } 233 234 [Test] Reflection_SingleValues()235 public void Reflection_SingleValues() 236 { 237 var message = new TestWellKnownTypes 238 { 239 StringField = "x", 240 BytesField = ByteString.CopyFrom(1, 2, 3), 241 BoolField = true, 242 FloatField = 12.5f, 243 DoubleField = 12.25d, 244 Int32Field = 1, 245 Int64Field = 2, 246 Uint32Field = 3, 247 Uint64Field = 4 248 }; 249 var fields = TestWellKnownTypes.Descriptor.Fields; 250 251 Assert.AreEqual("x", fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.GetValue(message)); 252 Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), fields[TestWellKnownTypes.BytesFieldFieldNumber].Accessor.GetValue(message)); 253 Assert.AreEqual(true, fields[TestWellKnownTypes.BoolFieldFieldNumber].Accessor.GetValue(message)); 254 Assert.AreEqual(12.5f, fields[TestWellKnownTypes.FloatFieldFieldNumber].Accessor.GetValue(message)); 255 Assert.AreEqual(12.25d, fields[TestWellKnownTypes.DoubleFieldFieldNumber].Accessor.GetValue(message)); 256 Assert.AreEqual(1, fields[TestWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message)); 257 Assert.AreEqual(2L, fields[TestWellKnownTypes.Int64FieldFieldNumber].Accessor.GetValue(message)); 258 Assert.AreEqual(3U, fields[TestWellKnownTypes.Uint32FieldFieldNumber].Accessor.GetValue(message)); 259 Assert.AreEqual(4UL, fields[TestWellKnownTypes.Uint64FieldFieldNumber].Accessor.GetValue(message)); 260 261 // And a couple of null fields... 262 message.StringField = null; 263 message.FloatField = null; 264 Assert.IsNull(fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.GetValue(message)); 265 Assert.IsNull(fields[TestWellKnownTypes.FloatFieldFieldNumber].Accessor.GetValue(message)); 266 } 267 268 [Test] Reflection_RepeatedFields()269 public void Reflection_RepeatedFields() 270 { 271 // Just a single example... note that we can't have a null value here 272 var message = new RepeatedWellKnownTypes { Int32Field = { 1, 2 } }; 273 var fields = RepeatedWellKnownTypes.Descriptor.Fields; 274 var list = (IList) fields[RepeatedWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message); 275 CollectionAssert.AreEqual(new[] { 1, 2 }, list); 276 } 277 278 [Test] Reflection_MapFields()279 public void Reflection_MapFields() 280 { 281 // Just a single example... note that we can't have a null value here despite the value type being int? 282 var message = new MapWellKnownTypes { Int32Field = { { 1, 2 } } }; 283 var fields = MapWellKnownTypes.Descriptor.Fields; 284 var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message); 285 Assert.AreEqual(2, dictionary[1]); 286 } 287 288 [Test] Oneof()289 public void Oneof() 290 { 291 var message = new OneofWellKnownTypes { EmptyField = new Empty() }; 292 // Start off with a non-wrapper 293 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.EmptyField, message.OneofFieldCase); 294 AssertOneofRoundTrip(message); 295 296 message.StringField = "foo"; 297 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase); 298 AssertOneofRoundTrip(message); 299 300 message.StringField = "foo"; 301 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase); 302 AssertOneofRoundTrip(message); 303 304 message.DoubleField = 0.0f; 305 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase); 306 AssertOneofRoundTrip(message); 307 308 message.DoubleField = 1.0f; 309 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase); 310 AssertOneofRoundTrip(message); 311 312 message.ClearOneofField(); 313 Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 314 AssertOneofRoundTrip(message); 315 } 316 AssertOneofRoundTrip(OneofWellKnownTypes message)317 private void AssertOneofRoundTrip(OneofWellKnownTypes message) 318 { 319 // Normal roundtrip, but explicitly checking the case... 320 MessageParsingHelpers.AssertRoundtrip(OneofWellKnownTypes.Parser, message, parsed => 321 { 322 Assert.AreEqual(message.OneofFieldCase, parsed.OneofFieldCase); 323 }); 324 } 325 326 [Test] 327 [TestCase("x", "y", "y")] 328 [TestCase("x", "", "x")] 329 [TestCase("x", null, "x")] 330 [TestCase("", "y", "y")] 331 [TestCase("", "", "")] 332 [TestCase("", null, "")] 333 [TestCase(null, "y", "y")] 334 [TestCase(null, "", "")] 335 [TestCase(null, null, null)] Merging(string original, string merged, string expected)336 public void Merging(string original, string merged, string expected) 337 { 338 var originalMessage = new TestWellKnownTypes { StringField = original }; 339 var mergingMessage = new TestWellKnownTypes { StringField = merged }; 340 originalMessage.MergeFrom(mergingMessage); 341 Assert.AreEqual(expected, originalMessage.StringField); 342 343 // Try it using MergeFrom(CodedInputStream) too... 344 originalMessage = new TestWellKnownTypes { StringField = original }; 345 originalMessage.MergeFrom(mergingMessage.ToByteArray()); 346 Assert.AreEqual(expected, originalMessage.StringField); 347 } 348 349 // Merging is odd with wrapper types, due to the way that default values aren't emitted in 350 // the binary stream. In fact we cheat a little bit - a message with an explicitly present default 351 // value will have that default value ignored. See issue 615. Fixing this would require significant upheaval to 352 // the FieldCodec side of things. 353 [Test] MergingStreamExplicitValue()354 public void MergingStreamExplicitValue() 355 { 356 var message = new TestWellKnownTypes { Int32Field = 5 }; 357 358 // Create a byte array which has the data of an Int32Value explicitly containing a value of 0. 359 // This wouldn't normally happen. 360 byte[] bytes; 361 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited); 362 var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint); 363 using (var stream = new MemoryStream()) 364 { 365 var coded = new CodedOutputStream(stream); 366 coded.WriteTag(wrapperTag); 367 coded.WriteLength(2); // valueTag + a value 0, each one byte 368 coded.WriteTag(valueTag); 369 coded.WriteInt32(0); 370 coded.Flush(); 371 bytes = stream.ToArray(); 372 } 373 374 message.MergeFrom(bytes); 375 // A normal implementation would have 0 now, as the explicit default would have been overwritten the 5. 376 // With the FieldCodec for Nullable<int>, we can't tell the difference between an implicit 0 and an explicit 0. 377 Assert.AreEqual(5, message.Int32Field); 378 } 379 380 [Test] MergingStreamNoValue()381 public void MergingStreamNoValue() 382 { 383 var message = new TestWellKnownTypes { Int32Field = 5 }; 384 385 // Create a byte array which an Int32 field, but with no value. 386 var bytes = new TestWellKnownTypes { Int32Field = 0 }.ToByteArray(); 387 Assert.AreEqual(2, bytes.Length); // The tag for Int32Field is a single byte, then a byte indicating a 0-length message. 388 message.MergeFrom(bytes); 389 390 // The "implicit" 0 did *not* overwrite the value. 391 // (This is the correct behaviour.) 392 Assert.AreEqual(5, message.Int32Field); 393 } 394 395 // All permutations of origin/merging value being null, zero (default) or non-default. 396 // As this is the in-memory version, we don't need to worry about the difference between implicit and explicit 0. 397 [Test] 398 [TestCase(null, null, null)] 399 [TestCase(null, 0, 0)] 400 [TestCase(null, 5, 5)] 401 [TestCase(0, null, 0)] 402 [TestCase(0, 0, 0)] 403 [TestCase(0, 5, 5)] 404 [TestCase(5, null, 5)] 405 [TestCase(5, 0, 5)] 406 [TestCase(5, 10, 10)] MergingMessageWithZero(int? originValue, int? mergingValue, int? expectedResult)407 public void MergingMessageWithZero(int? originValue, int? mergingValue, int? expectedResult) 408 { 409 // This differs from the MergingStreamCornerCase because when we merge message *objects*, 410 // we ignore default values from the "source". 411 var message1 = new TestWellKnownTypes { Int32Field = originValue }; 412 var message2 = new TestWellKnownTypes { Int32Field = mergingValue }; 413 message1.MergeFrom(message2); 414 Assert.AreEqual(expectedResult, message1.Int32Field); 415 } 416 417 [Test] UnknownFieldInWrapperInt32FastPath()418 public void UnknownFieldInWrapperInt32FastPath() 419 { 420 var stream = new MemoryStream(); 421 var output = new CodedOutputStream(stream); 422 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited); 423 var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint); 424 var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint); 425 426 output.WriteTag(wrapperTag); 427 // Wrapper message is just long enough - 6 bytes - to use the wrapper fast-path. 428 output.WriteLength(6); // unknownTag + value 5 + valueType, each 1 byte, + value 65536, 3 bytes 429 output.WriteTag(unknownTag); 430 output.WriteInt32((int) valueTag); // Sneakily "pretend" it's a tag when it's really a value 431 output.WriteTag(valueTag); 432 output.WriteInt32(65536); 433 434 output.Flush(); 435 Assert.AreEqual(8, stream.Length); // tag (1 byte) + length (1 byte) + message (6 bytes) 436 stream.Position = 0; 437 438 MessageParsingHelpers.AssertReadingMessage( 439 TestWellKnownTypes.Parser, 440 stream.ToArray(), 441 message => Assert.AreEqual(65536, message.Int32Field)); 442 } 443 444 [Test] UnknownFieldInWrapperInt32SlowPath()445 public void UnknownFieldInWrapperInt32SlowPath() 446 { 447 var stream = new MemoryStream(); 448 var output = new CodedOutputStream(stream); 449 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited); 450 var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint); 451 var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint); 452 453 output.WriteTag(wrapperTag); 454 // Wrapper message is too short to be used on the wrapper fast-path. 455 output.WriteLength(4); // unknownTag + value 5 + valueType + value 6, each 1 byte 456 output.WriteTag(unknownTag); 457 output.WriteInt32((int)valueTag); // Sneakily "pretend" it's a tag when it's really a value 458 output.WriteTag(valueTag); 459 output.WriteInt32(6); 460 461 output.Flush(); 462 Assert.Less(stream.Length, 8); // tag (1 byte) + length (1 byte) + message 463 stream.Position = 0; 464 465 MessageParsingHelpers.AssertReadingMessage( 466 TestWellKnownTypes.Parser, 467 stream.ToArray(), 468 message => Assert.AreEqual(6, message.Int32Field)); 469 } 470 471 [Test] UnknownFieldInWrapperInt64FastPath()472 public void UnknownFieldInWrapperInt64FastPath() 473 { 474 var stream = new MemoryStream(); 475 var output = new CodedOutputStream(stream); 476 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int64FieldFieldNumber, WireFormat.WireType.LengthDelimited); 477 var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint); 478 var valueTag = WireFormat.MakeTag(Int64Value.ValueFieldNumber, WireFormat.WireType.Varint); 479 480 output.WriteTag(wrapperTag); 481 // Wrapper message is just long enough - 10 bytes - to use the wrapper fast-path. 482 output.WriteLength(11); // unknownTag + value 5 + valueType, each 1 byte, + value 0xfffffffffffff, 8 bytes 483 output.WriteTag(unknownTag); 484 output.WriteInt64((int)valueTag); // Sneakily "pretend" it's a tag when it's really a value 485 output.WriteTag(valueTag); 486 output.WriteInt64(0xfffffffffffffL); 487 488 output.Flush(); 489 Assert.AreEqual(13, stream.Length); // tag (1 byte) + length (1 byte) + message (11 bytes) 490 stream.Position = 0; 491 492 MessageParsingHelpers.AssertReadingMessage( 493 TestWellKnownTypes.Parser, 494 stream.ToArray(), 495 message => Assert.AreEqual(0xfffffffffffffL, message.Int64Field)); 496 } 497 498 [Test] UnknownFieldInWrapperInt64SlowPath()499 public void UnknownFieldInWrapperInt64SlowPath() 500 { 501 var stream = new MemoryStream(); 502 var output = new CodedOutputStream(stream); 503 var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int64FieldFieldNumber, WireFormat.WireType.LengthDelimited); 504 var unknownTag = WireFormat.MakeTag(15, WireFormat.WireType.Varint); 505 var valueTag = WireFormat.MakeTag(Int64Value.ValueFieldNumber, WireFormat.WireType.Varint); 506 507 output.WriteTag(wrapperTag); 508 // Wrapper message is too short to be used on the wrapper fast-path. 509 output.WriteLength(4); // unknownTag + value 5 + valueType + value 6, each 1 byte 510 output.WriteTag(unknownTag); 511 output.WriteInt64((int)valueTag); // Sneakily "pretend" it's a tag when it's really a value 512 output.WriteTag(valueTag); 513 output.WriteInt64(6); 514 515 output.Flush(); 516 Assert.Less(stream.Length, 12); // tag (1 byte) + length (1 byte) + message 517 stream.Position = 0; 518 519 MessageParsingHelpers.AssertReadingMessage( 520 TestWellKnownTypes.Parser, 521 stream.ToArray(), 522 message => Assert.AreEqual(6L, message.Int64Field)); 523 } 524 525 [Test] ClearWithReflection()526 public void ClearWithReflection() 527 { 528 // String and Bytes are the tricky ones here, as the CLR type of the property 529 // is the same between the wrapper and non-wrapper types. 530 var message = new TestWellKnownTypes { StringField = "foo" }; 531 TestWellKnownTypes.Descriptor.Fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.Clear(message); 532 Assert.IsNull(message.StringField); 533 } 534 535 [Test] NaNComparisons()536 public void NaNComparisons() 537 { 538 var message1 = new TestWellKnownTypes { DoubleField = SampleNaNs.Regular }; 539 var message2 = new TestWellKnownTypes { DoubleField = SampleNaNs.PayloadFlipped }; 540 var message3 = new TestWellKnownTypes { DoubleField = SampleNaNs.Regular }; 541 542 EqualityTester.AssertInequality(message1, message2); 543 EqualityTester.AssertEquality(message1, message3); 544 } 545 } 546 } 547