Jon Skeet | 0aac0e4 | 2009-09-09 18:48:02 +0100 | [diff] [blame] | 1 | #region Copyright notice and license |
Jon Skeet | 60c059b | 2008-10-23 21:17:56 +0100 | [diff] [blame] | 2 | // 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 Skeet | 6803686 | 2008-10-22 13:30:34 +0100 | [diff] [blame] | 6 | // http://code.google.com/p/protobuf/ |
| 7 | // |
Jon Skeet | 60c059b | 2008-10-23 21:17:56 +0100 | [diff] [blame] | 8 | // Redistribution and use in source and binary forms, with or without |
| 9 | // modification, are permitted provided that the following conditions are |
| 10 | // met: |
Jon Skeet | 6803686 | 2008-10-22 13:30:34 +0100 | [diff] [blame] | 11 | // |
Jon Skeet | 60c059b | 2008-10-23 21:17:56 +0100 | [diff] [blame] | 12 | // * 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 Skeet | 6803686 | 2008-10-22 13:30:34 +0100 | [diff] [blame] | 21 | // |
Jon Skeet | 60c059b | 2008-10-23 21:17:56 +0100 | [diff] [blame] | 22 | // 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 Skeet | 0aac0e4 | 2009-09-09 18:48:02 +0100 | [diff] [blame] | 33 | #endregion |
| 34 | |
Jon Skeet | 6803686 | 2008-10-22 13:30:34 +0100 | [diff] [blame] | 35 | using System; |
| 36 | using System.Collections.Generic; |
| 37 | using Google.ProtocolBuffers.Descriptors; |
| 38 | using Google.ProtocolBuffers.TestProtos; |
| 39 | using NUnit.Framework; |
| 40 | |
| 41 | namespace 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 Skeet | 43da7ae | 2009-05-28 21:45:43 +0100 | [diff] [blame] | 332 | |
| 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 Skeet | 6803686 | 2008-10-22 13:30:34 +0100 | [diff] [blame] | 399 | } |
| 400 | } |