#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.IO; using System.Reflection; using Google.ProtocolBuffers.Descriptors; using Google.ProtocolBuffers.TestProtos; using NUnit.Framework; namespace Google.ProtocolBuffers { public class WireFormatTest { /// /// Keeps the attributes on FieldType and the switch statement in WireFormat in sync. /// [Test] public void FieldTypeToWireTypeMapping() { foreach (FieldInfo field in typeof(FieldType).GetFields(BindingFlags.Static | BindingFlags.Public)) { FieldType fieldType = (FieldType) field.GetValue(null); FieldMappingAttribute mapping = (FieldMappingAttribute) field.GetCustomAttributes(typeof(FieldMappingAttribute), false)[0]; Assert.AreEqual(mapping.WireType, WireFormat.GetWireType(fieldType)); } } [Test] public void Serialization() { TestAllTypes message = TestUtil.GetAllSet(); ByteString rawBytes = message.ToByteString(); Assert.AreEqual(rawBytes.Length, message.SerializedSize); TestAllTypes message2 = TestAllTypes.ParseFrom(rawBytes); TestUtil.AssertAllFieldsSet(message2); } [Test] public void SerializationPacked() { TestPackedTypes message = TestUtil.GetPackedSet(); ByteString rawBytes = message.ToByteString(); Assert.AreEqual(rawBytes.Length, message.SerializedSize); TestPackedTypes message2 = TestPackedTypes.ParseFrom(rawBytes); TestUtil.AssertPackedFieldsSet(message2); } [Test] public void SerializeExtensions() { // TestAllTypes and TestAllExtensions should have compatible wire formats, // so if we serialize a TestAllExtensions then parse it as TestAllTypes // it should work. TestAllExtensions message = TestUtil.GetAllExtensionsSet(); ByteString rawBytes = message.ToByteString(); Assert.AreEqual(rawBytes.Length, message.SerializedSize); TestAllTypes message2 = TestAllTypes.ParseFrom(rawBytes); TestUtil.AssertAllFieldsSet(message2); } [Test] public void SerializePackedExtensions() { // TestPackedTypes and TestPackedExtensions should have compatible wire // formats; check that they serialize to the same string. TestPackedExtensions message = TestUtil.GetPackedExtensionsSet(); ByteString rawBytes = message.ToByteString(); TestPackedTypes message2 = TestUtil.GetPackedSet(); ByteString rawBytes2 = message2.ToByteString(); Assert.AreEqual(rawBytes, rawBytes2); } [Test] public void SerializeDelimited() { MemoryStream stream = new MemoryStream(); TestUtil.GetAllSet().WriteDelimitedTo(stream); stream.WriteByte(12); TestUtil.GetPackedSet().WriteDelimitedTo(stream); stream.WriteByte(34); stream.Position = 0; TestUtil.AssertAllFieldsSet(TestAllTypes.ParseDelimitedFrom(stream)); Assert.AreEqual(12, stream.ReadByte()); TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseDelimitedFrom(stream)); Assert.AreEqual(34, stream.ReadByte()); Assert.AreEqual(-1, stream.ReadByte()); } [Test] public void ParseExtensions() { // TestAllTypes and TestAllExtensions should have compatible wire formats, // so if we serealize a TestAllTypes then parse it as TestAllExtensions // it should work. TestAllTypes message = TestUtil.GetAllSet(); ByteString rawBytes = message.ToByteString(); ExtensionRegistry registry = ExtensionRegistry.CreateInstance(); TestUtil.RegisterAllExtensions(registry); registry = registry.AsReadOnly(); TestAllExtensions message2 = TestAllExtensions.ParseFrom(rawBytes, registry); TestUtil.AssertAllExtensionsSet(message2); } [Test] public void ParsePackedExtensions() { // Ensure that packed extensions can be properly parsed. TestPackedExtensions message = TestUtil.GetPackedExtensionsSet(); ByteString rawBytes = message.ToByteString(); ExtensionRegistry registry = TestUtil.CreateExtensionRegistry(); TestPackedExtensions message2 = TestPackedExtensions.ParseFrom(rawBytes, registry); TestUtil.AssertPackedExtensionsSet(message2); } [Test] public void ExtensionsSerializedSize() { Assert.IsTrue(TestUtil.GetAllSet().SerializedSize < TestUtil.GetAllExtensionsSet().SerializedSize); } private static void AssertFieldsInOrder(ByteString data) { CodedInputStream input = data.CreateCodedInput(); uint previousTag = 0; uint tag; string name; while (input.ReadTag(out tag, out name)) { Assert.IsTrue(tag > previousTag); previousTag = tag; input.SkipField(); } } [Test] public void InterleavedFieldsAndExtensions() { // Tests that fields are written in order even when extension ranges // are interleaved with field numbers. ByteString data = TestFieldOrderings.CreateBuilder() .SetMyInt(1) .SetMyString("foo") .SetMyFloat(1.0F) .SetExtension(Unittest.MyExtensionInt, 23) .SetExtension(Unittest.MyExtensionString, "bar") .Build().ToByteString(); AssertFieldsInOrder(data); MessageDescriptor descriptor = TestFieldOrderings.Descriptor; ByteString dynamic_data = DynamicMessage.CreateBuilder(TestFieldOrderings.Descriptor) .SetField(descriptor.FindDescriptor("my_int"), 1L) .SetField(descriptor.FindDescriptor("my_string"), "foo") .SetField(descriptor.FindDescriptor("my_float"), 1.0F) .SetField(Unittest.MyExtensionInt.Descriptor, 23) .SetField(Unittest.MyExtensionString.Descriptor, "bar") .WeakBuild().ToByteString(); AssertFieldsInOrder(dynamic_data); } private const int UnknownTypeId = 1550055; private static readonly int TypeId1 = TestMessageSetExtension1.Descriptor.Extensions[0].FieldNumber; private static readonly int TypeId2 = TestMessageSetExtension2.Descriptor.Extensions[0].FieldNumber; [Test] public void SerializeMessageSet() { // Set up a TestMessageSet with two known messages and an unknown one. TestMessageSet messageSet = TestMessageSet.CreateBuilder() .SetExtension( TestMessageSetExtension1.MessageSetExtension, TestMessageSetExtension1.CreateBuilder().SetI(123).Build()) .SetExtension( TestMessageSetExtension2.MessageSetExtension, TestMessageSetExtension2.CreateBuilder().SetStr("foo").Build()) .SetUnknownFields( UnknownFieldSet.CreateBuilder() .AddField(UnknownTypeId, UnknownField.CreateBuilder() .AddLengthDelimited(ByteString.CopyFromUtf8("bar")) .Build()) .Build()) .Build(); ByteString data = messageSet.ToByteString(); // Parse back using RawMessageSet and check the contents. RawMessageSet raw = RawMessageSet.ParseFrom(data); Assert.AreEqual(0, raw.UnknownFields.FieldDictionary.Count); Assert.AreEqual(3, raw.ItemCount); Assert.AreEqual(TypeId1, raw.ItemList[0].TypeId); Assert.AreEqual(TypeId2, raw.ItemList[1].TypeId); Assert.AreEqual(UnknownTypeId, raw.ItemList[2].TypeId); TestMessageSetExtension1 message1 = TestMessageSetExtension1.ParseFrom(raw.GetItem(0).Message.ToByteArray()); Assert.AreEqual(123, message1.I); TestMessageSetExtension2 message2 = TestMessageSetExtension2.ParseFrom(raw.GetItem(1).Message.ToByteArray()); Assert.AreEqual("foo", message2.Str); Assert.AreEqual("bar", raw.GetItem(2).Message.ToStringUtf8()); } [Test] public void ParseMessageSet() { ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance(); extensionRegistry.Add(TestMessageSetExtension1.MessageSetExtension); extensionRegistry.Add(TestMessageSetExtension2.MessageSetExtension); // Set up a RawMessageSet with two known messages and an unknown one. RawMessageSet raw = RawMessageSet.CreateBuilder() .AddItem( RawMessageSet.Types.Item.CreateBuilder() .SetTypeId(TypeId1) .SetMessage( TestMessageSetExtension1.CreateBuilder() .SetI(123) .Build().ToByteString()) .Build()) .AddItem( RawMessageSet.Types.Item.CreateBuilder() .SetTypeId(TypeId2) .SetMessage( TestMessageSetExtension2.CreateBuilder() .SetStr("foo") .Build().ToByteString()) .Build()) .AddItem( RawMessageSet.Types.Item.CreateBuilder() .SetTypeId(UnknownTypeId) .SetMessage(ByteString.CopyFromUtf8("bar")) .Build()) .Build(); ByteString data = raw.ToByteString(); // Parse as a TestMessageSet and check the contents. TestMessageSet messageSet = TestMessageSet.ParseFrom(data, extensionRegistry); Assert.AreEqual(123, messageSet.GetExtension(TestMessageSetExtension1.MessageSetExtension).I); Assert.AreEqual("foo", messageSet.GetExtension(TestMessageSetExtension2.MessageSetExtension).Str); // Check for unknown field with type LENGTH_DELIMITED, // number UNKNOWN_TYPE_ID, and contents "bar". UnknownFieldSet unknownFields = messageSet.UnknownFields; Assert.AreEqual(1, unknownFields.FieldDictionary.Count); Assert.IsTrue(unknownFields.HasField(UnknownTypeId)); UnknownField field = unknownFields[UnknownTypeId]; Assert.AreEqual(1, field.LengthDelimitedList.Count); Assert.AreEqual("bar", field.LengthDelimitedList[0].ToStringUtf8()); } } }