blob: b77264f27e57144af4399248a9f44399b45a2617 [file] [log] [blame]
Jon Skeet60c059b2008-10-23 21:17:56 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// http://github.com/jskeet/dotnet-protobufs/
4// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01005// http://code.google.com/p/protobuf/
6//
Jon Skeet60c059b2008-10-23 21:17:56 +01007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
Jon Skeet68036862008-10-22 13:30:34 +010010//
Jon Skeet60c059b2008-10-23 21:17:56 +010011// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17// * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010020//
Jon Skeet60c059b2008-10-23 21:17:56 +010021// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet68036862008-10-22 13:30:34 +010032using System;
33using System.Collections.Generic;
34using Google.ProtocolBuffers.Descriptors;
35using NUnit.Framework;
36using Google.ProtocolBuffers.TestProtos;
37
38namespace Google.ProtocolBuffers {
39 [TestFixture]
40 public class AbstractMessageTest {
41
42 [Test]
43 public void Clear() {
44 AbstractMessageWrapper message = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(TestUtil.GetAllSet())).Clear().Build();
45 TestUtil.AssertClear((TestAllTypes) message.WrappedMessage);
46 }
47
48 [Test]
49 public void Copy() {
50 AbstractMessageWrapper message = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder()).MergeFrom(TestUtil.GetAllSet()).Build();
51 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
52 }
53
54 [Test]
55 public void SerializedSize() {
56 TestAllTypes message = TestUtil.GetAllSet();
57 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
58
59 Assert.AreEqual(message.SerializedSize, abstractMessage.SerializedSize);
60 }
61
62 [Test]
63 public void Serialization() {
64 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
65 TestUtil.AssertAllFieldsSet(TestAllTypes.ParseFrom(abstractMessage.ToByteString()));
66 Assert.AreEqual(TestUtil.GetAllSet().ToByteString(), abstractMessage.ToByteString());
67 }
68
69 [Test]
70 public void Parsing() {
71 IBuilder builder = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder());
72 AbstractMessageWrapper message = (AbstractMessageWrapper) builder.WeakMergeFrom(TestUtil.GetAllSet().ToByteString()).WeakBuild();
73 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
74 }
75
76 [Test]
Jon Skeet25a28582009-02-18 16:06:22 +000077 public void PackedSerialization() {
78 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetPackedSet());
79 TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseFrom(abstractMessage.ToByteString()));
80 Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), abstractMessage.ToByteString());
81 }
82
83 [Test]
84 public void PackedParsing() {
85 AbstractMessageWrapper.Builder builder = new AbstractMessageWrapper.Builder(TestPackedTypes.CreateBuilder());
86 AbstractMessageWrapper message = builder.MergeFrom(TestUtil.GetPackedSet().ToByteString()).Build();
87 TestUtil.AssertPackedFieldsSet((TestPackedTypes)message.WrappedMessage);
88 }
89
90 [Test]
Jon Skeet68036862008-10-22 13:30:34 +010091 public void OptimizedForSize() {
92 // We're mostly only Checking that this class was compiled successfully.
93 TestOptimizedForSize message = TestOptimizedForSize.CreateBuilder().SetI(1).Build();
94 message = TestOptimizedForSize.ParseFrom(message.ToByteString());
95 Assert.AreEqual(2, message.SerializedSize);
96 }
97
98 // -----------------------------------------------------------------
99 // Tests for isInitialized().
100
101 private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance;
102 private static readonly TestRequired TestRequiredInitialized = TestRequired.CreateBuilder().SetA(1).SetB(2).SetC(3).Build();
103
104 [Test]
105 public void IsInitialized() {
106 TestRequired.Builder builder = TestRequired.CreateBuilder();
107 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
108
109 Assert.IsFalse(abstractBuilder.IsInitialized);
110 builder.A = 1;
111 Assert.IsFalse(abstractBuilder.IsInitialized);
112 builder.B = 1;
113 Assert.IsFalse(abstractBuilder.IsInitialized);
114 builder.C = 1;
115 Assert.IsTrue(abstractBuilder.IsInitialized);
116 }
117
118 [Test]
119 public void ForeignIsInitialized() {
120 TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder();
121 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
122
123 Assert.IsTrue(abstractBuilder.IsInitialized);
124
125 builder.SetOptionalMessage(TestRequiredUninitialized);
126 Assert.IsFalse(abstractBuilder.IsInitialized);
127
128 builder.SetOptionalMessage(TestRequiredInitialized);
129 Assert.IsTrue(abstractBuilder.IsInitialized);
130
131 builder.AddRepeatedMessage(TestRequiredUninitialized);
132 Assert.IsFalse(abstractBuilder.IsInitialized);
133
134 builder.SetRepeatedMessage(0, TestRequiredInitialized);
135 Assert.IsTrue(abstractBuilder.IsInitialized);
136 }
137
138 // -----------------------------------------------------------------
139 // Tests for mergeFrom
140
141 static readonly TestAllTypes MergeSource = TestAllTypes.CreateBuilder()
142 .SetOptionalInt32(1)
143 .SetOptionalString("foo")
144 .SetOptionalForeignMessage(ForeignMessage.DefaultInstance)
145 .AddRepeatedString("bar")
146 .Build();
147
148 static readonly TestAllTypes MergeDest = TestAllTypes.CreateBuilder()
149 .SetOptionalInt64(2)
150 .SetOptionalString("baz")
151 .SetOptionalForeignMessage(ForeignMessage.CreateBuilder().SetC(3).Build())
152 .AddRepeatedString("qux")
153 .Build();
154
155 const string MergeResultText = "optional_int32: 1\n" +
156 "optional_int64: 2\n" +
157 "optional_string: \"foo\"\n" +
158 "optional_foreign_message {\n" +
159 " c: 3\n" +
160 "}\n" +
161 "repeated_string: \"qux\"\n" +
162 "repeated_string: \"bar\"\n";
163
164 [Test]
165 public void MergeFrom() {
166 AbstractMessageWrapper result = (AbstractMessageWrapper)
167 new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(MergeDest))
168 .MergeFrom(MergeSource)
169 .Build();
170
171 Assert.AreEqual(MergeResultText, result.ToString());
172 }
173
174 // -----------------------------------------------------------------
175 // Tests for equals and hashCode
176
177 [Test]
178 public void EqualsAndHashCode() {
179 TestAllTypes a = TestUtil.GetAllSet();
180 TestAllTypes b = TestAllTypes.CreateBuilder().Build();
181 TestAllTypes c = TestAllTypes.CreateBuilder(b).AddRepeatedString("x").Build();
182 TestAllTypes d = TestAllTypes.CreateBuilder(c).AddRepeatedString("y").Build();
183 TestAllExtensions e = TestUtil.GetAllExtensionsSet();
184 TestAllExtensions f = TestAllExtensions.CreateBuilder(e)
185 .AddExtension(UnitTestProtoFile.RepeatedInt32Extension, 999).Build();
186
187 CheckEqualsIsConsistent(a);
188 CheckEqualsIsConsistent(b);
189 CheckEqualsIsConsistent(c);
190 CheckEqualsIsConsistent(d);
191 CheckEqualsIsConsistent(e);
192 CheckEqualsIsConsistent(f);
193
194 CheckNotEqual(a, b);
195 CheckNotEqual(a, c);
196 CheckNotEqual(a, d);
197 CheckNotEqual(a, e);
198 CheckNotEqual(a, f);
199
200 CheckNotEqual(b, c);
201 CheckNotEqual(b, d);
202 CheckNotEqual(b, e);
203 CheckNotEqual(b, f);
204
205 CheckNotEqual(c, d);
206 CheckNotEqual(c, e);
207 CheckNotEqual(c, f);
208
209 CheckNotEqual(d, e);
210 CheckNotEqual(d, f);
211
212 CheckNotEqual(e, f);
213 }
214
215 /// <summary>
216 /// Asserts that the given protos are equal and have the same hash code.
217 /// </summary>
218 private static void CheckEqualsIsConsistent(IMessage message) {
219 // Object should be equal to itself.
220 Assert.AreEqual(message, message);
221
222 // Object should be equal to a dynamic copy of itself.
223 DynamicMessage dynamic = DynamicMessage.CreateBuilder(message).Build();
224 Assert.AreEqual(message, dynamic);
225 Assert.AreEqual(dynamic, message);
226 Assert.AreEqual(dynamic.GetHashCode(), message.GetHashCode());
227 }
228
229 /// <summary>
230 /// Asserts that the given protos are not equal and have different hash codes.
231 /// </summary>
232 /// <remarks>
233 /// It's valid for non-equal objects to have the same hash code, so
234 /// this test is stricter than it needs to be. However, this should happen
235 /// relatively rarely. (If this test fails, it's probably still due to a bug.)
236 /// </remarks>
237 private static void CheckNotEqual(IMessage m1, IMessage m2) {
238 String equalsError = string.Format("{0} should not be equal to {1}", m1, m2);
239 Assert.IsFalse(m1.Equals(m2), equalsError);
240 Assert.IsFalse(m2.Equals(m1), equalsError);
241
242 Assert.IsFalse(m1.GetHashCode() == m2.GetHashCode(),
243 string.Format("{0} should have a different hash code from {1}", m1, m2));
244 }
245
246 /// <summary>
247 /// Extends AbstractMessage and wraps some other message object. The methods
248 /// of the Message interface which aren't explicitly implemented by
249 /// AbstractMessage are forwarded to the wrapped object. This allows us to
250 /// test that AbstractMessage's implementations work even if the wrapped
251 /// object does not use them.
252 /// </summary>
253 private class AbstractMessageWrapper : AbstractMessage<AbstractMessageWrapper, AbstractMessageWrapper.Builder> {
254 private readonly IMessage wrappedMessage;
255
256 public IMessage WrappedMessage {
257 get { return wrappedMessage; }
258 }
259
260 public AbstractMessageWrapper(IMessage wrappedMessage) {
261 this.wrappedMessage = wrappedMessage;
262 }
263
264 public override MessageDescriptor DescriptorForType {
265 get { return wrappedMessage.DescriptorForType; }
266 }
267
268 public override AbstractMessageWrapper DefaultInstanceForType {
269 get { return new AbstractMessageWrapper(wrappedMessage.WeakDefaultInstanceForType); }
270 }
271
272 public override IDictionary<FieldDescriptor, object> AllFields {
273 get { return wrappedMessage.AllFields; }
274 }
275
276 public override bool HasField(FieldDescriptor field) {
277 return wrappedMessage.HasField(field);
278 }
279
280 public override object this[FieldDescriptor field] {
281 get { return wrappedMessage[field]; }
282 }
283
284 public override object this[FieldDescriptor field, int index] {
285 get { return wrappedMessage[field, index]; }
286 }
287
288 public override int GetRepeatedFieldCount(FieldDescriptor field) {
289 return wrappedMessage.GetRepeatedFieldCount(field);
290 }
291
292 public override UnknownFieldSet UnknownFields {
293 get { return wrappedMessage.UnknownFields; }
294 }
295
296 public override Builder CreateBuilderForType() {
297 return new Builder(wrappedMessage.WeakCreateBuilderForType());
298 }
299
300 internal class Builder : AbstractBuilder<AbstractMessageWrapper, Builder> {
301 private readonly IBuilder wrappedBuilder;
302
303 protected override Builder ThisBuilder {
304 get { return this; }
305 }
306
307 internal Builder(IBuilder wrappedBuilder) {
308 this.wrappedBuilder = wrappedBuilder;
309 }
310
311 public override Builder MergeFrom(AbstractMessageWrapper other) {
312 wrappedBuilder.WeakMergeFrom(other.wrappedMessage);
313 return this;
314 }
315
316 public override bool IsInitialized {
317 get { return wrappedBuilder.IsInitialized; }
318 }
319
320 public override IDictionary<FieldDescriptor, object> AllFields {
321 get { return wrappedBuilder.AllFields; }
322 }
323
324 public override object this[FieldDescriptor field] {
325 get { return wrappedBuilder[field]; }
326 set { wrappedBuilder[field] = value; }
327 }
328
329 public override MessageDescriptor DescriptorForType {
330 get { return wrappedBuilder.DescriptorForType; }
331 }
332
333 public override int GetRepeatedFieldCount(FieldDescriptor field) {
334 return wrappedBuilder.GetRepeatedFieldCount(field);
335 }
336
337 public override object this[FieldDescriptor field, int index] {
338 get { return wrappedBuilder[field, index]; }
339 set { wrappedBuilder[field, index] = value; }
340 }
341
342 public override bool HasField(FieldDescriptor field) {
343 return wrappedBuilder.HasField(field);
344 }
345
346 public override UnknownFieldSet UnknownFields {
347 get { return wrappedBuilder.UnknownFields; }
348 set { wrappedBuilder.UnknownFields = value; }
349 }
350
351 public override AbstractMessageWrapper Build() {
352 return new AbstractMessageWrapper(wrappedBuilder.WeakBuild());
353 }
354
355 public override AbstractMessageWrapper BuildPartial() {
356 return new AbstractMessageWrapper(wrappedBuilder.WeakBuildPartial());
357 }
358
359 public override Builder Clone() {
360 return new Builder(wrappedBuilder.WeakClone());
361 }
362
363 public override AbstractMessageWrapper DefaultInstanceForType {
364 get { return new AbstractMessageWrapper(wrappedBuilder.WeakDefaultInstanceForType); }
365 }
366
367 public override Builder ClearField(FieldDescriptor field) {
368 wrappedBuilder.WeakClearField(field);
369 return this;
370 }
371
372 public override Builder AddRepeatedField(FieldDescriptor field, object value) {
373 wrappedBuilder.WeakAddRepeatedField(field, value);
374 return this;
375 }
376
377 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
378 wrappedBuilder.CreateBuilderForField(field);
379 return this;
380 }
381
382 public override Builder MergeFrom(IMessage other) {
383 wrappedBuilder.WeakMergeFrom(other);
384 return this;
385 }
386
387 public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
388 wrappedBuilder.WeakMergeFrom(input, extensionRegistry);
389 return this;
390 }
391 }
392 }
393 }
394}