blob: 38cc8636cfeaa9d5682992a157660ec338f149b8 [file] [log] [blame]
Jon Skeet68036862008-10-22 13:30:34 +01001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.
3// http://code.google.com/p/protobuf/
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16using System;
17using System.Collections.Generic;
18using Google.ProtocolBuffers.Descriptors;
19using NUnit.Framework;
20using Google.ProtocolBuffers.TestProtos;
21
22namespace Google.ProtocolBuffers {
23 [TestFixture]
24 public class AbstractMessageTest {
25
26 [Test]
27 public void Clear() {
28 AbstractMessageWrapper message = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(TestUtil.GetAllSet())).Clear().Build();
29 TestUtil.AssertClear((TestAllTypes) message.WrappedMessage);
30 }
31
32 [Test]
33 public void Copy() {
34 AbstractMessageWrapper message = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder()).MergeFrom(TestUtil.GetAllSet()).Build();
35 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
36 }
37
38 [Test]
39 public void SerializedSize() {
40 TestAllTypes message = TestUtil.GetAllSet();
41 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
42
43 Assert.AreEqual(message.SerializedSize, abstractMessage.SerializedSize);
44 }
45
46 [Test]
47 public void Serialization() {
48 IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet());
49 TestUtil.AssertAllFieldsSet(TestAllTypes.ParseFrom(abstractMessage.ToByteString()));
50 Assert.AreEqual(TestUtil.GetAllSet().ToByteString(), abstractMessage.ToByteString());
51 }
52
53 [Test]
54 public void Parsing() {
55 IBuilder builder = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder());
56 AbstractMessageWrapper message = (AbstractMessageWrapper) builder.WeakMergeFrom(TestUtil.GetAllSet().ToByteString()).WeakBuild();
57 TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage);
58 }
59
60 [Test]
61 public void OptimizedForSize() {
62 // We're mostly only Checking that this class was compiled successfully.
63 TestOptimizedForSize message = TestOptimizedForSize.CreateBuilder().SetI(1).Build();
64 message = TestOptimizedForSize.ParseFrom(message.ToByteString());
65 Assert.AreEqual(2, message.SerializedSize);
66 }
67
68 // -----------------------------------------------------------------
69 // Tests for isInitialized().
70
71 private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance;
72 private static readonly TestRequired TestRequiredInitialized = TestRequired.CreateBuilder().SetA(1).SetB(2).SetC(3).Build();
73
74 [Test]
75 public void IsInitialized() {
76 TestRequired.Builder builder = TestRequired.CreateBuilder();
77 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
78
79 Assert.IsFalse(abstractBuilder.IsInitialized);
80 builder.A = 1;
81 Assert.IsFalse(abstractBuilder.IsInitialized);
82 builder.B = 1;
83 Assert.IsFalse(abstractBuilder.IsInitialized);
84 builder.C = 1;
85 Assert.IsTrue(abstractBuilder.IsInitialized);
86 }
87
88 [Test]
89 public void ForeignIsInitialized() {
90 TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder();
91 AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder);
92
93 Assert.IsTrue(abstractBuilder.IsInitialized);
94
95 builder.SetOptionalMessage(TestRequiredUninitialized);
96 Assert.IsFalse(abstractBuilder.IsInitialized);
97
98 builder.SetOptionalMessage(TestRequiredInitialized);
99 Assert.IsTrue(abstractBuilder.IsInitialized);
100
101 builder.AddRepeatedMessage(TestRequiredUninitialized);
102 Assert.IsFalse(abstractBuilder.IsInitialized);
103
104 builder.SetRepeatedMessage(0, TestRequiredInitialized);
105 Assert.IsTrue(abstractBuilder.IsInitialized);
106 }
107
108 // -----------------------------------------------------------------
109 // Tests for mergeFrom
110
111 static readonly TestAllTypes MergeSource = TestAllTypes.CreateBuilder()
112 .SetOptionalInt32(1)
113 .SetOptionalString("foo")
114 .SetOptionalForeignMessage(ForeignMessage.DefaultInstance)
115 .AddRepeatedString("bar")
116 .Build();
117
118 static readonly TestAllTypes MergeDest = TestAllTypes.CreateBuilder()
119 .SetOptionalInt64(2)
120 .SetOptionalString("baz")
121 .SetOptionalForeignMessage(ForeignMessage.CreateBuilder().SetC(3).Build())
122 .AddRepeatedString("qux")
123 .Build();
124
125 const string MergeResultText = "optional_int32: 1\n" +
126 "optional_int64: 2\n" +
127 "optional_string: \"foo\"\n" +
128 "optional_foreign_message {\n" +
129 " c: 3\n" +
130 "}\n" +
131 "repeated_string: \"qux\"\n" +
132 "repeated_string: \"bar\"\n";
133
134 [Test]
135 public void MergeFrom() {
136 AbstractMessageWrapper result = (AbstractMessageWrapper)
137 new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(MergeDest))
138 .MergeFrom(MergeSource)
139 .Build();
140
141 Assert.AreEqual(MergeResultText, result.ToString());
142 }
143
144 // -----------------------------------------------------------------
145 // Tests for equals and hashCode
146
147 [Test]
148 public void EqualsAndHashCode() {
149 TestAllTypes a = TestUtil.GetAllSet();
150 TestAllTypes b = TestAllTypes.CreateBuilder().Build();
151 TestAllTypes c = TestAllTypes.CreateBuilder(b).AddRepeatedString("x").Build();
152 TestAllTypes d = TestAllTypes.CreateBuilder(c).AddRepeatedString("y").Build();
153 TestAllExtensions e = TestUtil.GetAllExtensionsSet();
154 TestAllExtensions f = TestAllExtensions.CreateBuilder(e)
155 .AddExtension(UnitTestProtoFile.RepeatedInt32Extension, 999).Build();
156
157 CheckEqualsIsConsistent(a);
158 CheckEqualsIsConsistent(b);
159 CheckEqualsIsConsistent(c);
160 CheckEqualsIsConsistent(d);
161 CheckEqualsIsConsistent(e);
162 CheckEqualsIsConsistent(f);
163
164 CheckNotEqual(a, b);
165 CheckNotEqual(a, c);
166 CheckNotEqual(a, d);
167 CheckNotEqual(a, e);
168 CheckNotEqual(a, f);
169
170 CheckNotEqual(b, c);
171 CheckNotEqual(b, d);
172 CheckNotEqual(b, e);
173 CheckNotEqual(b, f);
174
175 CheckNotEqual(c, d);
176 CheckNotEqual(c, e);
177 CheckNotEqual(c, f);
178
179 CheckNotEqual(d, e);
180 CheckNotEqual(d, f);
181
182 CheckNotEqual(e, f);
183 }
184
185 /// <summary>
186 /// Asserts that the given protos are equal and have the same hash code.
187 /// </summary>
188 private static void CheckEqualsIsConsistent(IMessage message) {
189 // Object should be equal to itself.
190 Assert.AreEqual(message, message);
191
192 // Object should be equal to a dynamic copy of itself.
193 DynamicMessage dynamic = DynamicMessage.CreateBuilder(message).Build();
194 Assert.AreEqual(message, dynamic);
195 Assert.AreEqual(dynamic, message);
196 Assert.AreEqual(dynamic.GetHashCode(), message.GetHashCode());
197 }
198
199 /// <summary>
200 /// Asserts that the given protos are not equal and have different hash codes.
201 /// </summary>
202 /// <remarks>
203 /// It's valid for non-equal objects to have the same hash code, so
204 /// this test is stricter than it needs to be. However, this should happen
205 /// relatively rarely. (If this test fails, it's probably still due to a bug.)
206 /// </remarks>
207 private static void CheckNotEqual(IMessage m1, IMessage m2) {
208 String equalsError = string.Format("{0} should not be equal to {1}", m1, m2);
209 Assert.IsFalse(m1.Equals(m2), equalsError);
210 Assert.IsFalse(m2.Equals(m1), equalsError);
211
212 Assert.IsFalse(m1.GetHashCode() == m2.GetHashCode(),
213 string.Format("{0} should have a different hash code from {1}", m1, m2));
214 }
215
216 /// <summary>
217 /// Extends AbstractMessage and wraps some other message object. The methods
218 /// of the Message interface which aren't explicitly implemented by
219 /// AbstractMessage are forwarded to the wrapped object. This allows us to
220 /// test that AbstractMessage's implementations work even if the wrapped
221 /// object does not use them.
222 /// </summary>
223 private class AbstractMessageWrapper : AbstractMessage<AbstractMessageWrapper, AbstractMessageWrapper.Builder> {
224 private readonly IMessage wrappedMessage;
225
226 public IMessage WrappedMessage {
227 get { return wrappedMessage; }
228 }
229
230 public AbstractMessageWrapper(IMessage wrappedMessage) {
231 this.wrappedMessage = wrappedMessage;
232 }
233
234 public override MessageDescriptor DescriptorForType {
235 get { return wrappedMessage.DescriptorForType; }
236 }
237
238 public override AbstractMessageWrapper DefaultInstanceForType {
239 get { return new AbstractMessageWrapper(wrappedMessage.WeakDefaultInstanceForType); }
240 }
241
242 public override IDictionary<FieldDescriptor, object> AllFields {
243 get { return wrappedMessage.AllFields; }
244 }
245
246 public override bool HasField(FieldDescriptor field) {
247 return wrappedMessage.HasField(field);
248 }
249
250 public override object this[FieldDescriptor field] {
251 get { return wrappedMessage[field]; }
252 }
253
254 public override object this[FieldDescriptor field, int index] {
255 get { return wrappedMessage[field, index]; }
256 }
257
258 public override int GetRepeatedFieldCount(FieldDescriptor field) {
259 return wrappedMessage.GetRepeatedFieldCount(field);
260 }
261
262 public override UnknownFieldSet UnknownFields {
263 get { return wrappedMessage.UnknownFields; }
264 }
265
266 public override Builder CreateBuilderForType() {
267 return new Builder(wrappedMessage.WeakCreateBuilderForType());
268 }
269
270 internal class Builder : AbstractBuilder<AbstractMessageWrapper, Builder> {
271 private readonly IBuilder wrappedBuilder;
272
273 protected override Builder ThisBuilder {
274 get { return this; }
275 }
276
277 internal Builder(IBuilder wrappedBuilder) {
278 this.wrappedBuilder = wrappedBuilder;
279 }
280
281 public override Builder MergeFrom(AbstractMessageWrapper other) {
282 wrappedBuilder.WeakMergeFrom(other.wrappedMessage);
283 return this;
284 }
285
286 public override bool IsInitialized {
287 get { return wrappedBuilder.IsInitialized; }
288 }
289
290 public override IDictionary<FieldDescriptor, object> AllFields {
291 get { return wrappedBuilder.AllFields; }
292 }
293
294 public override object this[FieldDescriptor field] {
295 get { return wrappedBuilder[field]; }
296 set { wrappedBuilder[field] = value; }
297 }
298
299 public override MessageDescriptor DescriptorForType {
300 get { return wrappedBuilder.DescriptorForType; }
301 }
302
303 public override int GetRepeatedFieldCount(FieldDescriptor field) {
304 return wrappedBuilder.GetRepeatedFieldCount(field);
305 }
306
307 public override object this[FieldDescriptor field, int index] {
308 get { return wrappedBuilder[field, index]; }
309 set { wrappedBuilder[field, index] = value; }
310 }
311
312 public override bool HasField(FieldDescriptor field) {
313 return wrappedBuilder.HasField(field);
314 }
315
316 public override UnknownFieldSet UnknownFields {
317 get { return wrappedBuilder.UnknownFields; }
318 set { wrappedBuilder.UnknownFields = value; }
319 }
320
321 public override AbstractMessageWrapper Build() {
322 return new AbstractMessageWrapper(wrappedBuilder.WeakBuild());
323 }
324
325 public override AbstractMessageWrapper BuildPartial() {
326 return new AbstractMessageWrapper(wrappedBuilder.WeakBuildPartial());
327 }
328
329 public override Builder Clone() {
330 return new Builder(wrappedBuilder.WeakClone());
331 }
332
333 public override AbstractMessageWrapper DefaultInstanceForType {
334 get { return new AbstractMessageWrapper(wrappedBuilder.WeakDefaultInstanceForType); }
335 }
336
337 public override Builder ClearField(FieldDescriptor field) {
338 wrappedBuilder.WeakClearField(field);
339 return this;
340 }
341
342 public override Builder AddRepeatedField(FieldDescriptor field, object value) {
343 wrappedBuilder.WeakAddRepeatedField(field, value);
344 return this;
345 }
346
347 public override IBuilder CreateBuilderForField(FieldDescriptor field) {
348 wrappedBuilder.CreateBuilderForField(field);
349 return this;
350 }
351
352 public override Builder MergeFrom(IMessage other) {
353 wrappedBuilder.WeakMergeFrom(other);
354 return this;
355 }
356
357 public override Builder MergeFrom(CodedInputStream input, ExtensionRegistry extensionRegistry) {
358 wrappedBuilder.WeakMergeFrom(input, extensionRegistry);
359 return this;
360 }
361 }
362 }
363 }
364}