• 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 // 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 }