1 #region Copyright notice and license 2 // Protocol Buffers - Google's data interchange format 3 // Copyright 2018 Google Inc. All rights reserved. 4 // 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file or at 7 // https://developers.google.com/open-source/licenses/bsd 8 #endregion 9 10 using Google.Protobuf.Reflection; 11 using NUnit.Framework; 12 using System.Linq; 13 using System.Reflection; 14 15 namespace Google.Protobuf.Test.Reflection 16 { 17 // In reality this isn't a test for DescriptorDeclaration so much as the way they're loaded. 18 public class DescriptorDeclarationTest 19 { 20 static readonly FileDescriptor unitTestProto3Descriptor = LoadProtos(); 21 22 // Note: we don't expose a declaration for FileDescriptor as it doesn't have comments 23 // at the moment and the locations aren't terribly useful. 24 25 // The tests for most elements are quite basic: we don't test every aspect of every element. 26 // The code within the library falls into two categories: 27 // - Exposing the properties for *any* declaration 28 // - Finding the right declaration for an element from the descriptor data 29 // We have a per-element check to make sure we *are* finding the right declaration, and we 30 // check every property of declarations in at least one test, but we don't have a cross-product. 31 // That would effectively be testing protoc, which seems redundant here. 32 33 [Test] ServiceComments()34 public void ServiceComments() 35 { 36 var service = unitTestProto3Descriptor.FindTypeByName<ServiceDescriptor>("TestService"); 37 Assert.NotNull(service.Declaration); 38 Assert.AreEqual(" This is a test service\n", service.Declaration.LeadingComments); 39 } 40 41 [Test] MethodComments()42 public void MethodComments() 43 { 44 var service = unitTestProto3Descriptor.FindTypeByName<ServiceDescriptor>("TestService"); 45 var method = service.FindMethodByName("Foo"); 46 Assert.NotNull(method.Declaration); 47 Assert.AreEqual(" This is a test method\n", method.Declaration.LeadingComments); 48 } 49 50 [Test] MessageComments()51 public void MessageComments() 52 { 53 var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 54 Assert.NotNull(message.Declaration); 55 Assert.AreEqual(" This is a leading comment\n", message.Declaration.LeadingComments); 56 Assert.AreEqual(new[] { " This is leading detached comment 1\n", " This is leading detached comment 2\n" }, 57 message.Declaration.LeadingDetachedComments); 58 } 59 60 [Test] MessageLocations()61 public void MessageLocations() 62 { 63 var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 64 Assert.NotNull(message.Declaration); 65 Assert.AreEqual(1, message.Declaration.StartColumn); 66 67 Assert.AreEqual(2, message.Declaration.EndColumn); 68 69 // This is slightly brittle, but allows a reasonable amount of change. 70 var diff = message.Declaration.EndLine - message.Declaration.StartLine; 71 Assert.That(diff, Is.GreaterThanOrEqualTo(10)); 72 Assert.That(diff, Is.LessThanOrEqualTo(50)); 73 } 74 75 [Test] EnumComments()76 public void EnumComments() 77 { 78 var descriptor = unitTestProto3Descriptor.FindTypeByName<EnumDescriptor>("CommentEnum"); 79 Assert.NotNull(descriptor.Declaration); 80 Assert.AreEqual(" Leading enum comment\n", descriptor.Declaration.LeadingComments); 81 } 82 83 [Test] NestedMessageComments()84 public void NestedMessageComments() 85 { 86 var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 87 var nested = outer.FindDescriptor<MessageDescriptor>("NestedCommentMessage"); 88 Assert.NotNull(nested.Declaration); 89 Assert.AreEqual(" Leading nested message comment\n", nested.Declaration.LeadingComments); 90 } 91 92 [Test] NestedEnumComments()93 public void NestedEnumComments() 94 { 95 var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 96 var nested = outer.FindDescriptor<EnumDescriptor>("NestedCommentEnum"); 97 Assert.NotNull(nested.Declaration); 98 Assert.AreEqual(" Leading nested enum comment\n", nested.Declaration.LeadingComments); 99 } 100 101 [Test] FieldComments()102 public void FieldComments() 103 { 104 var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 105 var field = message.FindFieldByName("text"); 106 Assert.NotNull(field.Declaration); 107 Assert.AreEqual(" Leading field comment\n", field.Declaration.LeadingComments); 108 Assert.AreEqual(" Trailing field comment\n", field.Declaration.TrailingComments); 109 } 110 111 [Test] NestedMessageFieldComments()112 public void NestedMessageFieldComments() 113 { 114 var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 115 var nested = outer.FindDescriptor<MessageDescriptor>("NestedCommentMessage"); 116 var field = nested.FindFieldByName("nested_text"); 117 Assert.NotNull(field.Declaration); 118 Assert.AreEqual(" Leading nested message field comment\n", field.Declaration.LeadingComments); 119 } 120 121 [Test] EnumValueComments()122 public void EnumValueComments() 123 { 124 var enumDescriptor = unitTestProto3Descriptor.FindTypeByName<EnumDescriptor>("CommentEnum"); 125 var value = enumDescriptor.FindValueByName("ZERO_VALUE"); 126 Assert.NotNull(value.Declaration); 127 Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments); 128 } 129 130 [Test] NestedEnumValueComments()131 public void NestedEnumValueComments() 132 { 133 var outer = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("CommentMessage"); 134 var nested = outer.FindDescriptor<EnumDescriptor>("NestedCommentEnum"); 135 var value = nested.FindValueByName("ZERO_VALUE"); 136 Assert.NotNull(value.Declaration); 137 Assert.AreEqual(" Zero value comment\n", value.Declaration.LeadingComments); 138 } 139 140 [Test] OneofComments()141 public void OneofComments() 142 { 143 // CommentMessage doesn't have an enum, but we can use TestAllTypes. 144 var message = unitTestProto3Descriptor.FindTypeByName<MessageDescriptor>("TestAllTypes"); 145 var oneof = message.Oneofs.Single(o => o.Name == "oneof_field"); 146 Assert.NotNull(oneof.Declaration); 147 Assert.AreEqual(" For oneof test\n", oneof.Declaration.LeadingComments); 148 } 149 LoadProtos()150 private static FileDescriptor LoadProtos() 151 { 152 var type = typeof(DescriptorDeclarationTest); 153 // TODO: Make this simpler :) 154 FileDescriptorSet descriptorSet; 155 using (var stream = type.GetTypeInfo().Assembly.GetManifestResourceStream($"Google.Protobuf.Test.testprotos.pb")) 156 { 157 descriptorSet = FileDescriptorSet.Parser.ParseFrom(stream); 158 } 159 var byteStrings = descriptorSet.File.Select(f => f.ToByteString()).ToList(); 160 var descriptors = FileDescriptor.BuildFromByteStrings(byteStrings); 161 return descriptors.Single(d => d.Name == "csharp/protos/unittest_proto3.proto"); 162 } 163 } 164 } 165