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