aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/Google.Protobuf.Test/Reflection
diff options
context:
space:
mode:
Diffstat (limited to 'csharp/src/Google.Protobuf.Test/Reflection')
-rw-r--r--csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs175
-rw-r--r--csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs150
2 files changed, 300 insertions, 25 deletions
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs
new file mode 100644
index 00000000..d9d56672
--- /dev/null
+++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorDeclarationTest.cs
@@ -0,0 +1,175 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2018 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 Google.Protobuf.Reflection;
+using NUnit.Framework;
+using System.Linq;
+using System.Reflection;
+
+namespace Google.Protobuf.Test.Reflection
+{
+ // In reality this isn't a test for DescriptorDeclaration so much as the way they're loaded.
+ public class DescriptorDeclarationTest
+ {
+ static readonly FileDescriptor unitTestProto3Descriptor = LoadProtos();
+
+ // Note: we don't expose a declaration for FileDescriptor as it doesn't have comments
+ // at the moment and the locations aren't terribly useful.
+
+ // The tests for most elements are quite basic: we don't test every aspect of every element.
+ // The code within the library falls into two categories:
+ // - Exposing the properties for *any* declaration
+ // - Finding the right declaration for an element from the descriptor data
+ // We have a per-element check to make sure we *are* finding the right declaration, and we
+ // check every property of declarations in at least one test, but we don't have a cross-product.
+ // That would effectively be testing protoc, which seems redundant here.
+
+ [Test]
+ public void ServiceComments()
+ {
+ var service = unitTestProto3Descriptor.FindTypeByName<ServiceDescriptor>("TestService");
+ Assert.NotNull(service.Declaration);
+ Assert.AreEqual(" This is a test service\n", service.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void MethodComments()
+ {
+ var service = unitTestProto3Descriptor.FindTypeByName<ServiceDescriptor>("TestService");
+ var method = service.FindMethodByName("Foo");
+ Assert.NotNull(method.Declaration);
+ Assert.AreEqual(" This is a test method\n", method.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void MessageComments()
+ {
+ var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ Assert.NotNull(message.Declaration);
+ Assert.AreEqual(" This is a leading comment\n", message.Declaration.LeadingComments);
+ Assert.AreEqual(new[] { " This is leading detached comment 1\n", " This is leading detached comment 2\n" },
+ message.Declaration.LeadingDetachedComments);
+ }
+
+ // Note: this test is somewhat brittle; a change earlier in the proto will break it.
+ [Test]
+ public void MessageLocations()
+ {
+ var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ Assert.NotNull(message.Declaration);
+ Assert.AreEqual(389, message.Declaration.StartLine);
+ Assert.AreEqual(1, message.Declaration.StartColumn);
+
+ Assert.AreEqual(404, message.Declaration.EndLine);
+ Assert.AreEqual(2, message.Declaration.EndColumn);
+ }
+
+ [Test]
+ public void EnumComments()
+ {
+ var descriptor = unitTestProto3Descriptor.FindTypeByName<EnumDescriptor>("CommentEnum");
+ Assert.NotNull(descriptor.Declaration);
+ Assert.AreEqual(" Leading enum comment\n", descriptor.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void NestedMessageComments()
+ {
+ var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ var nested = outer.FindDescriptor<MessageDescriptor>("NestedCommentMessage");
+ Assert.NotNull(nested.Declaration);
+ Assert.AreEqual(" Leading nested message comment\n", nested.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void NestedEnumComments()
+ {
+ var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ var nested = outer.FindDescriptor<EnumDescriptor>("NestedCommentEnum");
+ Assert.NotNull(nested.Declaration);
+ Assert.AreEqual(" Leading nested enum comment\n", nested.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void FieldComments()
+ {
+ var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ var field = message.FindFieldByName("text");
+ Assert.NotNull(field.Declaration);
+ Assert.AreEqual(" Leading field comment\n", field.Declaration.LeadingComments);
+ Assert.AreEqual(" Trailing field comment\n", field.Declaration.TrailingComments);
+ }
+
+ [Test]
+ public void NestedMessageFieldComments()
+ {
+ var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ var nested = outer.FindDescriptor<MessageDescriptor>("NestedCommentMessage");
+ var field = nested.FindFieldByName("nested_text");
+ Assert.NotNull(field.Declaration);
+ Assert.AreEqual(" Leading nested message field comment\n", field.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void EnumValueComments()
+ {
+ var enumDescriptor = unitTestProto3Descriptor.FindTypeByName<EnumDescriptor>("CommentEnum");
+ var value = enumDescriptor.FindValueByName("ZERO_VALUE");
+ Assert.NotNull(value.Declaration);
+ Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments);
+ }
+
+ [Test]
+ public void NestedEnumValueComments()
+ {
+ var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage");
+ var nested = outer.FindDescriptor<EnumDescriptor>("NestedCommentEnum");
+ var value = nested.FindValueByName("ZERO_VALUE");
+ Assert.NotNull(value.Declaration);
+ Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments);
+ }
+
+ private static FileDescriptor LoadProtos()
+ {
+ var type = typeof(DescriptorDeclarationTest);
+ // TODO: Make this simpler :)
+ FileDescriptorSet descriptorSet;
+ using (var stream = type.GetTypeInfo().Assembly.GetManifestResourceStream($"Google.Protobuf.Test.testprotos.pb"))
+ {
+ descriptorSet = FileDescriptorSet.Parser.ParseFrom(stream);
+ }
+ var byteStrings = descriptorSet.File.Select(f => f.ToByteString()).ToList();
+ var descriptors = FileDescriptor.BuildFromByteStrings(byteStrings);
+ return descriptors.Single(d => d.Name == "unittest_proto3.proto");
+ }
+ }
+}
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
index 29a376e0..8e1097aa 100644
--- a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
@@ -30,10 +30,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
-using System.Linq;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
-using UnitTest.Issues.TestProtos;
+using System;
+using System.Collections.Generic;
+using System.Linq;
namespace Google.Protobuf.Reflection
{
@@ -44,10 +45,32 @@ namespace Google.Protobuf.Reflection
public class DescriptorsTest
{
[Test]
- public void FileDescriptor()
+ public void FileDescriptor_GeneratedCode()
{
- FileDescriptor file = UnittestProto3Reflection.Descriptor;
+ TestFileDescriptor(
+ UnittestProto3Reflection.Descriptor,
+ UnittestImportProto3Reflection.Descriptor,
+ UnittestImportPublicProto3Reflection.Descriptor);
+ }
+ [Test]
+ public void FileDescriptor_BuildFromByteStrings()
+ {
+ // The descriptors have to be supplied in an order such that all the
+ // dependencies come before the descriptors depending on them.
+ var descriptorData = new List<ByteString>
+ {
+ UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
+ UnittestImportProto3Reflection.Descriptor.SerializedData,
+ UnittestProto3Reflection.Descriptor.SerializedData
+ };
+ var converted = FileDescriptor.BuildFromByteStrings(descriptorData);
+ Assert.AreEqual(3, converted.Count);
+ TestFileDescriptor(converted[2], converted[1], converted[0]);
+ }
+
+ private void TestFileDescriptor(FileDescriptor file, FileDescriptor importedFile, FileDescriptor importedPublicFile)
+ {
Assert.AreEqual("unittest_proto3.proto", file.Name);
Assert.AreEqual("protobuf_unittest3", file.Package);
@@ -56,17 +79,12 @@ namespace Google.Protobuf.Reflection
// unittest_proto3.proto doesn't have any public imports, but unittest_import_proto3.proto does.
Assert.AreEqual(0, file.PublicDependencies.Count);
- Assert.AreEqual(1, UnittestImportProto3Reflection.Descriptor.PublicDependencies.Count);
- Assert.AreEqual(UnittestImportPublicProto3Reflection.Descriptor, UnittestImportProto3Reflection.Descriptor.PublicDependencies[0]);
+ Assert.AreEqual(1, importedFile.PublicDependencies.Count);
+ Assert.AreEqual(importedPublicFile, importedFile.PublicDependencies[0]);
Assert.AreEqual(1, file.Dependencies.Count);
- Assert.AreEqual(UnittestImportProto3Reflection.Descriptor, file.Dependencies[0]);
+ Assert.AreEqual(importedFile, file.Dependencies[0]);
- MessageDescriptor messageType = TestAllTypes.Descriptor;
- Assert.AreSame(typeof(TestAllTypes), messageType.ClrType);
- Assert.AreSame(TestAllTypes.Parser, messageType.Parser);
- Assert.AreEqual(messageType, file.MessageTypes[0]);
- Assert.AreEqual(messageType, file.FindTypeByName<MessageDescriptor>("TestAllTypes"));
Assert.Null(file.FindTypeByName<MessageDescriptor>("NoSuchType"));
Assert.Null(file.FindTypeByName<MessageDescriptor>("protobuf_unittest3.TestAllTypes"));
for (int i = 0; i < file.MessageTypes.Count; i++)
@@ -77,8 +95,8 @@ namespace Google.Protobuf.Reflection
Assert.AreEqual(file.EnumTypes[0], file.FindTypeByName<EnumDescriptor>("ForeignEnum"));
Assert.Null(file.FindTypeByName<EnumDescriptor>("NoSuchType"));
Assert.Null(file.FindTypeByName<EnumDescriptor>("protobuf_unittest3.ForeignEnum"));
- Assert.AreEqual(1, UnittestImportProto3Reflection.Descriptor.EnumTypes.Count);
- Assert.AreEqual("ImportEnum", UnittestImportProto3Reflection.Descriptor.EnumTypes[0].Name);
+ Assert.AreEqual(1, importedFile.EnumTypes.Count);
+ Assert.AreEqual("ImportEnum", importedFile.EnumTypes[0].Name);
for (int i = 0; i < file.EnumTypes.Count; i++)
{
Assert.AreEqual(i, file.EnumTypes[i].Index);
@@ -98,6 +116,56 @@ namespace Google.Protobuf.Reflection
}
[Test]
+ public void FileDescriptor_BuildFromByteStrings_MissingDependency()
+ {
+ var descriptorData = new List<ByteString>
+ {
+ UnittestImportProto3Reflection.Descriptor.SerializedData,
+ UnittestProto3Reflection.Descriptor.SerializedData,
+ };
+ // This will fail, because we're missing UnittestImportPublicProto3Reflection
+ Assert.Throws<ArgumentException>(() => FileDescriptor.BuildFromByteStrings(descriptorData));
+ }
+
+ [Test]
+ public void FileDescriptor_BuildFromByteStrings_DuplicateNames()
+ {
+ var descriptorData = new List<ByteString>
+ {
+ UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
+ UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
+ };
+ // This will fail due to the same name being used twice
+ Assert.Throws<ArgumentException>(() => FileDescriptor.BuildFromByteStrings(descriptorData));
+ }
+
+ [Test]
+ public void FileDescriptor_BuildFromByteStrings_IncorrectOrder()
+ {
+ var descriptorData = new List<ByteString>
+ {
+ UnittestProto3Reflection.Descriptor.SerializedData,
+ UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
+ UnittestImportProto3Reflection.Descriptor.SerializedData
+ };
+ // This will fail, because the dependencies should come first
+ Assert.Throws<ArgumentException>(() => FileDescriptor.BuildFromByteStrings(descriptorData));
+
+ }
+
+ [Test]
+ public void MessageDescriptorFromGeneratedCodeFileDescriptor()
+ {
+ var file = UnittestProto3Reflection.Descriptor;
+
+ MessageDescriptor messageType = TestAllTypes.Descriptor;
+ Assert.AreSame(typeof(TestAllTypes), messageType.ClrType);
+ Assert.AreSame(TestAllTypes.Parser, messageType.Parser);
+ Assert.AreEqual(messageType, file.MessageTypes[0]);
+ Assert.AreEqual(messageType, file.FindTypeByName<MessageDescriptor>("TestAllTypes"));
+ }
+
+ [Test]
public void MessageDescriptor()
{
MessageDescriptor messageType = TestAllTypes.Descriptor;
@@ -145,29 +213,61 @@ namespace Google.Protobuf.Reflection
}
[Test]
- public void FieldDescriptor()
+ public void FieldDescriptor_GeneratedCode()
{
- MessageDescriptor messageType = TestAllTypes.Descriptor;
- FieldDescriptor primitiveField = messageType.FindDescriptor<FieldDescriptor>("single_int32");
- FieldDescriptor enumField = messageType.FindDescriptor<FieldDescriptor>("single_nested_enum");
- FieldDescriptor messageField = messageType.FindDescriptor<FieldDescriptor>("single_foreign_message");
+ TestFieldDescriptor(UnittestProto3Reflection.Descriptor, TestAllTypes.Descriptor, ForeignMessage.Descriptor, ImportMessage.Descriptor);
+ }
+
+ [Test]
+ public void FieldDescriptor_BuildFromByteStrings()
+ {
+ // The descriptors have to be supplied in an order such that all the
+ // dependencies come before the descriptors depending on them.
+ var descriptorData = new List<ByteString>
+ {
+ UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
+ UnittestImportProto3Reflection.Descriptor.SerializedData,
+ UnittestProto3Reflection.Descriptor.SerializedData
+ };
+ var converted = FileDescriptor.BuildFromByteStrings(descriptorData);
+ TestFieldDescriptor(
+ converted[2],
+ converted[2].FindTypeByName<MessageDescriptor>("TestAllTypes"),
+ converted[2].FindTypeByName<MessageDescriptor>("ForeignMessage"),
+ converted[1].FindTypeByName<MessageDescriptor>("ImportMessage"));
+ }
+
+ public void TestFieldDescriptor(
+ FileDescriptor unitTestProto3Descriptor,
+ MessageDescriptor testAllTypesDescriptor,
+ MessageDescriptor foreignMessageDescriptor,
+ MessageDescriptor importMessageDescriptor)
+ {
+ FieldDescriptor primitiveField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_int32");
+ FieldDescriptor enumField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_nested_enum");
+ FieldDescriptor foreignMessageField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_foreign_message");
+ FieldDescriptor importMessageField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_import_message");
Assert.AreEqual("single_int32", primitiveField.Name);
Assert.AreEqual("protobuf_unittest3.TestAllTypes.single_int32",
primitiveField.FullName);
Assert.AreEqual(1, primitiveField.FieldNumber);
- Assert.AreEqual(messageType, primitiveField.ContainingType);
- Assert.AreEqual(UnittestProto3Reflection.Descriptor, primitiveField.File);
+ Assert.AreEqual(testAllTypesDescriptor, primitiveField.ContainingType);
+ Assert.AreEqual(unitTestProto3Descriptor, primitiveField.File);
Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
Assert.IsNull(primitiveField.Proto.Options);
Assert.AreEqual("single_nested_enum", enumField.Name);
Assert.AreEqual(FieldType.Enum, enumField.FieldType);
- // Assert.AreEqual(TestAllTypes.Types.NestedEnum.DescriptorProtoFile, enumField.EnumType);
+ Assert.AreEqual(testAllTypesDescriptor.EnumTypes[0], enumField.EnumType);
+
+ Assert.AreEqual("single_foreign_message", foreignMessageField.Name);
+ Assert.AreEqual(FieldType.Message, foreignMessageField.FieldType);
+ Assert.AreEqual(foreignMessageDescriptor, foreignMessageField.MessageType);
- Assert.AreEqual("single_foreign_message", messageField.Name);
- Assert.AreEqual(FieldType.Message, messageField.FieldType);
- Assert.AreEqual(ForeignMessage.Descriptor, messageField.MessageType);
+ Assert.AreEqual("single_import_message", importMessageField.Name);
+ Assert.AreEqual(FieldType.Message, importMessageField.FieldType);
+ Assert.AreEqual(importMessageDescriptor, importMessageField.MessageType);
}
[Test]