blob: d279ffc53de3faaa2304ba2fd8f54d629ae94ca7 [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 Google.ProtocolBuffers.TestProtos;
36using NUnit.Framework;
37
38namespace Google.ProtocolBuffers {
39 [TestFixture]
40 public class UnknownFieldSetTest {
41
42 private MessageDescriptor descriptor;
43 private TestAllTypes allFields;
44 private ByteString allFieldsData;
45
46 /// <summary>
47 /// An empty message that has been parsed from allFieldsData. So, it has
48 /// unknown fields of every type.
49 /// </summary>
50 private TestEmptyMessage emptyMessage;
51 private UnknownFieldSet unknownFields;
52
53 [SetUp]
54 public void SetUp() {
55 descriptor = TestAllTypes.Descriptor;
56 allFields = TestUtil.GetAllSet();
57 allFieldsData = allFields.ToByteString();
58 emptyMessage = TestEmptyMessage.ParseFrom(allFieldsData);
59 unknownFields = emptyMessage.UnknownFields;
60 }
61
62 private UnknownField GetField(String name) {
63 FieldDescriptor field = descriptor.FindDescriptor<FieldDescriptor>(name);
64 Assert.IsNotNull(field);
65 return unknownFields.FieldDictionary[field.FieldNumber];
66 }
67
68 /// <summary>
69 /// Constructs a protocol buffer which contains fields with all the same
70 /// numbers as allFieldsData except that each field is some other wire
71 /// type.
72 /// </summary>
73 private ByteString GetBizarroData() {
74 UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.CreateBuilder();
75
76 UnknownField varintField = UnknownField.CreateBuilder().AddVarint(1).Build();
77 UnknownField fixed32Field = UnknownField.CreateBuilder().AddFixed32(1).Build();
78
79 foreach (KeyValuePair<int, UnknownField> entry in unknownFields.FieldDictionary) {
80 if (entry.Value.VarintList.Count == 0) {
81 // Original field is not a varint, so use a varint.
82 bizarroFields.AddField(entry.Key, varintField);
83 } else {
84 // Original field *is* a varint, so use something else.
85 bizarroFields.AddField(entry.Key, fixed32Field);
86 }
87 }
88
89 return bizarroFields.Build().ToByteString();
90 }
91
92 // =================================================================
93
94 [Test]
95 public void Varint() {
96 UnknownField field = GetField("optional_int32");
97 Assert.AreEqual(1, field.VarintList.Count);
98 Assert.AreEqual(allFields.OptionalInt32, (long) field.VarintList[0]);
99 }
100
101 [Test]
102 public void Fixed32() {
103 UnknownField field = GetField("optional_fixed32");
104 Assert.AreEqual(1, field.Fixed32List.Count);
105 Assert.AreEqual(allFields.OptionalFixed32, (int) field.Fixed32List[0]);
106 }
107
108 [Test]
109 public void Fixed64() {
110 UnknownField field = GetField("optional_fixed64");
111 Assert.AreEqual(1, field.Fixed64List.Count);
112 Assert.AreEqual(allFields.OptionalFixed64, (long) field.Fixed64List[0]);
113 }
114
115 [Test]
116 public void LengthDelimited() {
117 UnknownField field = GetField("optional_bytes");
118 Assert.AreEqual(1, field.LengthDelimitedList.Count);
119 Assert.AreEqual(allFields.OptionalBytes, field.LengthDelimitedList[0]);
120 }
121
122 [Test]
123 public void Group() {
124 FieldDescriptor nestedFieldDescriptor =
125 TestAllTypes.Types.OptionalGroup.Descriptor.FindDescriptor<FieldDescriptor>("a");
126 Assert.IsNotNull(nestedFieldDescriptor);
127
128 UnknownField field = GetField("optionalgroup");
129 Assert.AreEqual(1, field.GroupList.Count);
130
131 UnknownFieldSet group = field.GroupList[0];
132 Assert.AreEqual(1, group.FieldDictionary.Count);
133 Assert.IsTrue(group.HasField(nestedFieldDescriptor.FieldNumber));
134
135 UnknownField nestedField = group[nestedFieldDescriptor.FieldNumber];
136 Assert.AreEqual(1, nestedField.VarintList.Count);
137 Assert.AreEqual(allFields.OptionalGroup.A, (long) nestedField.VarintList[0]);
138 }
139
140 [Test]
141 public void Serialize() {
142 // Check that serializing the UnknownFieldSet produces the original data again.
143 ByteString data = emptyMessage.ToByteString();
144 Assert.AreEqual(allFieldsData, data);
145 }
146
147 [Test]
148 public void CopyFrom() {
149 TestEmptyMessage message =
150 TestEmptyMessage.CreateBuilder().MergeFrom(emptyMessage).Build();
151
152 Assert.AreEqual(emptyMessage.ToString(), message.ToString());
153 }
154
155 [Test]
156 public void MergeFrom() {
157 TestEmptyMessage source =
158 TestEmptyMessage.CreateBuilder()
159 .SetUnknownFields(
160 UnknownFieldSet.CreateBuilder()
161 .AddField(2,
162 UnknownField.CreateBuilder()
163 .AddVarint(2).Build())
164 .AddField(3,
165 UnknownField.CreateBuilder()
166 .AddVarint(4).Build())
167 .Build())
168 .Build();
169 TestEmptyMessage destination =
170 TestEmptyMessage.CreateBuilder()
171 .SetUnknownFields(
172 UnknownFieldSet.CreateBuilder()
173 .AddField(1,
174 UnknownField.CreateBuilder()
175 .AddVarint(1).Build())
176 .AddField(3,
177 UnknownField.CreateBuilder()
178 .AddVarint(3).Build())
179 .Build())
180 .MergeFrom(source)
181 .Build();
182
183 Assert.AreEqual(
184 "1: 1\n" +
185 "2: 2\n" +
186 "3: 3\n" +
187 "3: 4\n",
188 destination.ToString());
189 }
190
191 [Test]
192 public void Clear() {
193 UnknownFieldSet fields =
194 UnknownFieldSet.CreateBuilder().MergeFrom(unknownFields).Clear().Build();
195 Assert.AreEqual(0, fields.FieldDictionary.Count);
196 }
197
198 [Test]
199 public void ClearMessage() {
200 TestEmptyMessage message =
201 TestEmptyMessage.CreateBuilder().MergeFrom(emptyMessage).Clear().Build();
202 Assert.AreEqual(0, message.SerializedSize);
203 }
204
205 [Test]
206 public void ParseKnownAndUnknown() {
207 // Test mixing known and unknown fields when parsing.
208
209 UnknownFieldSet fields =
210 UnknownFieldSet.CreateBuilder(unknownFields)
211 .AddField(123456,
212 UnknownField.CreateBuilder().AddVarint(654321).Build())
213 .Build();
214
215 ByteString data = fields.ToByteString();
216 TestAllTypes destination = TestAllTypes.ParseFrom(data);
217
218 TestUtil.AssertAllFieldsSet(destination);
219 Assert.AreEqual(1, destination.UnknownFields.FieldDictionary.Count);
220
221 UnknownField field = destination.UnknownFields[123456];
222 Assert.AreEqual(1, field.VarintList.Count);
223 Assert.AreEqual(654321, (long) field.VarintList[0]);
224 }
225
226 [Test]
227 public void WrongTypeTreatedAsUnknown() {
228 // Test that fields of the wrong wire type are treated like unknown fields
229 // when parsing.
230
231 ByteString bizarroData = GetBizarroData();
232 TestAllTypes allTypesMessage = TestAllTypes.ParseFrom(bizarroData);
233 TestEmptyMessage emptyMessage = TestEmptyMessage.ParseFrom(bizarroData);
234
235 // All fields should have been interpreted as unknown, so the debug strings
236 // should be the same.
237 Assert.AreEqual(emptyMessage.ToString(), allTypesMessage.ToString());
238 }
239
240 [Test]
241 public void UnknownExtensions() {
242 // Make sure fields are properly parsed to the UnknownFieldSet even when
243 // they are declared as extension numbers.
244
245 TestEmptyMessageWithExtensions message =
246 TestEmptyMessageWithExtensions.ParseFrom(allFieldsData);
247
248 Assert.AreEqual(unknownFields.FieldDictionary.Count,
249 message.UnknownFields.FieldDictionary.Count);
250 Assert.AreEqual(allFieldsData, message.ToByteString());
251 }
252
253 [Test]
254 public void WrongExtensionTypeTreatedAsUnknown() {
255 // Test that fields of the wrong wire type are treated like unknown fields
256 // when parsing extensions.
257
258 ByteString bizarroData = GetBizarroData();
259 TestAllExtensions allExtensionsMessage = TestAllExtensions.ParseFrom(bizarroData);
260 TestEmptyMessage emptyMessage = TestEmptyMessage.ParseFrom(bizarroData);
261
262 // All fields should have been interpreted as unknown, so the debug strings
263 // should be the same.
264 Assert.AreEqual(emptyMessage.ToString(),
265 allExtensionsMessage.ToString());
266 }
267
268 [Test]
269 public void ParseUnknownEnumValue() {
270 FieldDescriptor singularField = TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("optional_nested_enum");
271 FieldDescriptor repeatedField = TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("repeated_nested_enum");
272 Assert.IsNotNull(singularField);
273 Assert.IsNotNull(repeatedField);
274
275 ByteString data =
276 UnknownFieldSet.CreateBuilder()
277 .AddField(singularField.FieldNumber,
278 UnknownField.CreateBuilder()
279 .AddVarint((int) TestAllTypes.Types.NestedEnum.BAR)
280 .AddVarint(5) // not valid
281 .Build())
282 .AddField(repeatedField.FieldNumber,
283 UnknownField.CreateBuilder()
284 .AddVarint((int) TestAllTypes.Types.NestedEnum.FOO)
285 .AddVarint(4) // not valid
286 .AddVarint((int) TestAllTypes.Types.NestedEnum.BAZ)
287 .AddVarint(6) // not valid
288 .Build())
289 .Build()
290 .ToByteString();
291
292 {
293 TestAllTypes message = TestAllTypes.ParseFrom(data);
294 Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR,
295 message.OptionalNestedEnum);
296 TestUtil.AssertEqual(new [] {TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.BAZ},
297 message.RepeatedNestedEnumList);
298 TestUtil.AssertEqual(new[] {5UL}, message.UnknownFields[singularField.FieldNumber].VarintList);
299 TestUtil.AssertEqual(new[] {4UL, 6UL}, message.UnknownFields[repeatedField.FieldNumber].VarintList);
300 }
301
302 {
303 TestAllExtensions message =
304 TestAllExtensions.ParseFrom(data, TestUtil.CreateExtensionRegistry());
305 Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR,
306 message.GetExtension(UnitTestProtoFile.OptionalNestedEnumExtension));
307 TestUtil.AssertEqual(new[] { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.BAZ },
308 message.GetExtension(UnitTestProtoFile.RepeatedNestedEnumExtension));
309 TestUtil.AssertEqual(new[] { 5UL }, message.UnknownFields[singularField.FieldNumber].VarintList);
310 TestUtil.AssertEqual(new[] { 4UL, 6UL }, message.UnknownFields[repeatedField.FieldNumber].VarintList);
311 }
312 }
313
314 [Test]
315 public void LargeVarint() {
316 ByteString data =
317 UnknownFieldSet.CreateBuilder()
318 .AddField(1,
319 UnknownField.CreateBuilder()
320 .AddVarint(0x7FFFFFFFFFFFFFFFL)
321 .Build())
322 .Build()
323 .ToByteString();
324 UnknownFieldSet parsed = UnknownFieldSet.ParseFrom(data);
325 UnknownField field = parsed[1];
326 Assert.AreEqual(1, field.VarintList.Count);
327 Assert.AreEqual(0x7FFFFFFFFFFFFFFFUL, field.VarintList[0]);
328 }
Jon Skeet43da7ae2009-05-28 21:45:43 +0100329
330 [Test]
331 public void EqualsAndHashCode() {
332 UnknownField fixed32Field = UnknownField.CreateBuilder().AddFixed32(1).Build();
333 UnknownField fixed64Field = UnknownField.CreateBuilder().AddFixed64(1).Build();
334 UnknownField varIntField = UnknownField.CreateBuilder().AddVarint(1).Build();
335 UnknownField lengthDelimitedField = UnknownField.CreateBuilder().AddLengthDelimited(ByteString.Empty).Build();
336 UnknownField groupField = UnknownField.CreateBuilder().AddGroup(unknownFields).Build();
337
338 UnknownFieldSet a = UnknownFieldSet.CreateBuilder().AddField(1, fixed32Field).Build();
339 UnknownFieldSet b = UnknownFieldSet.CreateBuilder().AddField(1, fixed64Field).Build();
340 UnknownFieldSet c = UnknownFieldSet.CreateBuilder().AddField(1, varIntField).Build();
341 UnknownFieldSet d = UnknownFieldSet.CreateBuilder().AddField(1, lengthDelimitedField).Build();
342 UnknownFieldSet e = UnknownFieldSet.CreateBuilder().AddField(1, groupField).Build();
343
344 CheckEqualsIsConsistent(a);
345 CheckEqualsIsConsistent(b);
346 CheckEqualsIsConsistent(c);
347 CheckEqualsIsConsistent(d);
348 CheckEqualsIsConsistent(e);
349
350 CheckNotEqual(a, b);
351 CheckNotEqual(a, c);
352 CheckNotEqual(a, d);
353 CheckNotEqual(a, e);
354 CheckNotEqual(b, c);
355 CheckNotEqual(b, d);
356 CheckNotEqual(b, e);
357 CheckNotEqual(c, d);
358 CheckNotEqual(c, e);
359 CheckNotEqual(d, e);
360 }
361
362 /// <summary>
363 /// Asserts that the given field sets are not equal and have different
364 /// hash codes.
365 /// </summary>
366 /// <remarks>
367 /// It's valid for non-equal objects to have the same hash code, so
368 /// this test is stricter than it needs to be. However, this should happen
369 /// relatively rarely.
370 /// </remarks>
371 /// <param name="s1"></param>
372 /// <param name="s2"></param>
373 private static void CheckNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
374 String equalsError = string.Format("{0} should not be equal to {1}", s1, s2);
375 Assert.IsFalse(s1.Equals(s2), equalsError);
376 Assert.IsFalse(s2.Equals(s1), equalsError);
377
378 Assert.IsFalse(s1.GetHashCode() == s2.GetHashCode(),
379 string.Format("{0} should have a different hash code from {1}", s1, s2));
380
381 }
382
383 /**
384 * Asserts that the given field sets are equal and have identical hash codes.
385 */
386 private static void CheckEqualsIsConsistent(UnknownFieldSet set) {
387 // Object should be equal to itself.
388 Assert.AreEqual(set, set);
389
390 // Object should be equal to a copy of itself.
391 UnknownFieldSet copy = UnknownFieldSet.CreateBuilder(set).Build();
392 Assert.AreEqual(set, copy);
393 Assert.AreEqual(copy, set);
394 Assert.AreEqual(set.GetHashCode(), copy.GetHashCode());
395 }
Jon Skeet68036862008-10-22 13:30:34 +0100396 }
397}