blob: a502a6cd8507d59b5d1e431935c3de2eef7812bb [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
38using System.Collections.Generic;
csharptest6da31702011-06-04 12:52:57 -050039using System.IO;
csharptest71f662c2011-05-20 15:15:34 -050040using Google.ProtocolBuffers.Descriptors;
41using NUnit.Framework;
42using Google.ProtocolBuffers.TestProtos;
43
44namespace Google.ProtocolBuffers
45{
46 [TestFixture]
47 public class AbstractMessageTest
48 {
49 [Test]
50 public void Clear()
51 {
52 AbstractMessageWrapper message =
53 new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(TestUtil.GetAllSet())).Clear().Build();
54 TestUtil.AssertClear((TestAllTypes) message.WrappedMessage);
55 }
56
57 [Test]
58 public void Copy()
59 {
60 AbstractMessageWrapper message =
61 new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder()).MergeFrom(TestUtil.GetAllSet()).Build();
62 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
63 }
64
65 [Test]
csharptestced18e12011-06-09 19:47:56 -050066 public void CreateAndBuild()
67 {
68 TestAllTypes.CreateBuilder()
69 .Build();
70 }
71
72 [Test]
csharptest71f662c2011-05-20 15:15:34 -050073 public void SerializedSize()
74 {
75 TestAllTypes message = TestUtil.GetAllSet();
76 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
77
78 Assert.AreEqual(message.SerializedSize, abstractMessage.SerializedSize);
79 }
80
81 [Test]
82 public void Serialization()
83 {
84 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
85 TestUtil.AssertAllFieldsSet(TestAllTypes.ParseFrom(abstractMessage.ToByteString()));
86 Assert.AreEqual(TestUtil.GetAllSet().ToByteString(), abstractMessage.ToByteString());
87 }
88
89 [Test]
90 public void Parsing()
91 {
92 IBuilder builder = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder());
93 AbstractMessageWrapper message =
94 (AbstractMessageWrapper) builder.WeakMergeFrom(TestUtil.GetAllSet().ToByteString()).WeakBuild();
95 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
96 }
97
98 [Test]
99 public void PackedSerialization()
100 {
101 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetPackedSet());
102 TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseFrom(abstractMessage.ToByteString()));
103 Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), abstractMessage.ToByteString());
104 }
105
106 [Test]
107 public void PackedParsing()
108 {
109 AbstractMessageWrapper.Builder builder = new AbstractMessageWrapper.Builder(TestPackedTypes.CreateBuilder());
110 AbstractMessageWrapper message = builder.MergeFrom(TestUtil.GetPackedSet().ToByteString()).Build();
csharptest6da31702011-06-04 12:52:57 -0500111 TestUtil.AssertPackedFieldsSet((TestPackedTypes)message.WrappedMessage);
112 }
113
114 [Test]
115 public void UnpackedParsingOfPackedInput()
116 {
117 byte[] bytes = TestUtil.GetPackedSet().ToByteArray();
118 TestUnpackedTypes message = TestUnpackedTypes.ParseFrom(bytes);
119 TestUtil.AssertUnpackedFieldsSet(message);
120 }
121
122 [Test]
123 public void PackedParsingOfUnpackedInput()
124 {
125 byte[] bytes = TestUnpackedTypes.ParseFrom(TestUtil.GetPackedSet().ToByteArray()).ToByteArray();
126 TestPackedTypes message = TestPackedTypes.ParseFrom(bytes);
127 TestUtil.AssertPackedFieldsSet(message);
128 }
129
130 [Test]
131 public void UnpackedParsingOfPackedInputExtensions()
132 {
133 byte[] bytes = TestUtil.GetPackedSet().ToByteArray();
134 ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
135 UnitTestProtoFile.RegisterAllExtensions(registry);
csharptest08c84b92011-10-01 12:00:23 -0500136 UnitTestExtrasProtoFile.RegisterAllExtensions(registry);
csharptest6da31702011-06-04 12:52:57 -0500137 TestUnpackedExtensions message = TestUnpackedExtensions.ParseFrom(bytes, registry);
138 TestUtil.AssertUnpackedExtensionsSet(message);
139 }
140
141 [Test]
142 public void PackedParsingOfUnpackedInputExtensions()
143 {
144 byte[] bytes = TestUnpackedTypes.ParseFrom(TestUtil.GetPackedSet().ToByteArray()).ToByteArray();
145 ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
146 UnitTestProtoFile.RegisterAllExtensions(registry);
147 TestPackedExtensions message = TestPackedExtensions.ParseFrom(bytes, registry);
148 TestUtil.AssertPackedExtensionsSet(message);
csharptest71f662c2011-05-20 15:15:34 -0500149 }
150
151 [Test]
152 public void OptimizedForSize()
153 {
154 // We're mostly only Checking that this class was compiled successfully.
155 TestOptimizedForSize message = TestOptimizedForSize.CreateBuilder().SetI(1).Build();
156 message = TestOptimizedForSize.ParseFrom(message.ToByteString());
157 Assert.AreEqual(2, message.SerializedSize);
158 }
159
160 // -----------------------------------------------------------------
161 // Tests for isInitialized().
162
163 private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance;
164
165 private static readonly TestRequired TestRequiredInitialized =
166 TestRequired.CreateBuilder().SetA(1).SetB(2).SetC(3).Build();
167
168 [Test]
169 public void IsInitialized()
170 {
171 TestRequired.Builder builder = TestRequired.CreateBuilder();
172 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
173
174 Assert.IsFalse(abstractBuilder.IsInitialized);
175 builder.A = 1;
176 Assert.IsFalse(abstractBuilder.IsInitialized);
177 builder.B = 1;
178 Assert.IsFalse(abstractBuilder.IsInitialized);
179 builder.C = 1;
180 Assert.IsTrue(abstractBuilder.IsInitialized);
181 }
182
183 [Test]
184 public void ForeignIsInitialized()
185 {
186 TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder();
187 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
188
189 Assert.IsTrue(abstractBuilder.IsInitialized);
190
191 builder.SetOptionalMessage(TestRequiredUninitialized);
192 Assert.IsFalse(abstractBuilder.IsInitialized);
193
194 builder.SetOptionalMessage(TestRequiredInitialized);
195 Assert.IsTrue(abstractBuilder.IsInitialized);
196
197 builder.AddRepeatedMessage(TestRequiredUninitialized);
198 Assert.IsFalse(abstractBuilder.IsInitialized);
199
200 builder.SetRepeatedMessage(0, TestRequiredInitialized);
201 Assert.IsTrue(abstractBuilder.IsInitialized);
202 }
203
204 // -----------------------------------------------------------------
205 // Tests for mergeFrom
206
207 private static readonly TestAllTypes MergeSource = TestAllTypes.CreateBuilder()
208 .SetOptionalInt32(1)
209 .SetOptionalString("foo")
210 .SetOptionalForeignMessage(ForeignMessage.DefaultInstance)
211 .AddRepeatedString("bar")
212 .Build();
213
214 private static readonly TestAllTypes MergeDest = TestAllTypes.CreateBuilder()
215 .SetOptionalInt64(2)
216 .SetOptionalString("baz")
217 .SetOptionalForeignMessage(ForeignMessage.CreateBuilder().SetC(3).Build())
218 .AddRepeatedString("qux")
219 .Build();
220
221 private const string MergeResultText = "optional_int32: 1\n" +
222 "optional_int64: 2\n" +
223 "optional_string: \"foo\"\n" +
224 "optional_foreign_message {\n" +
225 " c: 3\n" +
226 "}\n" +
227 "repeated_string: \"qux\"\n" +
228 "repeated_string: \"bar\"\n";
229
230 [Test]
231 public void MergeFrom()
232 {
233 AbstractMessageWrapper result = (AbstractMessageWrapper)
234 new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(MergeDest))
235 .MergeFrom(MergeSource)
236 .Build();
237
238 Assert.AreEqual(MergeResultText, result.ToString());
239 }
240
241 // -----------------------------------------------------------------
242 // Tests for equals and hashCode
243
244 [Test]
245 public void EqualsAndHashCode()
246 {
247 TestAllTypes a = TestUtil.GetAllSet();
248 TestAllTypes b = TestAllTypes.CreateBuilder().Build();
249 TestAllTypes c = TestAllTypes.CreateBuilder(b).AddRepeatedString("x").Build();
250 TestAllTypes d = TestAllTypes.CreateBuilder(c).AddRepeatedString("y").Build();
251 TestAllExtensions e = TestUtil.GetAllExtensionsSet();
252 TestAllExtensions f = TestAllExtensions.CreateBuilder(e)
253 .AddExtension(UnitTestProtoFile.RepeatedInt32Extension, 999).Build();
254
255 CheckEqualsIsConsistent(a);
256 CheckEqualsIsConsistent(b);
257 CheckEqualsIsConsistent(c);
258 CheckEqualsIsConsistent(d);
259 CheckEqualsIsConsistent(e);
260 CheckEqualsIsConsistent(f);
261
262 CheckNotEqual(a, b);
263 CheckNotEqual(a, c);
264 CheckNotEqual(a, d);
265 CheckNotEqual(a, e);
266 CheckNotEqual(a, f);
267
268 CheckNotEqual(b, c);
269 CheckNotEqual(b, d);
270 CheckNotEqual(b, e);
271 CheckNotEqual(b, f);
272
273 CheckNotEqual(c, d);
274 CheckNotEqual(c, e);
275 CheckNotEqual(c, f);
276
277 CheckNotEqual(d, e);
278 CheckNotEqual(d, f);
279
280 CheckNotEqual(e, f);
281
282 // Deserializing into the TestEmptyMessage such that every field is an UnknownFieldSet.Field
283 TestEmptyMessage eUnknownFields = TestEmptyMessage.ParseFrom(e.ToByteArray());
284 TestEmptyMessage fUnknownFields = TestEmptyMessage.ParseFrom(f.ToByteArray());
285 CheckNotEqual(eUnknownFields, fUnknownFields);
286 CheckEqualsIsConsistent(eUnknownFields);
287 CheckEqualsIsConsistent(fUnknownFields);
288
289 // Subseqent reconstitutions should be identical
290 TestEmptyMessage eUnknownFields2 = TestEmptyMessage.ParseFrom(e.ToByteArray());
291 CheckEqualsIsConsistent(eUnknownFields, eUnknownFields2);
292 }
293
294 /// <summary>
295 /// Asserts that the given protos are equal and have the same hash code.
296 /// </summary>
297 private static void CheckEqualsIsConsistent(IMessage message)
298 {
299 // Object should be equal to itself.
300 Assert.AreEqual(message, message);
301
302 // Object should be equal to a dynamic copy of itself.
303 DynamicMessage dynamic = DynamicMessage.CreateBuilder(message).Build();
304 CheckEqualsIsConsistent(message, dynamic);
305 }
306
307 /// <summary>
308 /// Asserts that the given protos are equal and have the same hash code.
309 /// </summary>
310 private static void CheckEqualsIsConsistent(IMessage message1, IMessage message2)
311 {
312 Assert.AreEqual(message1, message2);
313 Assert.AreEqual(message2, message1);
314 Assert.AreEqual(message2.GetHashCode(), message1.GetHashCode());
315 }
316
317 /// <summary>
318 /// Asserts that the given protos are not equal and have different hash codes.
319 /// </summary>
320 /// <remarks>
321 /// It's valid for non-equal objects to have the same hash code, so
322 /// this test is stricter than it needs to be. However, this should happen
323 /// relatively rarely. (If this test fails, it's probably still due to a bug.)
324 /// </remarks>
325 private static void CheckNotEqual(IMessage m1, IMessage m2)
326 {
327 String equalsError = string.Format("{0} should not be equal to {1}", m1, m2);
328 Assert.IsFalse(m1.Equals(m2), equalsError);
329 Assert.IsFalse(m2.Equals(m1), equalsError);
330
331 Assert.IsFalse(m1.GetHashCode() == m2.GetHashCode(),
332 string.Format("{0} should have a different hash code from {1}", m1, m2));
333 }
334
335 /// <summary>
336 /// Extends AbstractMessage and wraps some other message object. The methods
337 /// of the Message interface which aren't explicitly implemented by
338 /// AbstractMessage are forwarded to the wrapped object. This allows us to
339 /// test that AbstractMessage's implementations work even if the wrapped
340 /// object does not use them.
341 /// </summary>
342 private class AbstractMessageWrapper : AbstractMessage<AbstractMessageWrapper, AbstractMessageWrapper.Builder>
343 {
344 private readonly IMessage wrappedMessage;
345
346 public IMessage WrappedMessage
347 {
348 get { return wrappedMessage; }
349 }
350
351 public AbstractMessageWrapper(IMessage wrappedMessage)
352 {
353 this.wrappedMessage = wrappedMessage;
354 }
355
356 public override MessageDescriptor DescriptorForType
357 {
358 get { return wrappedMessage.DescriptorForType; }
359 }
360
361 public override AbstractMessageWrapper DefaultInstanceForType
362 {
363 get { return new AbstractMessageWrapper(wrappedMessage.WeakDefaultInstanceForType); }
364 }
365
366 public override IDictionary<FieldDescriptor, object> AllFields
367 {
368 get { return wrappedMessage.AllFields; }
369 }
370
371 public override bool HasField(FieldDescriptor field)
372 {
373 return wrappedMessage.HasField(field);
374 }
375
376 public override object this[FieldDescriptor field]
377 {
378 get { return wrappedMessage[field]; }
379 }
380
381 public override object this[FieldDescriptor field, int index]
382 {
383 get { return wrappedMessage[field, index]; }
384 }
385
386 public override int GetRepeatedFieldCount(FieldDescriptor field)
387 {
388 return wrappedMessage.GetRepeatedFieldCount(field);
389 }
390
391 public override UnknownFieldSet UnknownFields
392 {
393 get { return wrappedMessage.UnknownFields; }
394 }
395
396 public override Builder CreateBuilderForType()
397 {
398 return new Builder(wrappedMessage.WeakCreateBuilderForType());
399 }
400
401 public override Builder ToBuilder()
402 {
403 return new Builder(wrappedMessage.WeakToBuilder());
404 }
405
406 internal class Builder : AbstractBuilder<AbstractMessageWrapper, Builder>
407 {
408 private readonly IBuilder wrappedBuilder;
409
410 protected override Builder ThisBuilder
411 {
412 get { return this; }
413 }
414
415 internal Builder(IBuilder wrappedBuilder)
416 {
417 this.wrappedBuilder = wrappedBuilder;
418 }
419
420 public override Builder MergeFrom(AbstractMessageWrapper other)
421 {
422 wrappedBuilder.WeakMergeFrom(other.wrappedMessage);
423 return this;
424 }
425
426 public override bool IsInitialized
427 {
428 get { return wrappedBuilder.IsInitialized; }
429 }
430
431 public override IDictionary<FieldDescriptor, object> AllFields
432 {
433 get { return wrappedBuilder.AllFields; }
434 }
435
436 public override object this[FieldDescriptor field]
437 {
438 get { return wrappedBuilder[field]; }
439 set { wrappedBuilder[field] = value; }
440 }
441
442 public override MessageDescriptor DescriptorForType
443 {
444 get { return wrappedBuilder.DescriptorForType; }
445 }
446
447 public override int GetRepeatedFieldCount(FieldDescriptor field)
448 {
449 return wrappedBuilder.GetRepeatedFieldCount(field);
450 }
451
452 public override object this[FieldDescriptor field, int index]
453 {
454 get { return wrappedBuilder[field, index]; }
455 set { wrappedBuilder[field, index] = value; }
456 }
457
458 public override bool HasField(FieldDescriptor field)
459 {
460 return wrappedBuilder.HasField(field);
461 }
462
463 public override UnknownFieldSet UnknownFields
464 {
465 get { return wrappedBuilder.UnknownFields; }
466 set { wrappedBuilder.UnknownFields = value; }
467 }
468
469 public override AbstractMessageWrapper Build()
470 {
471 return new AbstractMessageWrapper(wrappedBuilder.WeakBuild());
472 }
473
474 public override AbstractMessageWrapper BuildPartial()
475 {
476 return new AbstractMessageWrapper(wrappedBuilder.WeakBuildPartial());
477 }
478
479 public override Builder Clone()
480 {
481 return new Builder(wrappedBuilder.WeakClone());
482 }
483
484 public override AbstractMessageWrapper DefaultInstanceForType
485 {
486 get { return new AbstractMessageWrapper(wrappedBuilder.WeakDefaultInstanceForType); }
487 }
488
489 public override Builder ClearField(FieldDescriptor field)
490 {
491 wrappedBuilder.WeakClearField(field);
492 return this;
493 }
494
495 public override Builder AddRepeatedField(FieldDescriptor field, object value)
496 {
497 wrappedBuilder.WeakAddRepeatedField(field, value);
498 return this;
499 }
500
501 public override IBuilder CreateBuilderForField(FieldDescriptor field)
502 {
503 wrappedBuilder.CreateBuilderForField(field);
504 return this;
505 }
506
507 public override Builder MergeFrom(IMessage other)
508 {
509 wrappedBuilder.WeakMergeFrom(other);
510 return this;
511 }
512
csharptest17699c22011-06-03 21:57:15 -0500513 public override Builder MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry)
csharptest71f662c2011-05-20 15:15:34 -0500514 {
515 wrappedBuilder.WeakMergeFrom(input, extensionRegistry);
516 return this;
517 }
518 }
519 }
520 }
521}