| #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 System.IO; | |
| using Google.ProtocolBuffers.Descriptors; | |
| using Microsoft.VisualStudio.TestTools.UnitTesting; | |
| using Google.ProtocolBuffers.TestProtos; | |
| namespace Google.ProtocolBuffers | |
| { | |
| [TestClass] | |
| public class AbstractMessageTest | |
| { | |
| [TestMethod] | |
| public void Clear() | |
| { | |
| AbstractMessageWrapper message = | |
| new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(TestUtil.GetAllSet())).Clear().Build(); | |
| TestUtil.AssertClear((TestAllTypes) message.WrappedMessage); | |
| } | |
| [TestMethod] | |
| public void Copy() | |
| { | |
| AbstractMessageWrapper message = | |
| new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder()).MergeFrom(TestUtil.GetAllSet()).Build(); | |
| TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage); | |
| } | |
| [TestMethod] | |
| public void CreateAndBuild() | |
| { | |
| TestAllTypes.CreateBuilder() | |
| .Build(); | |
| } | |
| [TestMethod] | |
| public void SerializedSize() | |
| { | |
| TestAllTypes message = TestUtil.GetAllSet(); | |
| IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet()); | |
| Assert.AreEqual(message.SerializedSize, abstractMessage.SerializedSize); | |
| } | |
| [TestMethod] | |
| public void Serialization() | |
| { | |
| IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetAllSet()); | |
| TestUtil.AssertAllFieldsSet(TestAllTypes.ParseFrom(abstractMessage.ToByteString())); | |
| Assert.AreEqual(TestUtil.GetAllSet().ToByteString(), abstractMessage.ToByteString()); | |
| } | |
| [TestMethod] | |
| public void Parsing() | |
| { | |
| IBuilder builder = new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder()); | |
| AbstractMessageWrapper message = | |
| (AbstractMessageWrapper) builder.WeakMergeFrom(TestUtil.GetAllSet().ToByteString()).WeakBuild(); | |
| TestUtil.AssertAllFieldsSet((TestAllTypes) message.WrappedMessage); | |
| } | |
| [TestMethod] | |
| public void PackedSerialization() | |
| { | |
| IMessage abstractMessage = new AbstractMessageWrapper(TestUtil.GetPackedSet()); | |
| TestUtil.AssertPackedFieldsSet(TestPackedTypes.ParseFrom(abstractMessage.ToByteString())); | |
| Assert.AreEqual(TestUtil.GetPackedSet().ToByteString(), abstractMessage.ToByteString()); | |
| } | |
| [TestMethod] | |
| public void PackedParsing() | |
| { | |
| AbstractMessageWrapper.Builder builder = new AbstractMessageWrapper.Builder(TestPackedTypes.CreateBuilder()); | |
| AbstractMessageWrapper message = builder.MergeFrom(TestUtil.GetPackedSet().ToByteString()).Build(); | |
| TestUtil.AssertPackedFieldsSet((TestPackedTypes)message.WrappedMessage); | |
| } | |
| [TestMethod] | |
| public void UnpackedParsingOfPackedInput() | |
| { | |
| byte[] bytes = TestUtil.GetPackedSet().ToByteArray(); | |
| TestUnpackedTypes message = TestUnpackedTypes.ParseFrom(bytes); | |
| TestUtil.AssertUnpackedFieldsSet(message); | |
| } | |
| [TestMethod] | |
| public void PackedParsingOfUnpackedInput() | |
| { | |
| byte[] bytes = TestUnpackedTypes.ParseFrom(TestUtil.GetPackedSet().ToByteArray()).ToByteArray(); | |
| TestPackedTypes message = TestPackedTypes.ParseFrom(bytes); | |
| TestUtil.AssertPackedFieldsSet(message); | |
| } | |
| [TestMethod] | |
| public void UnpackedParsingOfPackedInputExtensions() | |
| { | |
| byte[] bytes = TestUtil.GetPackedSet().ToByteArray(); | |
| ExtensionRegistry registry = ExtensionRegistry.CreateInstance(); | |
| Unittest.RegisterAllExtensions(registry); | |
| UnittestImport.RegisterAllExtensions(registry); | |
| TestUnpackedExtensions message = TestUnpackedExtensions.ParseFrom(bytes, registry); | |
| TestUtil.AssertUnpackedExtensionsSet(message); | |
| } | |
| [TestMethod] | |
| public void PackedParsingOfUnpackedInputExtensions() | |
| { | |
| byte[] bytes = TestUnpackedTypes.ParseFrom(TestUtil.GetPackedSet().ToByteArray()).ToByteArray(); | |
| ExtensionRegistry registry = ExtensionRegistry.CreateInstance(); | |
| Unittest.RegisterAllExtensions(registry); | |
| TestPackedExtensions message = TestPackedExtensions.ParseFrom(bytes, registry); | |
| TestUtil.AssertPackedExtensionsSet(message); | |
| } | |
| [TestMethod] | |
| public void OptimizedForSize() | |
| { | |
| // We're mostly only Checking that this class was compiled successfully. | |
| TestOptimizedForSize message = TestOptimizedForSize.CreateBuilder().SetI(1).Build(); | |
| message = TestOptimizedForSize.ParseFrom(message.ToByteString()); | |
| Assert.AreEqual(2, message.SerializedSize); | |
| } | |
| // ----------------------------------------------------------------- | |
| // Tests for isInitialized(). | |
| private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance; | |
| private static readonly TestRequired TestRequiredInitialized = | |
| TestRequired.CreateBuilder().SetA(1).SetB(2).SetC(3).Build(); | |
| [TestMethod] | |
| public void IsInitialized() | |
| { | |
| TestRequired.Builder builder = TestRequired.CreateBuilder(); | |
| AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder); | |
| Assert.IsFalse(abstractBuilder.IsInitialized); | |
| builder.A = 1; | |
| Assert.IsFalse(abstractBuilder.IsInitialized); | |
| builder.B = 1; | |
| Assert.IsFalse(abstractBuilder.IsInitialized); | |
| builder.C = 1; | |
| Assert.IsTrue(abstractBuilder.IsInitialized); | |
| } | |
| [TestMethod] | |
| public void ForeignIsInitialized() | |
| { | |
| TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder(); | |
| AbstractMessageWrapper.Builder abstractBuilder = new AbstractMessageWrapper.Builder(builder); | |
| Assert.IsTrue(abstractBuilder.IsInitialized); | |
| builder.SetOptionalMessage(TestRequiredUninitialized); | |
| Assert.IsFalse(abstractBuilder.IsInitialized); | |
| builder.SetOptionalMessage(TestRequiredInitialized); | |
| Assert.IsTrue(abstractBuilder.IsInitialized); | |
| builder.AddRepeatedMessage(TestRequiredUninitialized); | |
| Assert.IsFalse(abstractBuilder.IsInitialized); | |
| builder.SetRepeatedMessage(0, TestRequiredInitialized); | |
| Assert.IsTrue(abstractBuilder.IsInitialized); | |
| } | |
| // ----------------------------------------------------------------- | |
| // Tests for mergeFrom | |
| private static readonly TestAllTypes MergeSource = TestAllTypes.CreateBuilder() | |
| .SetOptionalInt32(1) | |
| .SetOptionalString("foo") | |
| .SetOptionalForeignMessage(ForeignMessage.DefaultInstance) | |
| .AddRepeatedString("bar") | |
| .Build(); | |
| private static readonly TestAllTypes MergeDest = TestAllTypes.CreateBuilder() | |
| .SetOptionalInt64(2) | |
| .SetOptionalString("baz") | |
| .SetOptionalForeignMessage(ForeignMessage.CreateBuilder().SetC(3).Build()) | |
| .AddRepeatedString("qux") | |
| .Build(); | |
| private const string MergeResultText = "optional_int32: 1\n" + | |
| "optional_int64: 2\n" + | |
| "optional_string: \"foo\"\n" + | |
| "optional_foreign_message {\n" + | |
| " c: 3\n" + | |
| "}\n" + | |
| "repeated_string: \"qux\"\n" + | |
| "repeated_string: \"bar\"\n"; | |
| [TestMethod] | |
| public void MergeFrom() | |
| { | |
| AbstractMessageWrapper result = (AbstractMessageWrapper) | |
| new AbstractMessageWrapper.Builder(TestAllTypes.CreateBuilder(MergeDest)) | |
| .MergeFrom(MergeSource) | |
| .Build(); | |
| Assert.AreEqual(MergeResultText, result.ToString()); | |
| } | |
| // ----------------------------------------------------------------- | |
| // Tests for equals and hashCode | |
| [TestMethod] | |
| public void EqualsAndHashCode() | |
| { | |
| TestAllTypes a = TestUtil.GetAllSet(); | |
| TestAllTypes b = TestAllTypes.CreateBuilder().Build(); | |
| TestAllTypes c = TestAllTypes.CreateBuilder(b).AddRepeatedString("x").Build(); | |
| TestAllTypes d = TestAllTypes.CreateBuilder(c).AddRepeatedString("y").Build(); | |
| TestAllExtensions e = TestUtil.GetAllExtensionsSet(); | |
| TestAllExtensions f = TestAllExtensions.CreateBuilder(e) | |
| .AddExtension(Unittest.RepeatedInt32Extension, 999).Build(); | |
| CheckEqualsIsConsistent(a); | |
| CheckEqualsIsConsistent(b); | |
| CheckEqualsIsConsistent(c); | |
| CheckEqualsIsConsistent(d); | |
| CheckEqualsIsConsistent(e); | |
| CheckEqualsIsConsistent(f); | |
| CheckNotEqual(a, b); | |
| CheckNotEqual(a, c); | |
| CheckNotEqual(a, d); | |
| CheckNotEqual(a, e); | |
| CheckNotEqual(a, f); | |
| CheckNotEqual(b, c); | |
| CheckNotEqual(b, d); | |
| CheckNotEqual(b, e); | |
| CheckNotEqual(b, f); | |
| CheckNotEqual(c, d); | |
| CheckNotEqual(c, e); | |
| CheckNotEqual(c, f); | |
| CheckNotEqual(d, e); | |
| CheckNotEqual(d, f); | |
| CheckNotEqual(e, f); | |
| // Deserializing into the TestEmptyMessage such that every field is an UnknownFieldSet.Field | |
| TestEmptyMessage eUnknownFields = TestEmptyMessage.ParseFrom(e.ToByteArray()); | |
| TestEmptyMessage fUnknownFields = TestEmptyMessage.ParseFrom(f.ToByteArray()); | |
| CheckNotEqual(eUnknownFields, fUnknownFields); | |
| CheckEqualsIsConsistent(eUnknownFields); | |
| CheckEqualsIsConsistent(fUnknownFields); | |
| // Subseqent reconstitutions should be identical | |
| TestEmptyMessage eUnknownFields2 = TestEmptyMessage.ParseFrom(e.ToByteArray()); | |
| CheckEqualsIsConsistent(eUnknownFields, eUnknownFields2); | |
| } | |
| /// <summary> | |
| /// Asserts that the given protos are equal and have the same hash code. | |
| /// </summary> | |
| private static void CheckEqualsIsConsistent(IMessage message) | |
| { | |
| // Object should be equal to itself. | |
| Assert.AreEqual(message, message); | |
| // Object should be equal to a dynamic copy of itself. | |
| DynamicMessage dynamic = DynamicMessage.CreateBuilder(message).Build(); | |
| CheckEqualsIsConsistent(message, dynamic); | |
| } | |
| /// <summary> | |
| /// Asserts that the given protos are equal and have the same hash code. | |
| /// </summary> | |
| private static void CheckEqualsIsConsistent(IMessage message1, IMessage message2) | |
| { | |
| Assert.AreEqual(message1, message2); | |
| Assert.AreEqual(message2, message1); | |
| Assert.AreEqual(message2.GetHashCode(), message1.GetHashCode()); | |
| } | |
| /// <summary> | |
| /// Asserts that the given protos are not equal and have different hash codes. | |
| /// </summary> | |
| /// <remarks> | |
| /// 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. (If this test fails, it's probably still due to a bug.) | |
| /// </remarks> | |
| private static void CheckNotEqual(IMessage m1, IMessage m2) | |
| { | |
| String equalsError = string.Format("{0} should not be equal to {1}", m1, m2); | |
| Assert.IsFalse(m1.Equals(m2), equalsError); | |
| Assert.IsFalse(m2.Equals(m1), equalsError); | |
| Assert.IsFalse(m1.GetHashCode() == m2.GetHashCode(), | |
| string.Format("{0} should have a different hash code from {1}", m1, m2)); | |
| } | |
| /// <summary> | |
| /// Extends AbstractMessage and wraps some other message object. The methods | |
| /// of the Message interface which aren't explicitly implemented by | |
| /// AbstractMessage are forwarded to the wrapped object. This allows us to | |
| /// test that AbstractMessage's implementations work even if the wrapped | |
| /// object does not use them. | |
| /// </summary> | |
| private class AbstractMessageWrapper : AbstractMessage<AbstractMessageWrapper, AbstractMessageWrapper.Builder> | |
| { | |
| private readonly IMessage wrappedMessage; | |
| public IMessage WrappedMessage | |
| { | |
| get { return wrappedMessage; } | |
| } | |
| public AbstractMessageWrapper(IMessage wrappedMessage) | |
| { | |
| this.wrappedMessage = wrappedMessage; | |
| } | |
| public override MessageDescriptor DescriptorForType | |
| { | |
| get { return wrappedMessage.DescriptorForType; } | |
| } | |
| public override AbstractMessageWrapper DefaultInstanceForType | |
| { | |
| get { return new AbstractMessageWrapper(wrappedMessage.WeakDefaultInstanceForType); } | |
| } | |
| public override IDictionary<FieldDescriptor, object> AllFields | |
| { | |
| get { return wrappedMessage.AllFields; } | |
| } | |
| public override bool HasField(FieldDescriptor field) | |
| { | |
| return wrappedMessage.HasField(field); | |
| } | |
| public override object this[FieldDescriptor field] | |
| { | |
| get { return wrappedMessage[field]; } | |
| } | |
| public override object this[FieldDescriptor field, int index] | |
| { | |
| get { return wrappedMessage[field, index]; } | |
| } | |
| public override int GetRepeatedFieldCount(FieldDescriptor field) | |
| { | |
| return wrappedMessage.GetRepeatedFieldCount(field); | |
| } | |
| public override UnknownFieldSet UnknownFields | |
| { | |
| get { return wrappedMessage.UnknownFields; } | |
| } | |
| public override Builder CreateBuilderForType() | |
| { | |
| return new Builder(wrappedMessage.WeakCreateBuilderForType()); | |
| } | |
| public override Builder ToBuilder() | |
| { | |
| return new Builder(wrappedMessage.WeakToBuilder()); | |
| } | |
| internal class Builder : AbstractBuilder<AbstractMessageWrapper, Builder> | |
| { | |
| private readonly IBuilder wrappedBuilder; | |
| protected override Builder ThisBuilder | |
| { | |
| get { return this; } | |
| } | |
| internal Builder(IBuilder wrappedBuilder) | |
| { | |
| this.wrappedBuilder = wrappedBuilder; | |
| } | |
| public override Builder MergeFrom(AbstractMessageWrapper other) | |
| { | |
| wrappedBuilder.WeakMergeFrom(other.wrappedMessage); | |
| return this; | |
| } | |
| public override bool IsInitialized | |
| { | |
| get { return wrappedBuilder.IsInitialized; } | |
| } | |
| public override IDictionary<FieldDescriptor, object> AllFields | |
| { | |
| get { return wrappedBuilder.AllFields; } | |
| } | |
| public override object this[FieldDescriptor field] | |
| { | |
| get { return wrappedBuilder[field]; } | |
| set { wrappedBuilder[field] = value; } | |
| } | |
| public override MessageDescriptor DescriptorForType | |
| { | |
| get { return wrappedBuilder.DescriptorForType; } | |
| } | |
| public override int GetRepeatedFieldCount(FieldDescriptor field) | |
| { | |
| return wrappedBuilder.GetRepeatedFieldCount(field); | |
| } | |
| public override object this[FieldDescriptor field, int index] | |
| { | |
| get { return wrappedBuilder[field, index]; } | |
| set { wrappedBuilder[field, index] = value; } | |
| } | |
| public override bool HasField(FieldDescriptor field) | |
| { | |
| return wrappedBuilder.HasField(field); | |
| } | |
| public override UnknownFieldSet UnknownFields | |
| { | |
| get { return wrappedBuilder.UnknownFields; } | |
| set { wrappedBuilder.UnknownFields = value; } | |
| } | |
| public override AbstractMessageWrapper Build() | |
| { | |
| return new AbstractMessageWrapper(wrappedBuilder.WeakBuild()); | |
| } | |
| public override AbstractMessageWrapper BuildPartial() | |
| { | |
| return new AbstractMessageWrapper(wrappedBuilder.WeakBuildPartial()); | |
| } | |
| public override Builder Clone() | |
| { | |
| return new Builder(wrappedBuilder.WeakClone()); | |
| } | |
| public override AbstractMessageWrapper DefaultInstanceForType | |
| { | |
| get { return new AbstractMessageWrapper(wrappedBuilder.WeakDefaultInstanceForType); } | |
| } | |
| public override Builder ClearField(FieldDescriptor field) | |
| { | |
| wrappedBuilder.WeakClearField(field); | |
| return this; | |
| } | |
| public override Builder AddRepeatedField(FieldDescriptor field, object value) | |
| { | |
| wrappedBuilder.WeakAddRepeatedField(field, value); | |
| return this; | |
| } | |
| public override IBuilder CreateBuilderForField(FieldDescriptor field) | |
| { | |
| wrappedBuilder.CreateBuilderForField(field); | |
| return this; | |
| } | |
| public override Builder MergeFrom(IMessage other) | |
| { | |
| wrappedBuilder.WeakMergeFrom(other); | |
| return this; | |
| } | |
| public override Builder MergeFrom(ICodedInputStream input, ExtensionRegistry extensionRegistry) | |
| { | |
| wrappedBuilder.WeakMergeFrom(input, extensionRegistry); | |
| return this; | |
| } | |
| } | |
| } | |
| } | |
| } |