blob: 95bfcf5aff5913a9c5cfb0cf461a180e225478fe [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]
66 public void SerializedSize()
67 {
68 TestAllTypes message = TestUtil.GetAllSet();
69 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
70
71 Assert.AreEqual(message.SerializedSize, abstractMessage.SerializedSize);
72 }
73
74 [Test]
75 public void Serialization()
76 {
77 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
78 TestUtil.AssertAllFieldsSet(TestAllTypes.ParseFrom(abstractMessage.ToByteString()));
79 Assert.AreEqual(TestUtil.GetAllSet().ToByteString(), abstractMessage.ToByteString());
80 }
81
82 [Test]
83 public void Parsing()
84 {
85 IBuilder builder = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder());
86 AbstractMessageWrapper message =
87 (AbstractMessageWrapper) builder.WeakMergeFrom(TestUtil.GetAllSet().ToByteString()).WeakBuild();
88 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
89 }
90
91 [Test]
92 public void PackedSerialization()
93 {
94 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetPackedSet());
95 TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseFrom(abstractMessage.ToByteString()));
96 Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), abstractMessage.ToByteString());
97 }
98
99 [Test]
100 public void PackedParsing()
101 {
102 AbstractMessageWrapper.Builder builder = new AbstractMessageWrapper.Builder(TestPackedTypes.CreateBuilder());
103 AbstractMessageWrapper message = builder.MergeFrom(TestUtil.GetPackedSet().ToByteString()).Build();
csharptest6da31702011-06-04 12:52:57 -0500104 TestUtil.AssertPackedFieldsSet((TestPackedTypes)message.WrappedMessage);
105 }
106
107 [Test]
108 public void UnpackedParsingOfPackedInput()
109 {
110 byte[] bytes = TestUtil.GetPackedSet().ToByteArray();
111 TestUnpackedTypes message = TestUnpackedTypes.ParseFrom(bytes);
112 TestUtil.AssertUnpackedFieldsSet(message);
113 }
114
115 [Test]
116 public void PackedParsingOfUnpackedInput()
117 {
118 byte[] bytes = TestUnpackedTypes.ParseFrom(TestUtil.GetPackedSet().ToByteArray()).ToByteArray();
119 TestPackedTypes message = TestPackedTypes.ParseFrom(bytes);
120 TestUtil.AssertPackedFieldsSet(message);
121 }
122
123 [Test]
124 public void UnpackedParsingOfPackedInputExtensions()
125 {
126 byte[] bytes = TestUtil.GetPackedSet().ToByteArray();
127 ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
128 UnitTestProtoFile.RegisterAllExtensions(registry);
129 TestUnpackedExtensions message = TestUnpackedExtensions.ParseFrom(bytes, registry);
130 TestUtil.AssertUnpackedExtensionsSet(message);
131 }
132
133 [Test]
134 public void PackedParsingOfUnpackedInputExtensions()
135 {
136 byte[] bytes = TestUnpackedTypes.ParseFrom(TestUtil.GetPackedSet().ToByteArray()).ToByteArray();
137 ExtensionRegistry registry = ExtensionRegistry.CreateInstance();
138 UnitTestProtoFile.RegisterAllExtensions(registry);
139 TestPackedExtensions message = TestPackedExtensions.ParseFrom(bytes, registry);
140 TestUtil.AssertPackedExtensionsSet(message);
csharptest71f662c2011-05-20 15:15:34 -0500141 }
142
143 [Test]
144 public void OptimizedForSize()
145 {
146 // We're mostly only Checking that this class was compiled successfully.
147 TestOptimizedForSize message = TestOptimizedForSize.CreateBuilder().SetI(1).Build();
148 message = TestOptimizedForSize.ParseFrom(message.ToByteString());
149 Assert.AreEqual(2, message.SerializedSize);
150 }
151
152 // -----------------------------------------------------------------
153 // Tests for isInitialized().
154
155 private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance;
156
157 private static readonly TestRequired TestRequiredInitialized =
158 TestRequired.CreateBuilder().SetA(1).SetB(2).SetC(3).Build();
159
160 [Test]
161 public void IsInitialized()
162 {
163 TestRequired.Builder builder = TestRequired.CreateBuilder();
164 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
165
166 Assert.IsFalse(abstractBuilder.IsInitialized);
167 builder.A = 1;
168 Assert.IsFalse(abstractBuilder.IsInitialized);
169 builder.B = 1;
170 Assert.IsFalse(abstractBuilder.IsInitialized);
171 builder.C = 1;
172 Assert.IsTrue(abstractBuilder.IsInitialized);
173 }
174
175 [Test]
176 public void ForeignIsInitialized()
177 {
178 TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder();
179 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
180
181 Assert.IsTrue(abstractBuilder.IsInitialized);
182
183 builder.SetOptionalMessage(TestRequiredUninitialized);
184 Assert.IsFalse(abstractBuilder.IsInitialized);
185
186 builder.SetOptionalMessage(TestRequiredInitialized);
187 Assert.IsTrue(abstractBuilder.IsInitialized);
188
189 builder.AddRepeatedMessage(TestRequiredUninitialized);
190 Assert.IsFalse(abstractBuilder.IsInitialized);
191
192 builder.SetRepeatedMessage(0, TestRequiredInitialized);
193 Assert.IsTrue(abstractBuilder.IsInitialized);
194 }
195
196 // -----------------------------------------------------------------
197 // Tests for mergeFrom
198
199 private static readonly TestAllTypes MergeSource = TestAllTypes.CreateBuilder()
200 .SetOptionalInt32(1)
201 .SetOptionalString("foo")
202 .SetOptionalForeignMessage(ForeignMessage.DefaultInstance)
203 .AddRepeatedString("bar")
204 .Build();
205
206 private static readonly TestAllTypes MergeDest = TestAllTypes.CreateBuilder()
207 .SetOptionalInt64(2)
208 .SetOptionalString("baz")
209 .SetOptionalForeignMessage(ForeignMessage.CreateBuilder().SetC(3).Build())
210 .AddRepeatedString("qux")
211 .Build();
212
213 private const string MergeResultText = "optional_int32: 1\n" +
214 "optional_int64: 2\n" +
215 "optional_string: \"foo\"\n" +
216 "optional_foreign_message {\n" +
217 " c: 3\n" +
218 "}\n" +
219 "repeated_string: \"qux\"\n" +
220 "repeated_string: \"bar\"\n";
221
222 [Test]
223 public void MergeFrom()
224 {
225 AbstractMessageWrapper result = (AbstractMessageWrapper)
226 new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(MergeDest))
227 .MergeFrom(MergeSource)
228 .Build();
229
230 Assert.AreEqual(MergeResultText, result.ToString());
231 }
232
233 // -----------------------------------------------------------------
234 // Tests for equals and hashCode
235
236 [Test]
237 public void EqualsAndHashCode()
238 {
239 TestAllTypes a = TestUtil.GetAllSet();
240 TestAllTypes b = TestAllTypes.CreateBuilder().Build();
241 TestAllTypes c = TestAllTypes.CreateBuilder(b).AddRepeatedString("x").Build();
242 TestAllTypes d = TestAllTypes.CreateBuilder(c).AddRepeatedString("y").Build();
243 TestAllExtensions e = TestUtil.GetAllExtensionsSet();
244 TestAllExtensions f = TestAllExtensions.CreateBuilder(e)
245 .AddExtension(UnitTestProtoFile.RepeatedInt32Extension, 999).Build();
246
247 CheckEqualsIsConsistent(a);
248 CheckEqualsIsConsistent(b);
249 CheckEqualsIsConsistent(c);
250 CheckEqualsIsConsistent(d);
251 CheckEqualsIsConsistent(e);
252 CheckEqualsIsConsistent(f);
253
254 CheckNotEqual(a, b);
255 CheckNotEqual(a, c);
256 CheckNotEqual(a, d);
257 CheckNotEqual(a, e);
258 CheckNotEqual(a, f);
259
260 CheckNotEqual(b, c);
261 CheckNotEqual(b, d);
262 CheckNotEqual(b, e);
263 CheckNotEqual(b, f);
264
265 CheckNotEqual(c, d);
266 CheckNotEqual(c, e);
267 CheckNotEqual(c, f);
268
269 CheckNotEqual(d, e);
270 CheckNotEqual(d, f);
271
272 CheckNotEqual(e, f);
273
274 // Deserializing into the TestEmptyMessage such that every field is an UnknownFieldSet.Field
275 TestEmptyMessage eUnknownFields = TestEmptyMessage.ParseFrom(e.ToByteArray());
276 TestEmptyMessage fUnknownFields = TestEmptyMessage.ParseFrom(f.ToByteArray());
277 CheckNotEqual(eUnknownFields, fUnknownFields);
278 CheckEqualsIsConsistent(eUnknownFields);
279 CheckEqualsIsConsistent(fUnknownFields);
280
281 // Subseqent reconstitutions should be identical
282 TestEmptyMessage eUnknownFields2 = TestEmptyMessage.ParseFrom(e.ToByteArray());
283 CheckEqualsIsConsistent(eUnknownFields, eUnknownFields2);
284 }
285
286 /// <summary>
287 /// Asserts that the given protos are equal and have the same hash code.
288 /// </summary>
289 private static void CheckEqualsIsConsistent(IMessage message)
290 {
291 // Object should be equal to itself.
292 Assert.AreEqual(message, message);
293
294 // Object should be equal to a dynamic copy of itself.
295 DynamicMessage dynamic = DynamicMessage.CreateBuilder(message).Build();
296 CheckEqualsIsConsistent(message, dynamic);
297 }
298
299 /// <summary>
300 /// Asserts that the given protos are equal and have the same hash code.
301 /// </summary>
302 private static void CheckEqualsIsConsistent(IMessage message1, IMessage message2)
303 {
304 Assert.AreEqual(message1, message2);
305 Assert.AreEqual(message2, message1);
306 Assert.AreEqual(message2.GetHashCode(), message1.GetHashCode());
307 }
308
309 /// <summary>
310 /// Asserts that the given protos are not equal and have different hash codes.
311 /// </summary>
312 /// <remarks>
313 /// It's valid for non-equal objects to have the same hash code, so
314 /// this test is stricter than it needs to be. However, this should happen
315 /// relatively rarely. (If this test fails, it's probably still due to a bug.)
316 /// </remarks>
317 private static void CheckNotEqual(IMessage m1, IMessage m2)
318 {
319 String equalsError = string.Format("{0} should not be equal to {1}", m1, m2);
320 Assert.IsFalse(m1.Equals(m2), equalsError);
321 Assert.IsFalse(m2.Equals(m1), equalsError);
322
323 Assert.IsFalse(m1.GetHashCode() == m2.GetHashCode(),
324 string.Format("{0} should have a different hash code from {1}", m1, m2));
325 }
326
327 /// <summary>
328 /// Extends AbstractMessage and wraps some other message object. The methods
329 /// of the Message interface which aren't explicitly implemented by
330 /// AbstractMessage are forwarded to the wrapped object. This allows us to
331 /// test that AbstractMessage's implementations work even if the wrapped
332 /// object does not use them.
333 /// </summary>
334 private class AbstractMessageWrapper : AbstractMessage<AbstractMessageWrapper, AbstractMessageWrapper.Builder>
335 {
336 private readonly IMessage wrappedMessage;
337
338 public IMessage WrappedMessage
339 {
340 get { return wrappedMessage; }
341 }
342
343 public AbstractMessageWrapper(IMessage wrappedMessage)
344 {
345 this.wrappedMessage = wrappedMessage;
346 }
347
348 public override MessageDescriptor DescriptorForType
349 {
350 get { return wrappedMessage.DescriptorForType; }
351 }
352
353 public override AbstractMessageWrapper DefaultInstanceForType
354 {
355 get { return new AbstractMessageWrapper(wrappedMessage.WeakDefaultInstanceForType); }
356 }
357
358 public override IDictionary<FieldDescriptor, object> AllFields
359 {
360 get { return wrappedMessage.AllFields; }
361 }
362
363 public override bool HasField(FieldDescriptor field)
364 {
365 return wrappedMessage.HasField(field);
366 }
367
368 public override object this[FieldDescriptor field]
369 {
370 get { return wrappedMessage[field]; }
371 }
372
373 public override object this[FieldDescriptor field, int index]
374 {
375 get { return wrappedMessage[field, index]; }
376 }
377
378 public override int GetRepeatedFieldCount(FieldDescriptor field)
379 {
380 return wrappedMessage.GetRepeatedFieldCount(field);
381 }
382
383 public override UnknownFieldSet UnknownFields
384 {
385 get { return wrappedMessage.UnknownFields; }
386 }
387
388 public override Builder CreateBuilderForType()
389 {
390 return new Builder(wrappedMessage.WeakCreateBuilderForType());
391 }
392
393 public override Builder ToBuilder()
394 {
395 return new Builder(wrappedMessage.WeakToBuilder());
396 }
397
398 internal class Builder : AbstractBuilder<AbstractMessageWrapper, Builder>
399 {
400 private readonly IBuilder wrappedBuilder;
401
402 protected override Builder ThisBuilder
403 {
404 get { return this; }
405 }
406
407 internal Builder(IBuilder wrappedBuilder)
408 {
409 this.wrappedBuilder = wrappedBuilder;
410 }
411
412 public override Builder MergeFrom(AbstractMessageWrapper other)
413 {
414 wrappedBuilder.WeakMergeFrom(other.wrappedMessage);
415 return this;
416 }
417
418 public override bool IsInitialized
419 {
420 get { return wrappedBuilder.IsInitialized; }
421 }
422
423 public override IDictionary<FieldDescriptor, object> AllFields
424 {
425 get { return wrappedBuilder.AllFields; }
426 }
427
428 public override object this[FieldDescriptor field]
429 {
430 get { return wrappedBuilder[field]; }
431 set { wrappedBuilder[field] = value; }
432 }
433
434 public override MessageDescriptor DescriptorForType
435 {
436 get { return wrappedBuilder.DescriptorForType; }
437 }
438
439 public override int GetRepeatedFieldCount(FieldDescriptor field)
440 {
441 return wrappedBuilder.GetRepeatedFieldCount(field);
442 }
443
444 public override object this[FieldDescriptor field, int index]
445 {
446 get { return wrappedBuilder[field, index]; }
447 set { wrappedBuilder[field, index] = value; }
448 }
449
450 public override bool HasField(FieldDescriptor field)
451 {
452 return wrappedBuilder.HasField(field);
453 }
454
455 public override UnknownFieldSet UnknownFields
456 {
457 get { return wrappedBuilder.UnknownFields; }
458 set { wrappedBuilder.UnknownFields = value; }
459 }
460
461 public override AbstractMessageWrapper Build()
462 {
463 return new AbstractMessageWrapper(wrappedBuilder.WeakBuild());
464 }
465
466 public override AbstractMessageWrapper BuildPartial()
467 {
468 return new AbstractMessageWrapper(wrappedBuilder.WeakBuildPartial());
469 }
470
471 public override Builder Clone()
472 {
473 return new Builder(wrappedBuilder.WeakClone());
474 }
475
476 public override AbstractMessageWrapper DefaultInstanceForType
477 {
478 get { return new AbstractMessageWrapper(wrappedBuilder.WeakDefaultInstanceForType); }
479 }
480
481 public override Builder ClearField(FieldDescriptor field)
482 {
483 wrappedBuilder.WeakClearField(field);
484 return this;
485 }
486
487 public override Builder AddRepeatedField(FieldDescriptor field, object value)
488 {
489 wrappedBuilder.WeakAddRepeatedField(field, value);
490 return this;
491 }
492
493 public override IBuilder CreateBuilderForField(FieldDescriptor field)
494 {
495 wrappedBuilder.CreateBuilderForField(field);
496 return this;
497 }
498
499 public override Builder MergeFrom(IMessage other)
500 {
501 wrappedBuilder.WeakMergeFrom(other);
502 return this;
503 }
504
csharptest17699c22011-06-03 21:57:15 -0500505 public override Builder MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry)
csharptest71f662c2011-05-20 15:15:34 -0500506 {
507 wrappedBuilder.WeakMergeFrom(input, extensionRegistry);
508 return this;
509 }
510 }
511 }
512 }
513}