blob: 08de7fbfee16e7c346a34572b297c83162d4bf77 [file] [log] [blame]
Jon Skeet0aac0e42009-09-09 18:48:02 +01001#region Copyright notice and license
Jon Skeet60c059b2008-10-23 21:17:56 +01002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
Jon Skeet68036862008-10-22 13:30:34 +01006// http://code.google.com/p/protobuf/
7//
Jon Skeet60c059b2008-10-23 21:17:56 +01008// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
Jon Skeet68036862008-10-22 13:30:34 +010011//
Jon Skeet60c059b2008-10-23 21:17:56 +010012// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
Jon Skeet68036862008-10-22 13:30:34 +010021//
Jon Skeet60c059b2008-10-23 21:17:56 +010022// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Jon Skeet0aac0e42009-09-09 18:48:02 +010033#endregion
34
Jon Skeet68036862008-10-22 13:30:34 +010035using System;
36using System.Collections.Generic;
37using Google.ProtocolBuffers.Descriptors;
38using Google.ProtocolBuffers.TestProtos;
39using NUnit.Framework;
40
41namespace Google.ProtocolBuffers {
42 [TestFixture]
43 public class UnknownFieldSetTest {
44
45 private MessageDescriptor descriptor;
46 private TestAllTypes allFields;
47 private ByteString allFieldsData;
48
49 /// <summary>
50 /// An empty message that has been parsed from allFieldsData. So, it has
51 /// unknown fields of every type.
52 /// </summary>
53 private TestEmptyMessage emptyMessage;
54 private UnknownFieldSet unknownFields;
55
56 [SetUp]
57 public void SetUp() {
58 descriptor = TestAllTypes.Descriptor;
59 allFields = TestUtil.GetAllSet();
60 allFieldsData = allFields.ToByteString();
61 emptyMessage = TestEmptyMessage.ParseFrom(allFieldsData);
62 unknownFields = emptyMessage.UnknownFields;
63 }
64
65 private UnknownField GetField(String name) {
66 FieldDescriptor field = descriptor.FindDescriptor<FieldDescriptor>(name);
67 Assert.IsNotNull(field);
68 return unknownFields.FieldDictionary[field.FieldNumber];
69 }
70
71 /// <summary>
72 /// Constructs a protocol buffer which contains fields with all the same
73 /// numbers as allFieldsData except that each field is some other wire
74 /// type.
75 /// </summary>
76 private ByteString GetBizarroData() {
77 UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.CreateBuilder();
78
79 UnknownField varintField = UnknownField.CreateBuilder().AddVarint(1).Build();
80 UnknownField fixed32Field = UnknownField.CreateBuilder().AddFixed32(1).Build();
81
82 foreach (KeyValuePair<int, UnknownField> entry in unknownFields.FieldDictionary) {
83 if (entry.Value.VarintList.Count == 0) {
84 // Original field is not a varint, so use a varint.
85 bizarroFields.AddField(entry.Key, varintField);
86 } else {
87 // Original field *is* a varint, so use something else.
88 bizarroFields.AddField(entry.Key, fixed32Field);
89 }
90 }
91
92 return bizarroFields.Build().ToByteString();
93 }
94
95 // =================================================================
96
97 [Test]
98 public void Varint() {
99 UnknownField field = GetField("optional_int32");
100 Assert.AreEqual(1, field.VarintList.Count);
101 Assert.AreEqual(allFields.OptionalInt32, (long) field.VarintList[0]);
102 }
103
104 [Test]
105 public void Fixed32() {
106 UnknownField field = GetField("optional_fixed32");
107 Assert.AreEqual(1, field.Fixed32List.Count);
108 Assert.AreEqual(allFields.OptionalFixed32, (int) field.Fixed32List[0]);
109 }
110
111 [Test]
112 public void Fixed64() {
113 UnknownField field = GetField("optional_fixed64");
114 Assert.AreEqual(1, field.Fixed64List.Count);
115 Assert.AreEqual(allFields.OptionalFixed64, (long) field.Fixed64List[0]);
116 }
117
118 [Test]
119 public void LengthDelimited() {
120 UnknownField field = GetField("optional_bytes");
121 Assert.AreEqual(1, field.LengthDelimitedList.Count);
122 Assert.AreEqual(allFields.OptionalBytes, field.LengthDelimitedList[0]);
123 }
124
125 [Test]
126 public void Group() {
127 FieldDescriptor nestedFieldDescriptor =
128 TestAllTypes.Types.OptionalGroup.Descriptor.FindDescriptor<FieldDescriptor>("a");
129 Assert.IsNotNull(nestedFieldDescriptor);
130
131 UnknownField field = GetField("optionalgroup");
132 Assert.AreEqual(1, field.GroupList.Count);
133
134 UnknownFieldSet group = field.GroupList[0];
135 Assert.AreEqual(1, group.FieldDictionary.Count);
136 Assert.IsTrue(group.HasField(nestedFieldDescriptor.FieldNumber));
137
138 UnknownField nestedField = group[nestedFieldDescriptor.FieldNumber];
139 Assert.AreEqual(1, nestedField.VarintList.Count);
140 Assert.AreEqual(allFields.OptionalGroup.A, (long) nestedField.VarintList[0]);
141 }
142
143 [Test]
144 public void Serialize() {
145 // Check that serializing the UnknownFieldSet produces the original data again.
146 ByteString data = emptyMessage.ToByteString();
147 Assert.AreEqual(allFieldsData, data);
148 }
149
150 [Test]
151 public void CopyFrom() {
152 TestEmptyMessage message =
153 TestEmptyMessage.CreateBuilder().MergeFrom(emptyMessage).Build();
154
155 Assert.AreEqual(emptyMessage.ToString(), message.ToString());
156 }
157
158 [Test]
159 public void MergeFrom() {
160 TestEmptyMessage source =
161 TestEmptyMessage.CreateBuilder()
162 .SetUnknownFields(
163 UnknownFieldSet.CreateBuilder()
164 .AddField(2,
165 UnknownField.CreateBuilder()
166 .AddVarint(2).Build())
167 .AddField(3,
168 UnknownField.CreateBuilder()
169 .AddVarint(4).Build())
170 .Build())
171 .Build();
172 TestEmptyMessage destination =
173 TestEmptyMessage.CreateBuilder()
174 .SetUnknownFields(
175 UnknownFieldSet.CreateBuilder()
176 .AddField(1,
177 UnknownField.CreateBuilder()
178 .AddVarint(1).Build())
179 .AddField(3,
180 UnknownField.CreateBuilder()
181 .AddVarint(3).Build())
182 .Build())
183 .MergeFrom(source)
184 .Build();
185
186 Assert.AreEqual(
187 "1: 1\n" +
188 "2: 2\n" +
189 "3: 3\n" +
190 "3: 4\n",
191 destination.ToString());
192 }
193
194 [Test]
195 public void Clear() {
196 UnknownFieldSet fields =
197 UnknownFieldSet.CreateBuilder().MergeFrom(unknownFields).Clear().Build();
198 Assert.AreEqual(0, fields.FieldDictionary.Count);
199 }
200
201 [Test]
202 public void ClearMessage() {
203 TestEmptyMessage message =
204 TestEmptyMessage.CreateBuilder().MergeFrom(emptyMessage).Clear().Build();
205 Assert.AreEqual(0, message.SerializedSize);
206 }
207
208 [Test]
209 public void ParseKnownAndUnknown() {
210 // Test mixing known and unknown fields when parsing.
211
212 UnknownFieldSet fields =
213 UnknownFieldSet.CreateBuilder(unknownFields)
214 .AddField(123456,
215 UnknownField.CreateBuilder().AddVarint(654321).Build())
216 .Build();
217
218 ByteString data = fields.ToByteString();
219 TestAllTypes destination = TestAllTypes.ParseFrom(data);
220
221 TestUtil.AssertAllFieldsSet(destination);
222 Assert.AreEqual(1, destination.UnknownFields.FieldDictionary.Count);
223
224 UnknownField field = destination.UnknownFields[123456];
225 Assert.AreEqual(1, field.VarintList.Count);
226 Assert.AreEqual(654321, (long) field.VarintList[0]);
227 }
228
229 [Test]
230 public void WrongTypeTreatedAsUnknown() {
231 // Test that fields of the wrong wire type are treated like unknown fields
232 // when parsing.
233
234 ByteString bizarroData = GetBizarroData();
235 TestAllTypes allTypesMessage = TestAllTypes.ParseFrom(bizarroData);
236 TestEmptyMessage emptyMessage = TestEmptyMessage.ParseFrom(bizarroData);
237
238 // All fields should have been interpreted as unknown, so the debug strings
239 // should be the same.
240 Assert.AreEqual(emptyMessage.ToString(), allTypesMessage.ToString());
241 }
242
243 [Test]
244 public void UnknownExtensions() {
245 // Make sure fields are properly parsed to the UnknownFieldSet even when
246 // they are declared as extension numbers.
247
248 TestEmptyMessageWithExtensions message =
249 TestEmptyMessageWithExtensions.ParseFrom(allFieldsData);
250
251 Assert.AreEqual(unknownFields.FieldDictionary.Count,
252 message.UnknownFields.FieldDictionary.Count);
253 Assert.AreEqual(allFieldsData, message.ToByteString());
254 }
255
256 [Test]
257 public void WrongExtensionTypeTreatedAsUnknown() {
258 // Test that fields of the wrong wire type are treated like unknown fields
259 // when parsing extensions.
260
261 ByteString bizarroData = GetBizarroData();
262 TestAllExtensions allExtensionsMessage = TestAllExtensions.ParseFrom(bizarroData);
263 TestEmptyMessage emptyMessage = TestEmptyMessage.ParseFrom(bizarroData);
264
265 // All fields should have been interpreted as unknown, so the debug strings
266 // should be the same.
267 Assert.AreEqual(emptyMessage.ToString(),
268 allExtensionsMessage.ToString());
269 }
270
271 [Test]
272 public void ParseUnknownEnumValue() {
273 FieldDescriptor singularField = TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("optional_nested_enum");
274 FieldDescriptor repeatedField = TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("repeated_nested_enum");
275 Assert.IsNotNull(singularField);
276 Assert.IsNotNull(repeatedField);
277
278 ByteString data =
279 UnknownFieldSet.CreateBuilder()
280 .AddField(singularField.FieldNumber,
281 UnknownField.CreateBuilder()
282 .AddVarint((int) TestAllTypes.Types.NestedEnum.BAR)
283 .AddVarint(5) // not valid
284 .Build())
285 .AddField(repeatedField.FieldNumber,
286 UnknownField.CreateBuilder()
287 .AddVarint((int) TestAllTypes.Types.NestedEnum.FOO)
288 .AddVarint(4) // not valid
289 .AddVarint((int) TestAllTypes.Types.NestedEnum.BAZ)
290 .AddVarint(6) // not valid
291 .Build())
292 .Build()
293 .ToByteString();
294
295 {
296 TestAllTypes message = TestAllTypes.ParseFrom(data);
297 Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR,
298 message.OptionalNestedEnum);
299 TestUtil.AssertEqual(new [] {TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.BAZ},
300 message.RepeatedNestedEnumList);
301 TestUtil.AssertEqual(new[] {5UL}, message.UnknownFields[singularField.FieldNumber].VarintList);
302 TestUtil.AssertEqual(new[] {4UL, 6UL}, message.UnknownFields[repeatedField.FieldNumber].VarintList);
303 }
304
305 {
306 TestAllExtensions message =
307 TestAllExtensions.ParseFrom(data, TestUtil.CreateExtensionRegistry());
308 Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR,
309 message.GetExtension(UnitTestProtoFile.OptionalNestedEnumExtension));
310 TestUtil.AssertEqual(new[] { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.BAZ },
311 message.GetExtension(UnitTestProtoFile.RepeatedNestedEnumExtension));
312 TestUtil.AssertEqual(new[] { 5UL }, message.UnknownFields[singularField.FieldNumber].VarintList);
313 TestUtil.AssertEqual(new[] { 4UL, 6UL }, message.UnknownFields[repeatedField.FieldNumber].VarintList);
314 }
315 }
316
317 [Test]
318 public void LargeVarint() {
319 ByteString data =
320 UnknownFieldSet.CreateBuilder()
321 .AddField(1,
322 UnknownField.CreateBuilder()
323 .AddVarint(0x7FFFFFFFFFFFFFFFL)
324 .Build())
325 .Build()
326 .ToByteString();
327 UnknownFieldSet parsed = UnknownFieldSet.ParseFrom(data);
328 UnknownField field = parsed[1];
329 Assert.AreEqual(1, field.VarintList.Count);
330 Assert.AreEqual(0x7FFFFFFFFFFFFFFFUL, field.VarintList[0]);
331 }
Jon Skeet43da7ae2009-05-28 21:45:43 +0100332
333 [Test]
334 public void EqualsAndHashCode() {
335 UnknownField fixed32Field = UnknownField.CreateBuilder().AddFixed32(1).Build();
336 UnknownField fixed64Field = UnknownField.CreateBuilder().AddFixed64(1).Build();
337 UnknownField varIntField = UnknownField.CreateBuilder().AddVarint(1).Build();
338 UnknownField lengthDelimitedField = UnknownField.CreateBuilder().AddLengthDelimited(ByteString.Empty).Build();
339 UnknownField groupField = UnknownField.CreateBuilder().AddGroup(unknownFields).Build();
340
341 UnknownFieldSet a = UnknownFieldSet.CreateBuilder().AddField(1, fixed32Field).Build();
342 UnknownFieldSet b = UnknownFieldSet.CreateBuilder().AddField(1, fixed64Field).Build();
343 UnknownFieldSet c = UnknownFieldSet.CreateBuilder().AddField(1, varIntField).Build();
344 UnknownFieldSet d = UnknownFieldSet.CreateBuilder().AddField(1, lengthDelimitedField).Build();
345 UnknownFieldSet e = UnknownFieldSet.CreateBuilder().AddField(1, groupField).Build();
346
347 CheckEqualsIsConsistent(a);
348 CheckEqualsIsConsistent(b);
349 CheckEqualsIsConsistent(c);
350 CheckEqualsIsConsistent(d);
351 CheckEqualsIsConsistent(e);
352
353 CheckNotEqual(a, b);
354 CheckNotEqual(a, c);
355 CheckNotEqual(a, d);
356 CheckNotEqual(a, e);
357 CheckNotEqual(b, c);
358 CheckNotEqual(b, d);
359 CheckNotEqual(b, e);
360 CheckNotEqual(c, d);
361 CheckNotEqual(c, e);
362 CheckNotEqual(d, e);
363 }
364
365 /// <summary>
366 /// Asserts that the given field sets are not equal and have different
367 /// hash codes.
368 /// </summary>
369 /// <remarks>
370 /// It's valid for non-equal objects to have the same hash code, so
371 /// this test is stricter than it needs to be. However, this should happen
372 /// relatively rarely.
373 /// </remarks>
374 /// <param name="s1"></param>
375 /// <param name="s2"></param>
376 private static void CheckNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
377 String equalsError = string.Format("{0} should not be equal to {1}", s1, s2);
378 Assert.IsFalse(s1.Equals(s2), equalsError);
379 Assert.IsFalse(s2.Equals(s1), equalsError);
380
381 Assert.IsFalse(s1.GetHashCode() == s2.GetHashCode(),
382 string.Format("{0} should have a different hash code from {1}", s1, s2));
383
384 }
385
386 /**
387 * Asserts that the given field sets are equal and have identical hash codes.
388 */
389 private static void CheckEqualsIsConsistent(UnknownFieldSet set) {
390 // Object should be equal to itself.
391 Assert.AreEqual(set, set);
392
393 // Object should be equal to a copy of itself.
394 UnknownFieldSet copy = UnknownFieldSet.CreateBuilder(set).Build();
395 Assert.AreEqual(set, copy);
396 Assert.AreEqual(copy, set);
397 Assert.AreEqual(set.GetHashCode(), copy.GetHashCode());
398 }
Jon Skeet68036862008-10-22 13:30:34 +0100399 }
400}