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