diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh index 0508584d7e..49a5a42665 100755 --- a/csharp/generate_protos.sh +++ b/csharp/generate_protos.sh @@ -61,6 +61,7 @@ $PROTOC -Isrc -Icsharp/protos \ csharp/protos/unittest_issue6936_a.proto \ csharp/protos/unittest_issue6936_b.proto \ csharp/protos/unittest_issue6936_c.proto \ + csharp/protos/unittest_selfreferential_options.proto \ src/google/protobuf/unittest_well_known_types.proto \ src/google/protobuf/test_messages_proto3.proto \ src/google/protobuf/test_messages_proto2.proto \ diff --git a/csharp/protos/unittest_selfreferential_options.proto b/csharp/protos/unittest_selfreferential_options.proto new file mode 100644 index 0000000000..22f16cfbf5 --- /dev/null +++ b/csharp/protos/unittest_selfreferential_options.proto @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 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. + +syntax = "proto2"; + +package protobuf_unittest_selfreferential_options; +option csharp_namespace = "UnitTest.Issues.TestProtos.SelfreferentialOptions"; + +import "google/protobuf/descriptor.proto"; + +message FooOptions { + // Custom field option used in definition of the extension message. + optional int32 int_opt = 1 [(foo_options) = { + int_opt: 1 + [foo_int_opt]: 2 + [foo_foo_opt]: { + int_opt: 3 + } + }]; + + // Custom field option used in definition of the custom option's message. + optional int32 foo = 2 [(foo_options) = {foo: 1234}]; + + extensions 1000 to max; +} + +extend google.protobuf.FieldOptions { + // Custom field option used on the definition of that field option. + optional int32 bar_options = 1000 [(bar_options) = 1234]; + + optional FooOptions foo_options = 1001; +} + +extend FooOptions { + optional int32 foo_int_opt = 1000; + optional FooOptions foo_foo_opt = 1001; +} diff --git a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs index d066baec93..852db61ec9 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/CustomOptionsTest.cs @@ -226,6 +226,28 @@ namespace Google.Protobuf.Test.Reflection AssertOption("bar", bar.CustomOptions.TryGetString, UnittestIssue6936AExtensions.Opt, bar.GetOption, bar.GetOptions().GetExtension); } + [Test] + public void SelfReferentialOptions() + { + // Custom field option used in definition of the custom option's message. + var fooField = UnitTest.Issues.TestProtos.SelfreferentialOptions.FooOptions.Descriptor.FindFieldByName("foo"); + var fooFieldFooExtensionValue = fooField.GetOptions().GetExtension(UnitTest.Issues.TestProtos.SelfreferentialOptions.UnittestSelfreferentialOptionsExtensions.FooOptions); + Assert.AreEqual(1234, fooFieldFooExtensionValue.Foo); + + // Custom field option used on the definition of that field option. + var fileDescriptor = UnitTest.Issues.TestProtos.SelfreferentialOptions.UnittestSelfreferentialOptionsReflection.Descriptor; + var barOptionsField = fileDescriptor.Extensions.UnorderedExtensions.Single(field => field.Name == "bar_options"); + var barExtensionValue = barOptionsField.GetOptions().GetExtension(UnitTest.Issues.TestProtos.SelfreferentialOptions.UnittestSelfreferentialOptionsExtensions.BarOptions); + Assert.AreEqual(1234, barExtensionValue); + + // Custom field option used in definition of the extension message. + var intOptField = UnitTest.Issues.TestProtos.SelfreferentialOptions.FooOptions.Descriptor.FindFieldByName("int_opt"); + var intOptFieldFooExtensionValue = intOptField.GetOptions().GetExtension(UnitTest.Issues.TestProtos.SelfreferentialOptions.UnittestSelfreferentialOptionsExtensions.FooOptions); + Assert.AreEqual(1, intOptFieldFooExtensionValue.IntOpt); + Assert.AreEqual(2, intOptFieldFooExtensionValue.GetExtension(UnitTest.Issues.TestProtos.SelfreferentialOptions.UnittestSelfreferentialOptionsExtensions.FooIntOpt)); + Assert.AreEqual(3, intOptFieldFooExtensionValue.GetExtension(UnitTest.Issues.TestProtos.SelfreferentialOptions.UnittestSelfreferentialOptionsExtensions.FooFooOpt).IntOpt); + } + private void AssertOption(T expected, OptionFetcher customOptionFetcher, Extension extension, Func, T> getOptionFetcher, Func, T> extensionFetcher) where D : IExtendableMessage { Assert.IsTrue(customOptionFetcher(extension.FieldNumber, out T customOptionsValue));