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 System.IO; 35 using Google.Protobuf.TestProtos; 36 using Proto2 = Google.Protobuf.TestProtos.Proto2; 37 using NUnit.Framework; 38 using System.Collections; 39 using System.Collections.Generic; 40 using System.Linq; 41 using Google.Protobuf.WellKnownTypes; 42 43 namespace Google.Protobuf 44 { 45 /// <summary> 46 /// Tests around the generated TestAllTypes message. 47 /// </summary> 48 public partial class GeneratedMessageTest 49 { 50 [Test] EmptyMessageFieldDistinctFromMissingMessageField()51 public void EmptyMessageFieldDistinctFromMissingMessageField() 52 { 53 // This demonstrates what we're really interested in... 54 var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() }; 55 var message2 = new TestAllTypes(); // SingleForeignMessage is null 56 EqualityTester.AssertInequality(message1, message2); 57 } 58 59 [Test] DefaultValues()60 public void DefaultValues() 61 { 62 // Single fields 63 var message = new TestAllTypes(); 64 Assert.AreEqual(false, message.SingleBool); 65 Assert.AreEqual(ByteString.Empty, message.SingleBytes); 66 Assert.AreEqual(0.0, message.SingleDouble); 67 Assert.AreEqual(0, message.SingleFixed32); 68 Assert.AreEqual(0L, message.SingleFixed64); 69 Assert.AreEqual(0.0f, message.SingleFloat); 70 Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum); 71 Assert.IsNull(message.SingleForeignMessage); 72 Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum); 73 Assert.IsNull(message.SingleImportMessage); 74 Assert.AreEqual(0, message.SingleInt32); 75 Assert.AreEqual(0L, message.SingleInt64); 76 Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum); 77 Assert.IsNull(message.SingleNestedMessage); 78 Assert.IsNull(message.SinglePublicImportMessage); 79 Assert.AreEqual(0, message.SingleSfixed32); 80 Assert.AreEqual(0L, message.SingleSfixed64); 81 Assert.AreEqual(0, message.SingleSint32); 82 Assert.AreEqual(0L, message.SingleSint64); 83 Assert.AreEqual("", message.SingleString); 84 Assert.AreEqual(0U, message.SingleUint32); 85 Assert.AreEqual(0UL, message.SingleUint64); 86 87 // Repeated fields 88 Assert.AreEqual(0, message.RepeatedBool.Count); 89 Assert.AreEqual(0, message.RepeatedBytes.Count); 90 Assert.AreEqual(0, message.RepeatedDouble.Count); 91 Assert.AreEqual(0, message.RepeatedFixed32.Count); 92 Assert.AreEqual(0, message.RepeatedFixed64.Count); 93 Assert.AreEqual(0, message.RepeatedFloat.Count); 94 Assert.AreEqual(0, message.RepeatedForeignEnum.Count); 95 Assert.AreEqual(0, message.RepeatedForeignMessage.Count); 96 Assert.AreEqual(0, message.RepeatedImportEnum.Count); 97 Assert.AreEqual(0, message.RepeatedImportMessage.Count); 98 Assert.AreEqual(0, message.RepeatedNestedEnum.Count); 99 Assert.AreEqual(0, message.RepeatedNestedMessage.Count); 100 Assert.AreEqual(0, message.RepeatedPublicImportMessage.Count); 101 Assert.AreEqual(0, message.RepeatedSfixed32.Count); 102 Assert.AreEqual(0, message.RepeatedSfixed64.Count); 103 Assert.AreEqual(0, message.RepeatedSint32.Count); 104 Assert.AreEqual(0, message.RepeatedSint64.Count); 105 Assert.AreEqual(0, message.RepeatedString.Count); 106 Assert.AreEqual(0, message.RepeatedUint32.Count); 107 Assert.AreEqual(0, message.RepeatedUint64.Count); 108 109 // Oneof fields 110 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 111 Assert.AreEqual(0, message.OneofUint32); 112 Assert.AreEqual("", message.OneofString); 113 Assert.AreEqual(ByteString.Empty, message.OneofBytes); 114 Assert.IsNull(message.OneofNestedMessage); 115 } 116 117 [Test] NullStringAndBytesRejected()118 public void NullStringAndBytesRejected() 119 { 120 var message = new TestAllTypes(); 121 Assert.Throws<ArgumentNullException>(() => message.SingleString = null); 122 Assert.Throws<ArgumentNullException>(() => message.OneofString = null); 123 Assert.Throws<ArgumentNullException>(() => message.SingleBytes = null); 124 Assert.Throws<ArgumentNullException>(() => message.OneofBytes = null); 125 } 126 127 [Test] RoundTrip_Empty()128 public void RoundTrip_Empty() 129 { 130 var message = new TestAllTypes(); 131 // Without setting any values, there's nothing to write. 132 byte[] bytes = message.ToByteArray(); 133 Assert.AreEqual(0, bytes.Length); 134 135 MessageParsingHelpers.AssertWritingMessage(message); 136 137 MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); 138 } 139 140 [Test] RoundTrip_SingleValues()141 public void RoundTrip_SingleValues() 142 { 143 var message = new TestAllTypes 144 { 145 SingleBool = true, 146 SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), 147 SingleDouble = 23.5, 148 SingleFixed32 = 23, 149 SingleFixed64 = 1234567890123, 150 SingleFloat = 12.25f, 151 SingleForeignEnum = ForeignEnum.ForeignBar, 152 SingleForeignMessage = new ForeignMessage { C = 10 }, 153 SingleImportEnum = ImportEnum.ImportBaz, 154 SingleImportMessage = new ImportMessage { D = 20 }, 155 SingleInt32 = 100, 156 SingleInt64 = 3210987654321, 157 SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, 158 SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, 159 SinglePublicImportMessage = new PublicImportMessage { E = 54 }, 160 SingleSfixed32 = -123, 161 SingleSfixed64 = -12345678901234, 162 SingleSint32 = -456, 163 SingleSint64 = -12345678901235, 164 SingleString = "test", 165 SingleUint32 = uint.MaxValue, 166 SingleUint64 = ulong.MaxValue 167 }; 168 169 MessageParsingHelpers.AssertWritingMessage(message); 170 171 MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); 172 } 173 174 [Test] RoundTrip_RepeatedValues()175 public void RoundTrip_RepeatedValues() 176 { 177 var message = new TestAllTypes 178 { 179 RepeatedBool = { true, false }, 180 RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, 181 RepeatedDouble = { -12.25, 23.5 }, 182 RepeatedFixed32 = { uint.MaxValue, 23 }, 183 RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, 184 RepeatedFloat = { 100f, 12.25f }, 185 RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, 186 RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, 187 RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, 188 RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, 189 RepeatedInt32 = { 100, 200 }, 190 RepeatedInt64 = { 3210987654321, long.MaxValue }, 191 RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, 192 RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, 193 RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, 194 RepeatedSfixed32 = { -123, 123 }, 195 RepeatedSfixed64 = { -12345678901234, 12345678901234 }, 196 RepeatedSint32 = { -456, 100 }, 197 RepeatedSint64 = { -12345678901235, 123 }, 198 RepeatedString = { "foo", "bar" }, 199 RepeatedUint32 = { uint.MaxValue, uint.MinValue }, 200 RepeatedUint64 = { ulong.MaxValue, uint.MinValue } 201 }; 202 203 MessageParsingHelpers.AssertWritingMessage(message); 204 205 MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message); 206 } 207 208 // Note that not every map within map_unittest_proto3 is used. They all go through very 209 // similar code paths. The fact that all maps are present is validation that we have codecs 210 // for every type. 211 [Test] RoundTrip_Maps()212 public void RoundTrip_Maps() 213 { 214 var message = new TestMap 215 { 216 MapBoolBool = { 217 { false, true }, 218 { true, false } 219 }, 220 MapInt32Bytes = { 221 { 5, ByteString.CopyFrom(6, 7, 8) }, 222 { 25, ByteString.CopyFrom(1, 2, 3, 4, 5) }, 223 { 10, ByteString.Empty } 224 }, 225 MapInt32ForeignMessage = { 226 { 0, new ForeignMessage { C = 10 } }, 227 { 5, new ForeignMessage() }, 228 }, 229 MapInt32Enum = { 230 { 1, MapEnum.Bar }, 231 { 2000, MapEnum.Foo } 232 } 233 }; 234 235 MessageParsingHelpers.AssertWritingMessage(message); 236 237 MessageParsingHelpers.AssertRoundtrip(TestMap.Parser, message); 238 } 239 240 [Test] MapWithEmptyEntry()241 public void MapWithEmptyEntry() 242 { 243 var message = new TestMap 244 { 245 MapInt32Bytes = { { 0, ByteString.Empty } } 246 }; 247 248 byte[] bytes = message.ToByteArray(); 249 Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte) 250 251 MessageParsingHelpers.AssertWritingMessage(message); 252 253 MessageParsingHelpers.AssertReadingMessage( 254 TestMap.Parser, 255 bytes, 256 parsed=> 257 { 258 Assert.AreEqual(1, parsed.MapInt32Bytes.Count); 259 Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]); 260 }); 261 } 262 263 [Test] MapWithOnlyValue()264 public void MapWithOnlyValue() 265 { 266 // Hand-craft the stream to contain a single entry with just a value. 267 var memoryStream = new MemoryStream(); 268 var output = new CodedOutputStream(memoryStream); 269 output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); 270 var nestedMessage = new ForeignMessage { C = 20 }; 271 // Size of the entry (tag, size written by WriteMessage, data written by WriteMessage) 272 output.WriteLength(2 + nestedMessage.CalculateSize()); 273 output.WriteTag(2, WireFormat.WireType.LengthDelimited); 274 output.WriteMessage(nestedMessage); 275 output.Flush(); 276 277 MessageParsingHelpers.AssertReadingMessage( 278 TestMap.Parser, 279 memoryStream.ToArray(), 280 parsed => 281 { 282 Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]); 283 }); 284 } 285 286 [Test] MapWithOnlyKey_PrimitiveValue()287 public void MapWithOnlyKey_PrimitiveValue() 288 { 289 // Hand-craft the stream to contain a single entry with just a key. 290 var memoryStream = new MemoryStream(); 291 var output = new CodedOutputStream(memoryStream); 292 output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited); 293 int key = 10; 294 output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); 295 output.WriteTag(1, WireFormat.WireType.Varint); 296 output.WriteInt32(key); 297 output.Flush(); 298 299 MessageParsingHelpers.AssertReadingMessage( 300 TestMap.Parser, 301 memoryStream.ToArray(), 302 parsed => 303 { 304 Assert.AreEqual(0.0, parsed.MapInt32Double[key]); 305 }); 306 } 307 308 [Test] MapWithOnlyKey_MessageValue()309 public void MapWithOnlyKey_MessageValue() 310 { 311 // Hand-craft the stream to contain a single entry with just a key. 312 var memoryStream = new MemoryStream(); 313 var output = new CodedOutputStream(memoryStream); 314 output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited); 315 int key = 10; 316 output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key)); 317 output.WriteTag(1, WireFormat.WireType.Varint); 318 output.WriteInt32(key); 319 output.Flush(); 320 321 MessageParsingHelpers.AssertReadingMessage( 322 TestMap.Parser, 323 memoryStream.ToArray(), 324 parsed => 325 { 326 Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]); 327 }); 328 } 329 330 [Test] MapIgnoresExtraFieldsWithinEntryMessages()331 public void MapIgnoresExtraFieldsWithinEntryMessages() 332 { 333 // Hand-craft the stream to contain a single entry with three fields 334 var memoryStream = new MemoryStream(); 335 var output = new CodedOutputStream(memoryStream); 336 337 output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); 338 339 var key = 10; // Field 1 340 var value = 20; // Field 2 341 var extra = 30; // Field 3 342 343 // Each field can be represented in a single byte, with a single byte tag. 344 // Total message size: 6 bytes. 345 output.WriteLength(6); 346 output.WriteTag(1, WireFormat.WireType.Varint); 347 output.WriteInt32(key); 348 output.WriteTag(2, WireFormat.WireType.Varint); 349 output.WriteInt32(value); 350 output.WriteTag(3, WireFormat.WireType.Varint); 351 output.WriteInt32(extra); 352 output.Flush(); 353 354 MessageParsingHelpers.AssertReadingMessage( 355 TestMap.Parser, 356 memoryStream.ToArray(), 357 parsed => 358 { 359 Assert.AreEqual(value, parsed.MapInt32Int32[key]); 360 }); 361 } 362 363 [Test] MapFieldOrderIsIrrelevant()364 public void MapFieldOrderIsIrrelevant() 365 { 366 var memoryStream = new MemoryStream(); 367 var output = new CodedOutputStream(memoryStream); 368 369 output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); 370 371 var key = 10; 372 var value = 20; 373 374 // Each field can be represented in a single byte, with a single byte tag. 375 // Total message size: 4 bytes. 376 output.WriteLength(4); 377 output.WriteTag(2, WireFormat.WireType.Varint); 378 output.WriteInt32(value); 379 output.WriteTag(1, WireFormat.WireType.Varint); 380 output.WriteInt32(key); 381 output.Flush(); 382 383 MessageParsingHelpers.AssertReadingMessage( 384 TestMap.Parser, 385 memoryStream.ToArray(), 386 parsed => 387 { 388 Assert.AreEqual(value, parsed.MapInt32Int32[key]); 389 }); 390 } 391 392 [Test] MapNonContiguousEntries()393 public void MapNonContiguousEntries() 394 { 395 var memoryStream = new MemoryStream(); 396 var output = new CodedOutputStream(memoryStream); 397 398 // Message structure: 399 // Entry for MapInt32Int32 400 // Entry for MapStringString 401 // Entry for MapInt32Int32 402 403 // First entry 404 var key1 = 10; 405 var value1 = 20; 406 output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); 407 output.WriteLength(4); 408 output.WriteTag(1, WireFormat.WireType.Varint); 409 output.WriteInt32(key1); 410 output.WriteTag(2, WireFormat.WireType.Varint); 411 output.WriteInt32(value1); 412 413 // Second entry 414 var key2 = "a"; 415 var value2 = "b"; 416 output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited); 417 output.WriteLength(6); // 3 bytes per entry: tag, size, character 418 output.WriteTag(1, WireFormat.WireType.LengthDelimited); 419 output.WriteString(key2); 420 output.WriteTag(2, WireFormat.WireType.LengthDelimited); 421 output.WriteString(value2); 422 423 // Third entry 424 var key3 = 15; 425 var value3 = 25; 426 output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); 427 output.WriteLength(4); 428 output.WriteTag(1, WireFormat.WireType.Varint); 429 output.WriteInt32(key3); 430 output.WriteTag(2, WireFormat.WireType.Varint); 431 output.WriteInt32(value3); 432 433 output.Flush(); 434 435 MessageParsingHelpers.AssertReadingMessage( 436 TestMap.Parser, 437 memoryStream.ToArray(), 438 parsed => 439 { 440 var expected = new TestMap 441 { 442 MapInt32Int32 = { { key1, value1 }, { key3, value3 } }, 443 MapStringString = { { key2, value2 } } 444 }; 445 Assert.AreEqual(expected, parsed); 446 }); 447 } 448 449 [Test] DuplicateKeys_LastEntryWins()450 public void DuplicateKeys_LastEntryWins() 451 { 452 var memoryStream = new MemoryStream(); 453 var output = new CodedOutputStream(memoryStream); 454 455 var key = 10; 456 var value1 = 20; 457 var value2 = 30; 458 459 // First entry 460 output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); 461 output.WriteLength(4); 462 output.WriteTag(1, WireFormat.WireType.Varint); 463 output.WriteInt32(key); 464 output.WriteTag(2, WireFormat.WireType.Varint); 465 output.WriteInt32(value1); 466 467 // Second entry - same key, different value 468 output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited); 469 output.WriteLength(4); 470 output.WriteTag(1, WireFormat.WireType.Varint); 471 output.WriteInt32(key); 472 output.WriteTag(2, WireFormat.WireType.Varint); 473 output.WriteInt32(value2); 474 output.Flush(); 475 476 MessageParsingHelpers.AssertReadingMessage( 477 TestMap.Parser, 478 memoryStream.ToArray(), 479 parsed => 480 { 481 Assert.AreEqual(value2, parsed.MapInt32Int32[key]); 482 }); 483 } 484 485 [Test] CloneSingleNonMessageValues()486 public void CloneSingleNonMessageValues() 487 { 488 var original = new TestAllTypes 489 { 490 SingleBool = true, 491 SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), 492 SingleDouble = 23.5, 493 SingleFixed32 = 23, 494 SingleFixed64 = 1234567890123, 495 SingleFloat = 12.25f, 496 SingleInt32 = 100, 497 SingleInt64 = 3210987654321, 498 SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, 499 SingleSfixed32 = -123, 500 SingleSfixed64 = -12345678901234, 501 SingleSint32 = -456, 502 SingleSint64 = -12345678901235, 503 SingleString = "test", 504 SingleUint32 = uint.MaxValue, 505 SingleUint64 = ulong.MaxValue 506 }; 507 var clone = original.Clone(); 508 Assert.AreNotSame(original, clone); 509 Assert.AreEqual(original, clone); 510 // Just as a single example 511 clone.SingleInt32 = 150; 512 Assert.AreNotEqual(original, clone); 513 } 514 515 [Test] CloneRepeatedNonMessageValues()516 public void CloneRepeatedNonMessageValues() 517 { 518 var original = new TestAllTypes 519 { 520 RepeatedBool = { true, false }, 521 RepeatedBytes = { ByteString.CopyFrom(1, 2, 3, 4), ByteString.CopyFrom(5, 6) }, 522 RepeatedDouble = { -12.25, 23.5 }, 523 RepeatedFixed32 = { uint.MaxValue, 23 }, 524 RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, 525 RepeatedFloat = { 100f, 12.25f }, 526 RepeatedInt32 = { 100, 200 }, 527 RepeatedInt64 = { 3210987654321, long.MaxValue }, 528 RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, 529 RepeatedSfixed32 = { -123, 123 }, 530 RepeatedSfixed64 = { -12345678901234, 12345678901234 }, 531 RepeatedSint32 = { -456, 100 }, 532 RepeatedSint64 = { -12345678901235, 123 }, 533 RepeatedString = { "foo", "bar" }, 534 RepeatedUint32 = { uint.MaxValue, uint.MinValue }, 535 RepeatedUint64 = { ulong.MaxValue, uint.MinValue } 536 }; 537 538 var clone = original.Clone(); 539 Assert.AreNotSame(original, clone); 540 Assert.AreEqual(original, clone); 541 // Just as a single example 542 clone.RepeatedDouble.Add(25.5); 543 Assert.AreNotEqual(original, clone); 544 } 545 546 [Test] CloneSingleMessageField()547 public void CloneSingleMessageField() 548 { 549 var original = new TestAllTypes 550 { 551 SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } 552 }; 553 554 var clone = original.Clone(); 555 Assert.AreNotSame(original, clone); 556 Assert.AreNotSame(original.SingleNestedMessage, clone.SingleNestedMessage); 557 Assert.AreEqual(original, clone); 558 559 clone.SingleNestedMessage.Bb = 30; 560 Assert.AreNotEqual(original, clone); 561 } 562 563 [Test] CloneRepeatedMessageField()564 public void CloneRepeatedMessageField() 565 { 566 var original = new TestAllTypes 567 { 568 RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 20 } } 569 }; 570 571 var clone = original.Clone(); 572 Assert.AreNotSame(original, clone); 573 Assert.AreNotSame(original.RepeatedNestedMessage, clone.RepeatedNestedMessage); 574 Assert.AreNotSame(original.RepeatedNestedMessage[0], clone.RepeatedNestedMessage[0]); 575 Assert.AreEqual(original, clone); 576 577 clone.RepeatedNestedMessage[0].Bb = 30; 578 Assert.AreNotEqual(original, clone); 579 } 580 581 [Test] CloneOneofField()582 public void CloneOneofField() 583 { 584 var original = new TestAllTypes 585 { 586 OneofNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } 587 }; 588 589 var clone = original.Clone(); 590 Assert.AreNotSame(original, clone); 591 Assert.AreEqual(original, clone); 592 593 // We should have cloned the message 594 original.OneofNestedMessage.Bb = 30; 595 Assert.AreNotEqual(original, clone); 596 } 597 598 [Test] OneofProperties()599 public void OneofProperties() 600 { 601 // Switch the oneof case between each of the different options, and check everything behaves 602 // as expected in each case. 603 var message = new TestAllTypes(); 604 Assert.AreEqual("", message.OneofString); 605 Assert.AreEqual(0, message.OneofUint32); 606 Assert.AreEqual(ByteString.Empty, message.OneofBytes); 607 Assert.IsNull(message.OneofNestedMessage); 608 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 609 610 message.OneofString = "sample"; 611 Assert.AreEqual("sample", message.OneofString); 612 Assert.AreEqual(0, message.OneofUint32); 613 Assert.AreEqual(ByteString.Empty, message.OneofBytes); 614 Assert.IsNull(message.OneofNestedMessage); 615 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message.OneofFieldCase); 616 617 var bytes = ByteString.CopyFrom(1, 2, 3); 618 message.OneofBytes = bytes; 619 Assert.AreEqual("", message.OneofString); 620 Assert.AreEqual(0, message.OneofUint32); 621 Assert.AreEqual(bytes, message.OneofBytes); 622 Assert.IsNull(message.OneofNestedMessage); 623 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofBytes, message.OneofFieldCase); 624 625 message.OneofUint32 = 20; 626 Assert.AreEqual("", message.OneofString); 627 Assert.AreEqual(20, message.OneofUint32); 628 Assert.AreEqual(ByteString.Empty, message.OneofBytes); 629 Assert.IsNull(message.OneofNestedMessage); 630 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase); 631 632 var nestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 25 }; 633 message.OneofNestedMessage = nestedMessage; 634 Assert.AreEqual("", message.OneofString); 635 Assert.AreEqual(0, message.OneofUint32); 636 Assert.AreEqual(ByteString.Empty, message.OneofBytes); 637 Assert.AreEqual(nestedMessage, message.OneofNestedMessage); 638 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofNestedMessage, message.OneofFieldCase); 639 640 message.ClearOneofField(); 641 Assert.AreEqual("", message.OneofString); 642 Assert.AreEqual(0, message.OneofUint32); 643 Assert.AreEqual(ByteString.Empty, message.OneofBytes); 644 Assert.IsNull(message.OneofNestedMessage); 645 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.None, message.OneofFieldCase); 646 } 647 648 [Test] Oneof_DefaultValuesNotEqual()649 public void Oneof_DefaultValuesNotEqual() 650 { 651 var message1 = new TestAllTypes { OneofString = "" }; 652 var message2 = new TestAllTypes { OneofUint32 = 0 }; 653 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofString, message1.OneofFieldCase); 654 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message2.OneofFieldCase); 655 Assert.AreNotEqual(message1, message2); 656 } 657 658 [Test] OneofSerialization_NonDefaultValue()659 public void OneofSerialization_NonDefaultValue() 660 { 661 var message = new TestAllTypes(); 662 message.OneofString = "this would take a bit of space"; 663 message.OneofUint32 = 10; 664 var bytes = message.ToByteArray(); 665 Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string! 666 667 MessageParsingHelpers.AssertWritingMessage(message); 668 669 MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage => 670 { 671 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase); 672 }); 673 } 674 675 [Test] OneofSerialization_DefaultValue()676 public void OneofSerialization_DefaultValue() 677 { 678 var message = new TestAllTypes(); 679 message.OneofString = "this would take a bit of space"; 680 message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized 681 var bytes = message.ToByteArray(); 682 Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized 683 684 MessageParsingHelpers.AssertWritingMessage(message); 685 686 MessageParsingHelpers.AssertRoundtrip(TestAllTypes.Parser, message, parsedMessage => 687 { 688 Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, parsedMessage.OneofFieldCase); 689 }); 690 } 691 692 [Test] DiscardUnknownFields_RealDataStillRead()693 public void DiscardUnknownFields_RealDataStillRead() 694 { 695 var message = SampleMessages.CreateFullTestAllTypes(); 696 var stream = new MemoryStream(); 697 var output = new CodedOutputStream(stream); 698 var unusedFieldNumber = 23456; 699 Assert.IsFalse(TestAllTypes.Descriptor.Fields.InDeclarationOrder().Select(x => x.FieldNumber).Contains(unusedFieldNumber)); 700 output.WriteTag(unusedFieldNumber, WireFormat.WireType.LengthDelimited); 701 output.WriteString("ignore me"); 702 message.WriteTo(output); 703 output.Flush(); 704 705 MessageParsingHelpers.AssertReadingMessage( 706 TestAllTypes.Parser, 707 stream.ToArray(), 708 parsed => 709 { 710 // TODO(jieluo): Add test back when DiscardUnknownFields API is supported. 711 // Assert.AreEqual(message, parsed); 712 }); 713 } 714 715 [Test] DiscardUnknownFields_AllTypes()716 public void DiscardUnknownFields_AllTypes() 717 { 718 // Simple way of ensuring we can skip all kinds of fields. 719 var data = SampleMessages.CreateFullTestAllTypes().ToByteArray(); 720 var empty = Empty.Parser.ParseFrom(data); 721 722 MessageParsingHelpers.AssertReadingMessage( 723 Empty.Parser, 724 data, 725 parsed => 726 { 727 // TODO(jieluo): Add test back when DiscardUnknownFields API is supported. 728 // Assert.AreNotEqual(new Empty(), empty); 729 }); 730 } 731 732 // This was originally seen as a conformance test failure. 733 [Test] TruncatedMessageFieldThrows()734 public void TruncatedMessageFieldThrows() 735 { 736 // 130, 3 is the message tag 737 // 1 is the data length - but there's no data. 738 var data = new byte[] { 130, 3, 1 }; 739 MessageParsingHelpers.AssertReadingMessageThrows<TestAllTypes, InvalidProtocolBufferException>(TestAllTypes.Parser, data); 740 } 741 742 /// <summary> 743 /// Demonstrates current behaviour with an extraneous end group tag - see issue 688 744 /// for details; we may want to change this. 745 /// </summary> 746 [Test] ExtraEndGroupThrows()747 public void ExtraEndGroupThrows() 748 { 749 var message = SampleMessages.CreateFullTestAllTypes(); 750 var stream = new MemoryStream(); 751 var output = new CodedOutputStream(stream); 752 753 output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32); 754 output.WriteFixed32(123); 755 output.WriteTag(100, WireFormat.WireType.EndGroup); 756 757 output.Flush(); 758 759 stream.Position = 0; 760 MessageParsingHelpers.AssertReadingMessageThrows<TestAllTypes, InvalidProtocolBufferException>(TestAllTypes.Parser, stream.ToArray()); 761 } 762 763 [Test] CustomDiagnosticMessage_DirectToStringCall()764 public void CustomDiagnosticMessage_DirectToStringCall() 765 { 766 var message = new ForeignMessage { C = 31 }; 767 Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString()); 768 Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message)); 769 } 770 771 [Test] CustomDiagnosticMessage_Nested()772 public void CustomDiagnosticMessage_Nested() 773 { 774 var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } }; 775 Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString()); 776 Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message)); 777 } 778 779 [Test] CustomDiagnosticMessage_DirectToTextWriterCall()780 public void CustomDiagnosticMessage_DirectToTextWriterCall() 781 { 782 var message = new ForeignMessage { C = 31 }; 783 var writer = new StringWriter(); 784 JsonFormatter.Default.Format(message, writer); 785 Assert.AreEqual("{ \"c\": 31 }", writer.ToString()); 786 } 787 788 [Test] NaNComparisons()789 public void NaNComparisons() 790 { 791 var message1 = new TestAllTypes { SingleDouble = SampleNaNs.Regular }; 792 var message2 = new TestAllTypes { SingleDouble = SampleNaNs.PayloadFlipped }; 793 var message3 = new TestAllTypes { SingleDouble = SampleNaNs.Regular }; 794 795 EqualityTester.AssertInequality(message1, message2); 796 EqualityTester.AssertEquality(message1, message3); 797 } 798 } 799 }