Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
15 KiB
344 lines
15 KiB
#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 Google.ProtocolBuffers.Descriptors; |
|
using Google.ProtocolBuffers.TestProtos; |
|
using NUnit.Framework; |
|
|
|
namespace Google.ProtocolBuffers |
|
{ |
|
/// <summary> |
|
/// Miscellaneous tests for message operations that apply to both |
|
/// generated and dynamic messages. |
|
/// </summary> |
|
public class MessageTest |
|
{ |
|
// ================================================================= |
|
// Message-merging tests. |
|
|
|
private static readonly TestAllTypes MergeSource = new TestAllTypes.Builder |
|
{ |
|
OptionalInt32 = 1, |
|
OptionalString = "foo", |
|
OptionalForeignMessage = |
|
ForeignMessage.DefaultInstance, |
|
}.AddRepeatedString("bar").Build(); |
|
|
|
private static readonly TestAllTypes MergeDest = new TestAllTypes.Builder |
|
{ |
|
OptionalInt64 = 2, |
|
OptionalString = "baz", |
|
OptionalForeignMessage = |
|
new ForeignMessage.Builder {C = 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"; |
|
|
|
[Test] |
|
public void MergeFrom() |
|
{ |
|
TestAllTypes result = TestAllTypes.CreateBuilder(MergeDest).MergeFrom(MergeSource).Build(); |
|
|
|
Assert.AreEqual(MergeResultText, result.ToString()); |
|
} |
|
|
|
/// <summary> |
|
/// Test merging a DynamicMessage into a GeneratedMessage. |
|
/// As long as they have the same descriptor, this should work, but it is an |
|
/// entirely different code path. |
|
/// </summary> |
|
[Test] |
|
public void MergeFromDynamic() |
|
{ |
|
TestAllTypes result = (TestAllTypes) TestAllTypes.CreateBuilder(MergeDest) |
|
.MergeFrom(DynamicMessage.CreateBuilder(MergeSource).Build()) |
|
.Build(); |
|
|
|
Assert.AreEqual(MergeResultText, result.ToString()); |
|
} |
|
|
|
/// <summary> |
|
/// Test merging two DynamicMessages. |
|
/// </summary> |
|
[Test] |
|
public void DynamicMergeFrom() |
|
{ |
|
DynamicMessage result = (DynamicMessage) DynamicMessage.CreateBuilder(MergeDest) |
|
.MergeFrom( |
|
(DynamicMessage) |
|
DynamicMessage.CreateBuilder(MergeSource).Build()) |
|
.Build(); |
|
|
|
Assert.AreEqual(MergeResultText, result.ToString()); |
|
} |
|
|
|
// ================================================================= |
|
// Required-field-related tests. |
|
|
|
private static readonly TestRequired TestRequiredUninitialized = TestRequired.DefaultInstance; |
|
|
|
private static readonly TestRequired TestRequiredInitialized = new TestRequired.Builder |
|
{ |
|
A = 1, |
|
B = 2, |
|
C = 3 |
|
}.Build(); |
|
|
|
[Test] |
|
public void Initialization() |
|
{ |
|
TestRequired.Builder builder = TestRequired.CreateBuilder(); |
|
|
|
Assert.IsFalse(builder.IsInitialized); |
|
builder.A = 1; |
|
Assert.IsFalse(builder.IsInitialized); |
|
builder.B = 1; |
|
Assert.IsFalse(builder.IsInitialized); |
|
builder.C = 1; |
|
Assert.IsTrue(builder.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void UninitializedBuilderToString() |
|
{ |
|
TestRequired.Builder builder = TestRequired.CreateBuilder().SetA(1); |
|
Assert.AreEqual("a: 1\n", builder.ToString()); |
|
} |
|
|
|
[Test] |
|
public void RequiredForeign() |
|
{ |
|
TestRequiredForeign.Builder builder = TestRequiredForeign.CreateBuilder(); |
|
|
|
Assert.IsTrue(builder.IsInitialized); |
|
|
|
builder.SetOptionalMessage(TestRequiredUninitialized); |
|
Assert.IsFalse(builder.IsInitialized); |
|
|
|
builder.SetOptionalMessage(TestRequiredInitialized); |
|
Assert.IsTrue(builder.IsInitialized); |
|
|
|
builder.AddRepeatedMessage(TestRequiredUninitialized); |
|
Assert.IsFalse(builder.IsInitialized); |
|
|
|
builder.SetRepeatedMessage(0, TestRequiredInitialized); |
|
Assert.IsTrue(builder.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void RequiredExtension() |
|
{ |
|
TestAllExtensions.Builder builder = TestAllExtensions.CreateBuilder(); |
|
|
|
Assert.IsTrue(builder.IsInitialized); |
|
|
|
builder.SetExtension(TestRequired.Single, TestRequiredUninitialized); |
|
Assert.IsFalse(builder.IsInitialized); |
|
|
|
builder.SetExtension(TestRequired.Single, TestRequiredInitialized); |
|
Assert.IsTrue(builder.IsInitialized); |
|
|
|
builder.AddExtension(TestRequired.Multi, TestRequiredUninitialized); |
|
Assert.IsFalse(builder.IsInitialized); |
|
|
|
builder.SetExtension(TestRequired.Multi, 0, TestRequiredInitialized); |
|
Assert.IsTrue(builder.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void RequiredDynamic() |
|
{ |
|
MessageDescriptor descriptor = TestRequired.Descriptor; |
|
DynamicMessage.Builder builder = DynamicMessage.CreateBuilder(descriptor); |
|
|
|
Assert.IsFalse(builder.IsInitialized); |
|
builder[descriptor.FindDescriptor<FieldDescriptor>("a")] = 1; |
|
Assert.IsFalse(builder.IsInitialized); |
|
builder[descriptor.FindDescriptor<FieldDescriptor>("b")] = 1; |
|
Assert.IsFalse(builder.IsInitialized); |
|
builder[descriptor.FindDescriptor<FieldDescriptor>("c")] = 1; |
|
Assert.IsTrue(builder.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void RequiredDynamicForeign() |
|
{ |
|
MessageDescriptor descriptor = TestRequiredForeign.Descriptor; |
|
DynamicMessage.Builder builder = DynamicMessage.CreateBuilder(descriptor); |
|
|
|
Assert.IsTrue(builder.IsInitialized); |
|
|
|
builder[descriptor.FindDescriptor<FieldDescriptor>("optional_message")] = TestRequiredUninitialized; |
|
Assert.IsFalse(builder.IsInitialized); |
|
|
|
builder[descriptor.FindDescriptor<FieldDescriptor>("optional_message")] = TestRequiredInitialized; |
|
Assert.IsTrue(builder.IsInitialized); |
|
|
|
builder.AddRepeatedField(descriptor.FindDescriptor<FieldDescriptor>("repeated_message"), |
|
TestRequiredUninitialized); |
|
Assert.IsFalse(builder.IsInitialized); |
|
|
|
builder.SetRepeatedField(descriptor.FindDescriptor<FieldDescriptor>("repeated_message"), 0, |
|
TestRequiredInitialized); |
|
Assert.IsTrue(builder.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void UninitializedException() |
|
{ |
|
var e = Assert.Throws<UninitializedMessageException>(() => TestRequired.CreateBuilder().Build()); |
|
Assert.AreEqual("Message missing required fields: a, b, c", e.Message); |
|
} |
|
|
|
[Test] |
|
public void BuildPartial() |
|
{ |
|
// We're mostly testing that no exception is thrown. |
|
TestRequired message = TestRequired.CreateBuilder().BuildPartial(); |
|
Assert.IsFalse(message.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void NestedUninitializedException() |
|
{ |
|
var e = Assert.Throws<UninitializedMessageException>(() => TestRequiredForeign.CreateBuilder() |
|
.SetOptionalMessage(TestRequiredUninitialized) |
|
.AddRepeatedMessage(TestRequiredUninitialized) |
|
.AddRepeatedMessage(TestRequiredUninitialized) |
|
.Build()); |
|
Assert.AreEqual( |
|
"Message missing required fields: " + |
|
"optional_message.a, " + |
|
"optional_message.b, " + |
|
"optional_message.c, " + |
|
"repeated_message[0].a, " + |
|
"repeated_message[0].b, " + |
|
"repeated_message[0].c, " + |
|
"repeated_message[1].a, " + |
|
"repeated_message[1].b, " + |
|
"repeated_message[1].c", |
|
e.Message); |
|
} |
|
|
|
[Test] |
|
public void BuildNestedPartial() |
|
{ |
|
// We're mostly testing that no exception is thrown. |
|
TestRequiredForeign message = |
|
TestRequiredForeign.CreateBuilder() |
|
.SetOptionalMessage(TestRequiredUninitialized) |
|
.AddRepeatedMessage(TestRequiredUninitialized) |
|
.AddRepeatedMessage(TestRequiredUninitialized) |
|
.BuildPartial(); |
|
Assert.IsFalse(message.IsInitialized); |
|
} |
|
|
|
[Test] |
|
public void ParseUninitialized() |
|
{ |
|
var e = Assert.Throws<InvalidProtocolBufferException>(() => TestRequired.ParseFrom(ByteString.Empty)); |
|
Assert.AreEqual("Message missing required fields: a, b, c", e.Message); |
|
} |
|
|
|
[Test] |
|
public void ParseNestedUnititialized() |
|
{ |
|
ByteString data = |
|
TestRequiredForeign.CreateBuilder() |
|
.SetOptionalMessage(TestRequiredUninitialized) |
|
.AddRepeatedMessage(TestRequiredUninitialized) |
|
.AddRepeatedMessage(TestRequiredUninitialized) |
|
.BuildPartial().ToByteString(); |
|
|
|
var e = Assert.Throws<InvalidProtocolBufferException>(() => TestRequiredForeign.ParseFrom(data)); |
|
Assert.AreEqual( |
|
"Message missing required fields: " + |
|
"optional_message.a, " + |
|
"optional_message.b, " + |
|
"optional_message.c, " + |
|
"repeated_message[0].a, " + |
|
"repeated_message[0].b, " + |
|
"repeated_message[0].c, " + |
|
"repeated_message[1].a, " + |
|
"repeated_message[1].b, " + |
|
"repeated_message[1].c", |
|
e.Message); |
|
} |
|
|
|
[Test] |
|
public void DynamicUninitializedException() |
|
{ |
|
var e = Assert.Throws<UninitializedMessageException>(() => DynamicMessage.CreateBuilder(TestRequired.Descriptor).Build()); |
|
Assert.AreEqual("Message missing required fields: a, b, c", e.Message); |
|
} |
|
|
|
[Test] |
|
public void DynamicBuildPartial() |
|
{ |
|
// We're mostly testing that no exception is thrown. |
|
DynamicMessage message = DynamicMessage.CreateBuilder(TestRequired.Descriptor).BuildPartial(); |
|
Assert.IsFalse(message.Initialized); |
|
} |
|
|
|
[Test] |
|
public void DynamicParseUnititialized() |
|
{ |
|
MessageDescriptor descriptor = TestRequired.Descriptor; |
|
var e = Assert.Throws<InvalidProtocolBufferException>(() => DynamicMessage.ParseFrom(descriptor, ByteString.Empty)); |
|
Assert.AreEqual("Message missing required fields: a, b, c", e.Message); |
|
} |
|
|
|
[Test] |
|
public void PackedTypesWrittenDirectlyToStream() |
|
{ |
|
TestPackedTypes message = new TestPackedTypes.Builder {PackedInt32List = {0, 1, 2}}.Build(); |
|
MemoryStream stream = new MemoryStream(); |
|
message.WriteTo(stream); |
|
stream.Position = 0; |
|
TestPackedTypes readMessage = TestPackedTypes.ParseFrom(stream); |
|
Assert.AreEqual(message, readMessage); |
|
} |
|
} |
|
} |