• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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