From d6c9495797d202a19a93dee724c3c9fc0d6564c6 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 14 Aug 2008 20:35:28 +0100 Subject: [PATCH] More tests, and a bug fix. --- csharp/ProtocolBuffers.Test/WireFormatTest.cs | 192 ++++++++++++++++++ csharp/ProtocolBuffers/DynamicMessage.cs | 2 +- csharp/ProtocolBuffers/ExtendableMessage.cs | 2 +- csharp/ProtocolBuffers/FieldSet.cs | 7 +- csharp/ProtocolBuffers/IBuilder.cs | 24 +-- csharp/ProtocolBuffers/RpcUtil.cs | 2 +- .../com/google/protobuf/WireFormatTest.java | 1 + 7 files changed, 212 insertions(+), 18 deletions(-) diff --git a/csharp/ProtocolBuffers.Test/WireFormatTest.cs b/csharp/ProtocolBuffers.Test/WireFormatTest.cs index 87c9dc6d3e..ecf8730669 100644 --- a/csharp/ProtocolBuffers.Test/WireFormatTest.cs +++ b/csharp/ProtocolBuffers.Test/WireFormatTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Google.ProtocolBuffers.TestProtos; using NUnit.Framework; using Google.ProtocolBuffers.Descriptors; @@ -16,5 +17,196 @@ namespace Google.ProtocolBuffers { Assert.AreEqual(WireFormat.WireType.LengthDelimited, WireFormat.FieldTypeToWireFormatMap[FieldType.String]); Assert.AreEqual(WireFormat.WireType.LengthDelimited, WireFormat.FieldTypeToWireFormatMap[FieldType.Message]); } + + [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 SerializeExtensions() { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serealize 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 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 ExtensionsSerializedSize() { + Assert.AreEqual(TestUtil.GetAllSet().SerializedSize, TestUtil.GetAllExtensionsSet().SerializedSize); + } + + private void AssertFieldsInOrder(ByteString data) { + CodedInputStream input = data.CreateCodedInput(); + uint previousTag = 0; + + while (true) { + uint tag = input.ReadTag(); + if (tag == 0) { + break; + } + + Assert.IsTrue(tag > previousTag); + previousTag = tag; + input.SkipField(tag); + } + } + + [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(UnitTestProtoFile.MyExtensionInt, 23) + .SetExtension(UnitTestProtoFile.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(UnitTestProtoFile.MyExtensionInt.Descriptor, 23) + .SetField(UnitTestProtoFile.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.Types.MessageSetExtension, + TestMessageSetExtension1.CreateBuilder().SetI(123).Build()) + .SetExtension( + TestMessageSetExtension2.Types.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.Types.MessageSetExtension); + extensionRegistry.Add(TestMessageSetExtension2.Types.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.Types.MessageSetExtension).I); + Assert.AreEqual("foo", messageSet.GetExtension(TestMessageSetExtension2.Types.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()); + } + } } diff --git a/csharp/ProtocolBuffers/DynamicMessage.cs b/csharp/ProtocolBuffers/DynamicMessage.cs index f0f4cde174..224b8deedb 100644 --- a/csharp/ProtocolBuffers/DynamicMessage.cs +++ b/csharp/ProtocolBuffers/DynamicMessage.cs @@ -233,7 +233,7 @@ namespace Google.ProtocolBuffers { internal Builder(MessageDescriptor type) { this.type = type; - this.fields = FieldSet.CreateFieldSet(); + this.fields = FieldSet.CreateInstance(); this.unknownFields = UnknownFieldSet.DefaultInstance; } diff --git a/csharp/ProtocolBuffers/ExtendableMessage.cs b/csharp/ProtocolBuffers/ExtendableMessage.cs index 60d0d5831c..84a69b53ac 100644 --- a/csharp/ProtocolBuffers/ExtendableMessage.cs +++ b/csharp/ProtocolBuffers/ExtendableMessage.cs @@ -10,7 +10,7 @@ namespace Google.ProtocolBuffers { where TBuilder : GeneratedBuilder { protected ExtendableMessage() {} - private readonly FieldSet extensions = FieldSet.CreateFieldSet(); + private readonly FieldSet extensions = FieldSet.CreateInstance(); /// /// Access for the builder. diff --git a/csharp/ProtocolBuffers/FieldSet.cs b/csharp/ProtocolBuffers/FieldSet.cs index 79394ca495..6e563e7bf0 100644 --- a/csharp/ProtocolBuffers/FieldSet.cs +++ b/csharp/ProtocolBuffers/FieldSet.cs @@ -30,8 +30,9 @@ namespace Google.ProtocolBuffers { this.fields = fields; } - public static FieldSet CreateFieldSet() { - return new FieldSet(new Dictionary()); + public static FieldSet CreateInstance() { + // Use SortedList to keep fields in the canonical order + return new FieldSet(new SortedList()); } /// @@ -507,7 +508,7 @@ namespace Google.ProtocolBuffers { } /// - /// See + /// See /// public void MergeFrom(IMessage other) { MergeFields(other.AllFields); diff --git a/csharp/ProtocolBuffers/IBuilder.cs b/csharp/ProtocolBuffers/IBuilder.cs index 52263feb69..4499079297 100644 --- a/csharp/ProtocolBuffers/IBuilder.cs +++ b/csharp/ProtocolBuffers/IBuilder.cs @@ -35,6 +35,18 @@ namespace Google.ProtocolBuffers { /// bool IsInitialized { get; } + /// + /// Only present in the nongeneric interface - useful for tests, but + /// not as much in real life. + /// + IBuilder SetField(FieldDescriptor field, object value); + + /// + /// Only present in the nongeneric interface - useful for tests, but + /// not as much in real life. + /// + IBuilder SetRepeatedField(FieldDescriptor field, int index, object value); + /// /// Behaves like the equivalent property in IMessage<T>. /// The returned map may or may not reflect future changes to the builder. @@ -56,18 +68,6 @@ namespace Google.ProtocolBuffers { /// MessageDescriptor DescriptorForType { get; } - /// - /// Only present in the nongeneric interface - useful for tests, but - /// not as much in real life. - /// - IBuilder SetField(FieldDescriptor field, object value); - - /// - /// Only present in the nongeneric interface - useful for tests, but - /// not as much in real life. - /// - IBuilder SetRepeatedField(FieldDescriptor field, int index, object value); - /// /// /// diff --git a/csharp/ProtocolBuffers/RpcUtil.cs b/csharp/ProtocolBuffers/RpcUtil.cs index ebd3f47f6e..92675c0258 100644 --- a/csharp/ProtocolBuffers/RpcUtil.cs +++ b/csharp/ProtocolBuffers/RpcUtil.cs @@ -26,7 +26,7 @@ namespace Google.ProtocolBuffers { where TBuilder : IBuilder { return message => { TMessage castMessage = message as TMessage; - if (castMessage == null) { + if (castMessage == null) { castMessage = defaultInstance.CreateBuilderForType().MergeFrom(message).Build(); } action(castMessage); diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java index 84cc89f8a4..80f80030d9 100644 --- a/java/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java @@ -91,6 +91,7 @@ public class WireFormatTest extends TestCase { } assertTrue(tag > previousTag); + previousTag = tag; input.skipField(tag); } }