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