1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2017 Google Inc.  All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32 
33 using Google.Protobuf.Reflection;
34 using Google.Protobuf.WellKnownTypes;
35 using NUnit.Framework;
36 using System.IO;
37 using System.Linq;
38 using UnitTest.Issues.TestProtos;
39 using static Google.Protobuf.WireFormat;
40 using static UnitTest.Issues.TestProtos.ComplexOptionType2.Types;
41 using static UnitTest.Issues.TestProtos.DummyMessageContainingEnum.Types;
42 using static Google.Protobuf.Test.Reflection.CustomOptionNumber;
43 
44 namespace Google.Protobuf.Test.Reflection
45 {
46     // Internal enum to allow us to use "using static" for convenience.
47     // These are the options defined in unittest_custom_options_proto3.proto
48     internal enum CustomOptionNumber
49     {
50         FileOpt1 = 7736974,
51         MessageOpt1 = 7739036,
52         FieldOpt1 = 7740936,
53         OneofOpt1 = 7740111,
54         EnumOpt1 = 7753576,
55         EnumValueOpt1 = 1560678,
56         ServiceOpt1 = 7887650,
57         MethodOpt1 = 7890860,
58 
59         // All message options...
60         BoolOpt = 7706090,
61         Int32Opt = 7705709,
62         Int64Opt = 7705542,
63         UInt32Opt = 7704880,
64         UInt64Opt = 7702367,
65         SInt32Opt = 7701568,
66         SInt64Opt = 7700863,
67         Fixed32Opt = 7700307,
68         Fixed64Opt = 7700194,
69         SFixed32Opt = 7698645,
70         SFixed64Opt = 7685475,
71         FloatOpt = 7675390,
72         DoubleOpt = 7673293,
73         StringOpt = 7673285,
74         BytesOpt = 7673238,
75         EnumOpt = 7673233,
76         MessageTypeOpt = 7665967,
77 
78         // Miscellaneous
79         ComplexOpt4 = 7633546,
80         ComplexOpt1 = 7646756,
81         ComplexOpt2 = 7636949,
82         ComplexOpt3 = 7636463,
83 
84         // Aggregates
85         AggregateFileOpt = 15478479,
86         AggregateMsgOpt = 15480088,
87         AggregateFieldOpt = 15481374,
88         AggregateEnumOpt = 15483218,
89         AggregateEnumValueOpt = 15486921,
90         AggregateServiceOpt = 15497145,
91         AggregateMethodOpt = 15512713,
92     }
93 
94     /// <summary>
95     /// The majority of the testing here is done via parsed descriptors. That's simpler to
96     /// achieve (and more important) than constructing a CodedInputStream manually.
97     /// </summary>
98     public class CustomOptionsTest
99     {
OptionFetcher(int field, out T value)100         delegate bool OptionFetcher<T>(int field, out T value);
101 
102         [Test]
ScalarOptions()103         public void ScalarOptions()
104         {
105             var options = CustomOptionOtherValues.Descriptor.CustomOptions;
106             AssertOption(-100, options.TryGetInt32, Int32Opt);
107             AssertOption(12.3456789f, options.TryGetFloat, FloatOpt);
108             AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt);
109             AssertOption("Hello, \"World\"", options.TryGetString, StringOpt);
110             AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt);
111             AssertOption((int)TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt);
112         }
113 
114         [Test]
MessageOptions()115         public void MessageOptions()
116         {
117             var options = VariousComplexOptions.Descriptor.CustomOptions;
118             AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1);
119             AssertOption(new ComplexOptionType2
120             {
121                 Baz = 987,
122                 Bar = new ComplexOptionType1 { Foo = 743 },
123                 Fred = new ComplexOptionType4 { Waldo = 321 },
124                 Barney = { new ComplexOptionType4 { Waldo = 101 }, new ComplexOptionType4 { Waldo = 212 } }
125             },
126                 options.TryGetMessage, ComplexOpt2);
127             AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3);
128         }
129 
130         [Test]
OptionLocations()131         public void OptionLocations()
132         {
133             var fileOptions = UnittestCustomOptionsProto3Reflection.Descriptor.CustomOptions;
134             AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1);
135 
136             var messageOptions = TestMessageWithCustomOptions.Descriptor.CustomOptions;
137             AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1);
138 
139             var fieldOptions = TestMessageWithCustomOptions.Descriptor.Fields["field1"].CustomOptions;
140             AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1);
141 
142             var oneofOptions = TestMessageWithCustomOptions.Descriptor.Oneofs[0].CustomOptions;
143             AssertOption(-99, oneofOptions.TryGetInt32, OneofOpt1);
144 
145             var enumOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].CustomOptions;
146             AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1);
147 
148             var enumValueOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].FindValueByNumber(2).CustomOptions;
149             AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1);
150 
151             var service = UnittestCustomOptionsProto3Reflection.Descriptor.Services
152                 .Single(s => s.Name == "TestServiceWithCustomOptions");
153             var serviceOptions = service.CustomOptions;
154             AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1);
155 
156             var methodOptions = service.Methods[0].CustomOptions;
157             AssertOption((int)UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1);
158         }
159 
160         [Test]
MinValues()161         public void MinValues()
162         {
163             var options = CustomOptionMinIntegerValues.Descriptor.CustomOptions;
164             AssertOption(false, options.TryGetBool, BoolOpt);
165             AssertOption(int.MinValue, options.TryGetInt32, Int32Opt);
166             AssertOption(long.MinValue, options.TryGetInt64, Int64Opt);
167             AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt);
168             AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt);
169             AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt);
170             AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt);
171             AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt);
172             AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt);
173             AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt);
174             AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt);
175         }
176 
177         [Test]
MaxValues()178         public void MaxValues()
179         {
180             var options = CustomOptionMaxIntegerValues.Descriptor.CustomOptions;
181             AssertOption(true, options.TryGetBool, BoolOpt);
182             AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt);
183             AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt);
184             AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt);
185             AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt);
186             AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt);
187             AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt);
188             AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt);
189             AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt);
190             AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt);
191             AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt);
192         }
193 
194         [Test]
AggregateOptions()195         public void AggregateOptions()
196         {
197             // Just two examples
198             var messageOptions = AggregateMessage.Descriptor.CustomOptions;
199             AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt);
200 
201             var fieldOptions = AggregateMessage.Descriptor.Fields["fieldname"].CustomOptions;
202             AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt);
203         }
204 
AssertOption(T expected, OptionFetcher<T> fetcher, CustomOptionNumber field)205         private void AssertOption<T>(T expected, OptionFetcher<T> fetcher, CustomOptionNumber field)
206         {
207             T actual;
208             Assert.IsTrue(fetcher((int)field, out actual));
209             Assert.AreEqual(expected, actual);
210         }
211     }
212 }
213