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