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