#region Copyright notice and license // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // http://github.com/jskeet/dotnet-protobufs/ // Original C++/Java/Python code: // http://code.google.com/p/protobuf/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion using System; using System.Collections.Generic; using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.TestProtos; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Google.ProtocolBuffers { [TestClass] public class UnknownFieldSetTest { private MessageDescriptor descriptor; private TestAllTypes allFields; private ByteString allFieldsData; /// /// An empty message that has been parsed from allFieldsData. So, it has /// unknown fields of every type. /// private TestEmptyMessage emptyMessage; private UnknownFieldSet unknownFields; [TestInitialize] public void SetUp() { descriptor = TestAllTypes.Descriptor; allFields = TestUtil.GetAllSet(); allFieldsData = allFields.ToByteString(); emptyMessage = TestEmptyMessage.ParseFrom(allFieldsData); unknownFields = emptyMessage.UnknownFields; } private UnknownField GetField(String name) { FieldDescriptor field = descriptor.FindDescriptor(name); Assert.IsNotNull(field); return unknownFields.FieldDictionary[field.FieldNumber]; } /// /// Constructs a protocol buffer which contains fields with all the same /// numbers as allFieldsData except that each field is some other wire /// type. /// private ByteString GetBizarroData() { UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.CreateBuilder(); UnknownField varintField = UnknownField.CreateBuilder().AddVarint(1).Build(); UnknownField fixed32Field = UnknownField.CreateBuilder().AddFixed32(1).Build(); foreach (KeyValuePair entry in unknownFields.FieldDictionary) { if (entry.Value.VarintList.Count == 0) { // Original field is not a varint, so use a varint. bizarroFields.AddField(entry.Key, varintField); } else { // Original field *is* a varint, so use something else. bizarroFields.AddField(entry.Key, fixed32Field); } } return bizarroFields.Build().ToByteString(); } // ================================================================= [TestMethod] public void Varint() { UnknownField field = GetField("optional_int32"); Assert.AreEqual(1, field.VarintList.Count); Assert.AreEqual(allFields.OptionalInt32, (long) field.VarintList[0]); } [TestMethod] public void Fixed32() { UnknownField field = GetField("optional_fixed32"); Assert.AreEqual(1, field.Fixed32List.Count); Assert.AreEqual(allFields.OptionalFixed32, (int) field.Fixed32List[0]); } [TestMethod] public void Fixed64() { UnknownField field = GetField("optional_fixed64"); Assert.AreEqual(1, field.Fixed64List.Count); Assert.AreEqual((long)allFields.OptionalFixed64, (long)field.Fixed64List[0]); } [TestMethod] public void LengthDelimited() { UnknownField field = GetField("optional_bytes"); Assert.AreEqual(1, field.LengthDelimitedList.Count); Assert.AreEqual(allFields.OptionalBytes, field.LengthDelimitedList[0]); } [TestMethod] public void Group() { FieldDescriptor nestedFieldDescriptor = TestAllTypes.Types.OptionalGroup.Descriptor.FindDescriptor("a"); Assert.IsNotNull(nestedFieldDescriptor); UnknownField field = GetField("optionalgroup"); Assert.AreEqual(1, field.GroupList.Count); UnknownFieldSet group = field.GroupList[0]; Assert.AreEqual(1, group.FieldDictionary.Count); Assert.IsTrue(group.HasField(nestedFieldDescriptor.FieldNumber)); UnknownField nestedField = group[nestedFieldDescriptor.FieldNumber]; Assert.AreEqual(1, nestedField.VarintList.Count); Assert.AreEqual(allFields.OptionalGroup.A, (long) nestedField.VarintList[0]); } [TestMethod] public void Serialize() { // Check that serializing the UnknownFieldSet produces the original data again. ByteString data = emptyMessage.ToByteString(); Assert.AreEqual(allFieldsData, data); } [TestMethod] public void CopyFrom() { TestEmptyMessage message = TestEmptyMessage.CreateBuilder().MergeFrom(emptyMessage).Build(); Assert.AreEqual(emptyMessage.ToString(), message.ToString()); } [TestMethod] public void MergeFrom() { TestEmptyMessage source = TestEmptyMessage.CreateBuilder() .SetUnknownFields( UnknownFieldSet.CreateBuilder() .AddField(2, UnknownField.CreateBuilder() .AddVarint(2).Build()) .AddField(3, UnknownField.CreateBuilder() .AddVarint(4).Build()) .Build()) .Build(); TestEmptyMessage destination = TestEmptyMessage.CreateBuilder() .SetUnknownFields( UnknownFieldSet.CreateBuilder() .AddField(1, UnknownField.CreateBuilder() .AddVarint(1).Build()) .AddField(3, UnknownField.CreateBuilder() .AddVarint(3).Build()) .Build()) .MergeFrom(source) .Build(); Assert.AreEqual( "1: 1\n" + "2: 2\n" + "3: 3\n" + "3: 4\n", destination.ToString()); } [TestMethod] public void Clear() { UnknownFieldSet fields = UnknownFieldSet.CreateBuilder().MergeFrom(unknownFields).Clear().Build(); Assert.AreEqual(0, fields.FieldDictionary.Count); } [TestMethod] public void ClearMessage() { TestEmptyMessage message = TestEmptyMessage.CreateBuilder().MergeFrom(emptyMessage).Clear().Build(); Assert.AreEqual(0, message.SerializedSize); } [TestMethod] public void ParseKnownAndUnknown() { // Test mixing known and unknown fields when parsing. UnknownFieldSet fields = UnknownFieldSet.CreateBuilder(unknownFields) .AddField(123456, UnknownField.CreateBuilder().AddVarint(654321).Build()) .Build(); ByteString data = fields.ToByteString(); TestAllTypes destination = TestAllTypes.ParseFrom(data); TestUtil.AssertAllFieldsSet(destination); Assert.AreEqual(1, destination.UnknownFields.FieldDictionary.Count); UnknownField field = destination.UnknownFields[123456]; Assert.AreEqual(1, field.VarintList.Count); Assert.AreEqual(654321, (long) field.VarintList[0]); } [TestMethod] public void WrongTypeTreatedAsUnknown() { // Test that fields of the wrong wire type are treated like unknown fields // when parsing. ByteString bizarroData = GetBizarroData(); TestAllTypes allTypesMessage = TestAllTypes.ParseFrom(bizarroData); TestEmptyMessage emptyMessage = TestEmptyMessage.ParseFrom(bizarroData); // All fields should have been interpreted as unknown, so the debug strings // should be the same. Assert.AreEqual(emptyMessage.ToString(), allTypesMessage.ToString()); } [TestMethod] public void UnknownExtensions() { // Make sure fields are properly parsed to the UnknownFieldSet even when // they are declared as extension numbers. TestEmptyMessageWithExtensions message = TestEmptyMessageWithExtensions.ParseFrom(allFieldsData); Assert.AreEqual(unknownFields.FieldDictionary.Count, message.UnknownFields.FieldDictionary.Count); Assert.AreEqual(allFieldsData, message.ToByteString()); } [TestMethod] public void WrongExtensionTypeTreatedAsUnknown() { // Test that fields of the wrong wire type are treated like unknown fields // when parsing extensions. ByteString bizarroData = GetBizarroData(); TestAllExtensions allExtensionsMessage = TestAllExtensions.ParseFrom(bizarroData); TestEmptyMessage emptyMessage = TestEmptyMessage.ParseFrom(bizarroData); // All fields should have been interpreted as unknown, so the debug strings // should be the same. Assert.AreEqual(emptyMessage.ToString(), allExtensionsMessage.ToString()); } [TestMethod] public void ParseUnknownEnumValue() { FieldDescriptor singularField = TestAllTypes.Descriptor.FindDescriptor("optional_nested_enum"); FieldDescriptor repeatedField = TestAllTypes.Descriptor.FindDescriptor("repeated_nested_enum"); Assert.IsNotNull(singularField); Assert.IsNotNull(repeatedField); ByteString data = UnknownFieldSet.CreateBuilder() .AddField(singularField.FieldNumber, UnknownField.CreateBuilder() .AddVarint((int) TestAllTypes.Types.NestedEnum.BAR) .AddVarint(5) // not valid .Build()) .AddField(repeatedField.FieldNumber, UnknownField.CreateBuilder() .AddVarint((int) TestAllTypes.Types.NestedEnum.FOO) .AddVarint(4) // not valid .AddVarint((int) TestAllTypes.Types.NestedEnum.BAZ) .AddVarint(6) // not valid .Build()) .Build() .ToByteString(); { TestAllTypes message = TestAllTypes.ParseFrom(data); Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR, message.OptionalNestedEnum); TestUtil.AssertEqual(new[] {TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.BAZ}, message.RepeatedNestedEnumList); TestUtil.AssertEqual(new[] {5UL}, message.UnknownFields[singularField.FieldNumber].VarintList); TestUtil.AssertEqual(new[] {4UL, 6UL}, message.UnknownFields[repeatedField.FieldNumber].VarintList); } { TestAllExtensions message = TestAllExtensions.ParseFrom(data, TestUtil.CreateExtensionRegistry()); Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR, message.GetExtension(UnitTestProtoFile.OptionalNestedEnumExtension)); TestUtil.AssertEqual(new[] {TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.BAZ}, message.GetExtension(UnitTestProtoFile.RepeatedNestedEnumExtension)); TestUtil.AssertEqual(new[] {5UL}, message.UnknownFields[singularField.FieldNumber].VarintList); TestUtil.AssertEqual(new[] {4UL, 6UL}, message.UnknownFields[repeatedField.FieldNumber].VarintList); } } [TestMethod] public void LargeVarint() { ByteString data = UnknownFieldSet.CreateBuilder() .AddField(1, UnknownField.CreateBuilder() .AddVarint(0x7FFFFFFFFFFFFFFFL) .Build()) .Build() .ToByteString(); UnknownFieldSet parsed = UnknownFieldSet.ParseFrom(data); UnknownField field = parsed[1]; Assert.AreEqual(1, field.VarintList.Count); Assert.AreEqual(0x7FFFFFFFFFFFFFFFUL, field.VarintList[0]); } [TestMethod] public void EqualsAndHashCode() { UnknownField fixed32Field = UnknownField.CreateBuilder().AddFixed32(1).Build(); UnknownField fixed64Field = UnknownField.CreateBuilder().AddFixed64(1).Build(); UnknownField varIntField = UnknownField.CreateBuilder().AddVarint(1).Build(); UnknownField lengthDelimitedField = UnknownField.CreateBuilder().AddLengthDelimited(ByteString.Empty).Build(); UnknownField groupField = UnknownField.CreateBuilder().AddGroup(unknownFields).Build(); UnknownFieldSet a = UnknownFieldSet.CreateBuilder().AddField(1, fixed32Field).Build(); UnknownFieldSet b = UnknownFieldSet.CreateBuilder().AddField(1, fixed64Field).Build(); UnknownFieldSet c = UnknownFieldSet.CreateBuilder().AddField(1, varIntField).Build(); UnknownFieldSet d = UnknownFieldSet.CreateBuilder().AddField(1, lengthDelimitedField).Build(); UnknownFieldSet e = UnknownFieldSet.CreateBuilder().AddField(1, groupField).Build(); CheckEqualsIsConsistent(a); CheckEqualsIsConsistent(b); CheckEqualsIsConsistent(c); CheckEqualsIsConsistent(d); CheckEqualsIsConsistent(e); CheckNotEqual(a, b); CheckNotEqual(a, c); CheckNotEqual(a, d); CheckNotEqual(a, e); CheckNotEqual(b, c); CheckNotEqual(b, d); CheckNotEqual(b, e); CheckNotEqual(c, d); CheckNotEqual(c, e); CheckNotEqual(d, e); } /// /// Asserts that the given field sets are not equal and have different /// hash codes. /// /// /// It's valid for non-equal objects to have the same hash code, so /// this test is stricter than it needs to be. However, this should happen /// relatively rarely. /// /// /// private static void CheckNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) { String equalsError = string.Format("{0} should not be equal to {1}", s1, s2); Assert.IsFalse(s1.Equals(s2), equalsError); Assert.IsFalse(s2.Equals(s1), equalsError); Assert.IsFalse(s1.GetHashCode() == s2.GetHashCode(), string.Format("{0} should have a different hash code from {1}", s1, s2)); } /** * Asserts that the given field sets are equal and have identical hash codes. */ private static void CheckEqualsIsConsistent(UnknownFieldSet set) { // Object should be equal to itself. Assert.AreEqual(set, set); // Object should be equal to a copy of itself. UnknownFieldSet copy = UnknownFieldSet.CreateBuilder(set).Build(); Assert.AreEqual(set, copy); Assert.AreEqual(copy, set); Assert.AreEqual(set.GetHashCode(), copy.GetHashCode()); } } }