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
33using System;
34using System.IO;
35using Google.Protobuf.TestProtos;
36using NUnit.Framework;
37using System.Collections;
38using System.Collections.Generic;
39using System.Linq;
40using Google.Protobuf.WellKnownTypes;
41
42namespace Google.Protobuf
43{
44    /// <summary>
45    /// Tests around the generated TestAllTypes message.
46    /// </summary>
47    public class GeneratedMessageTest
48    {
49        [Test]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
641        public void DiscardUnknownFields_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	    // TODO(jieluo): Add test back after DiscardUnknownFields is supported
656            // Assert.AreEqual(message, parsed);
657        }
658
659        [Test]
660        public void DiscardUnknownFields_AllTypes()
661        {
662            // Simple way of ensuring we can skip all kinds of fields.
663            var data = SampleMessages.CreateFullTestAllTypes().ToByteArray();
664            var empty = Empty.Parser.ParseFrom(data);
665	    // TODO(jieluo): Add test back after DiscardUnknownField is supported.
666            // Assert.AreEqual(new Empty(), empty);
667        }
668
669        // This was originally seen as a conformance test failure.
670        [Test]
671        public void TruncatedMessageFieldThrows()
672        {
673            // 130, 3 is the message tag
674            // 1 is the data length - but there's no data.
675            var data = new byte[] { 130, 3, 1 };
676            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(data));
677        }
678
679        /// <summary>
680        /// Demonstrates current behaviour with an extraneous end group tag - see issue 688
681        /// for details; we may want to change this.
682        /// </summary>
683        [Test]
684        public void ExtraEndGroupThrows()
685        {
686            var message = SampleMessages.CreateFullTestAllTypes();
687            var stream = new MemoryStream();
688            var output = new CodedOutputStream(stream);
689
690            output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32);
691            output.WriteFixed32(123);
692            output.WriteTag(100, WireFormat.WireType.EndGroup);
693
694            output.Flush();
695
696            stream.Position = 0;
697            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream));
698        }
699
700        [Test]
701        public void CustomDiagnosticMessage_DirectToStringCall()
702        {
703            var message = new ForeignMessage { C = 31 };
704            Assert.AreEqual("{ \"c\": 31, \"@cInHex\": \"1f\" }", message.ToString());
705            Assert.AreEqual("{ \"c\": 31 }", JsonFormatter.Default.Format(message));
706        }
707
708        [Test]
709        public void CustomDiagnosticMessage_Nested()
710        {
711            var message = new TestAllTypes { SingleForeignMessage = new ForeignMessage { C = 16 } };
712            Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16, \"@cInHex\": \"10\" } }", message.ToString());
713            Assert.AreEqual("{ \"singleForeignMessage\": { \"c\": 16 } }", JsonFormatter.Default.Format(message));
714        }
715
716        [Test]
717        public void CustomDiagnosticMessage_DirectToTextWriterCall()
718        {
719            var message = new ForeignMessage { C = 31 };
720            var writer = new StringWriter();
721            JsonFormatter.Default.Format(message, writer);
722            Assert.AreEqual("{ \"c\": 31 }", writer.ToString());
723        }
724    }
725}
726