blob: 5694754e38b0efbd562d24d7cdecd39955612613 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001#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);
Austin Schuh40c16522018-10-28 20:27:54 -070069 Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum);
Brian Silverman9c614bc2016-02-15 20:20:02 -050070 Assert.IsNull(message.SingleForeignMessage);
Austin Schuh40c16522018-10-28 20:27:54 -070071 Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum);
Brian Silverman9c614bc2016-02-15 20:20:02 -050072 Assert.IsNull(message.SingleImportMessage);
73 Assert.AreEqual(0, message.SingleInt32);
74 Assert.AreEqual(0L, message.SingleInt64);
Austin Schuh40c16522018-10-28 20:27:54 -070075 Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum);
Brian Silverman9c614bc2016-02-15 20:20:02 -050076 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,
Austin Schuh40c16522018-10-28 20:27:54 -0700148 SingleForeignEnum = ForeignEnum.ForeignBar,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500149 SingleForeignMessage = new ForeignMessage { C = 10 },
Austin Schuh40c16522018-10-28 20:27:54 -0700150 SingleImportEnum = ImportEnum.ImportBaz,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500151 SingleImportMessage = new ImportMessage { D = 20 },
152 SingleInt32 = 100,
153 SingleInt64 = 3210987654321,
Austin Schuh40c16522018-10-28 20:27:54 -0700154 SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500155 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 },
Austin Schuh40c16522018-10-28 20:27:54 -0700182 RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar },
Brian Silverman9c614bc2016-02-15 20:20:02 -0500183 RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } },
Austin Schuh40c16522018-10-28 20:27:54 -0700184 RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified },
Brian Silverman9c614bc2016-02-15 20:20:02 -0500185 RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } },
186 RepeatedInt32 = { 100, 200 },
187 RepeatedInt64 = { 3210987654321, long.MaxValue },
Austin Schuh40c16522018-10-28 20:27:54 -0700188 RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg },
Brian Silverman9c614bc2016-02-15 20:20:02 -0500189 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 = {
Austin Schuh40c16522018-10-28 20:27:54 -0700227 { 1, MapEnum.Bar },
228 { 2000, MapEnum.Foo }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500229 }
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 }
Austin Schuh40c16522018-10-28 20:27:54 -0700252
Brian Silverman9c614bc2016-02-15 20:20:02 -0500253 [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,
Austin Schuh40c16522018-10-28 20:27:54 -0700452 SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo,
Brian Silverman9c614bc2016-02-15 20:20:02 -0500453 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 },
Austin Schuh40c16522018-10-28 20:27:54 -0700482 RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg },
Brian Silverman9c614bc2016-02-15 20:20:02 -0500483 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]
Austin Schuh40c16522018-10-28 20:27:54 -0700641 public void DiscardUnknownFields_RealDataStillRead()
Brian Silverman9c614bc2016-02-15 20:20:02 -0500642 {
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);
Austin Schuh40c16522018-10-28 20:27:54 -0700655 // TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
656 // Assert.AreEqual(message, parsed);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500657 }
658
659 [Test]
Austin Schuh40c16522018-10-28 20:27:54 -0700660 public void DiscardUnknownFields_AllTypes()
Brian Silverman9c614bc2016-02-15 20:20:02 -0500661 {
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);
Austin Schuh40c16522018-10-28 20:27:54 -0700665 // TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
666 // Assert.AreNotEqual(new Empty(), empty);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500667 }
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.
Austin Schuh40c16522018-10-28 20:27:54 -0700675 var data = new byte[] { 130, 3, 1 };
Brian Silverman9c614bc2016-02-15 20:20:02 -0500676 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]
Austin Schuh40c16522018-10-28 20:27:54 -0700684 public void ExtraEndGroupThrows()
Brian Silverman9c614bc2016-02-15 20:20:02 -0500685 {
686 var message = SampleMessages.CreateFullTestAllTypes();
687 var stream = new MemoryStream();
688 var output = new CodedOutputStream(stream);
689
Brian Silverman9c614bc2016-02-15 20:20:02 -0500690 output.WriteTag(TestAllTypes.SingleFixed32FieldNumber, WireFormat.WireType.Fixed32);
691 output.WriteFixed32(123);
Austin Schuh40c16522018-10-28 20:27:54 -0700692 output.WriteTag(100, WireFormat.WireType.EndGroup);
Brian Silverman9c614bc2016-02-15 20:20:02 -0500693
694 output.Flush();
695
696 stream.Position = 0;
Austin Schuh40c16522018-10-28 20:27:54 -0700697 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream));
Brian Silverman9c614bc2016-02-15 20:20:02 -0500698 }
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 }
Austin Schuh40c16522018-10-28 20:27:54 -0700715
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 [Test]
726 public void NaNComparisons()
727 {
728 var message1 = new TestAllTypes { SingleDouble = SampleNaNs.Regular };
729 var message2 = new TestAllTypes { SingleDouble = SampleNaNs.PayloadFlipped };
730 var message3 = new TestAllTypes { SingleDouble = SampleNaNs.Regular };
731
732 EqualityTester.AssertInequality(message1, message2);
733 EqualityTester.AssertEquality(message1, message3);
734 }
Brian Silverman9c614bc2016-02-15 20:20:02 -0500735 }
Austin Schuh40c16522018-10-28 20:27:54 -0700736}