blob: 68b4d6af7cf8b70dc124cd37ee2d664dcb000ceb [file] [log] [blame]
Austin Schuh40c16522018-10-28 20:27:54 -07001#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
33using Google.Protobuf.Reflection;
34using Google.Protobuf.WellKnownTypes;
35using NUnit.Framework;
36using System.IO;
37using System.Linq;
38using UnitTest.Issues.TestProtos;
39using static Google.Protobuf.WireFormat;
40using static UnitTest.Issues.TestProtos.ComplexOptionType2.Types;
41using static UnitTest.Issues.TestProtos.DummyMessageContainingEnum.Types;
42using static Google.Protobuf.Test.Reflection.CustomOptionNumber;
43
44namespace 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 {
100 delegate bool OptionFetcher<T>(int field, out T value);
101
102 [Test]
103 public void EmptyOptionsIsShared()
104 {
105 var structOptions = Struct.Descriptor.CustomOptions;
106 var timestampOptions = Struct.Descriptor.CustomOptions;
107 Assert.AreSame(structOptions, timestampOptions);
108 }
109
110 [Test]
111 public void SimpleIntegerTest()
112 {
113 var stream = new MemoryStream();
114 var output = new CodedOutputStream(stream);
115 output.WriteTag(MakeTag(1, WireType.Varint));
116 output.WriteInt32(1234567);
117 output.Flush();
118 stream.Position = 0;
119 var input = new CodedInputStream(stream);
120 input.ReadTag();
121
122 var options = CustomOptions.Empty;
123 options = options.ReadOrSkipUnknownField(input);
124
125 int intValue;
126 Assert.True(options.TryGetInt32(1, out intValue));
127 Assert.AreEqual(1234567, intValue);
128
129 string stringValue;
130 // No ByteString stored values
131 Assert.False(options.TryGetString(1, out stringValue));
132 // Nothing stored for field 2
133 Assert.False(options.TryGetInt32(2, out intValue));
134 }
135
136 [Test]
137 public void SimpleStringTest()
138 {
139 var stream = new MemoryStream();
140 var output = new CodedOutputStream(stream);
141 output.WriteTag(MakeTag(1, WireType.LengthDelimited));
142 output.WriteString("value");
143 output.Flush();
144 stream.Position = 0;
145 var input = new CodedInputStream(stream);
146 input.ReadTag();
147
148 var options = CustomOptions.Empty;
149 options = options.ReadOrSkipUnknownField(input);
150
151 string stringValue;
152 Assert.True(options.TryGetString(1, out stringValue));
153 Assert.AreEqual("value", stringValue);
154
155 int intValue;
156 // No numeric stored values
157 Assert.False(options.TryGetInt32(1, out intValue));
158 // Nothing stored for field 2
159 Assert.False(options.TryGetString(2, out stringValue));
160 }
161
162 [Test]
163 public void ScalarOptions()
164 {
165 var options = CustomOptionOtherValues.Descriptor.CustomOptions;
166 AssertOption(-100, options.TryGetInt32, Int32Opt);
167 AssertOption(12.3456789f, options.TryGetFloat, FloatOpt);
168 AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt);
169 AssertOption("Hello, \"World\"", options.TryGetString, StringOpt);
170 AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt);
171 AssertOption((int) TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt);
172 }
173
174 [Test]
175 public void MessageOptions()
176 {
177 var options = VariousComplexOptions.Descriptor.CustomOptions;
178 AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1);
179 AssertOption(new ComplexOptionType2
180 {
181 Baz = 987, Bar = new ComplexOptionType1 { Foo = 743 },
182 Fred = new ComplexOptionType4 { Waldo = 321 },
183 Barney = { new ComplexOptionType4 { Waldo = 101 }, new ComplexOptionType4 { Waldo = 212 } }
184 },
185 options.TryGetMessage, ComplexOpt2);
186 AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3);
187 }
188
189 [Test]
190 public void OptionLocations()
191 {
192 var fileOptions = UnittestCustomOptionsProto3Reflection.Descriptor.CustomOptions;
193 AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1);
194
195 var messageOptions = TestMessageWithCustomOptions.Descriptor.CustomOptions;
196 AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1);
197
198 var fieldOptions = TestMessageWithCustomOptions.Descriptor.Fields["field1"] .CustomOptions;
199 AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1);
200
201 var oneofOptions = TestMessageWithCustomOptions.Descriptor.Oneofs[0].CustomOptions;
202 AssertOption(-99, oneofOptions.TryGetInt32, OneofOpt1);
203
204 var enumOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].CustomOptions;
205 AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1);
206
207 var enumValueOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].FindValueByNumber(2).CustomOptions;
208 AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1);
209
210 var service = UnittestCustomOptionsProto3Reflection.Descriptor.Services
211 .Single(s => s.Name == "TestServiceWithCustomOptions");
212 var serviceOptions = service.CustomOptions;
213 AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1);
214
215 var methodOptions = service.Methods[0].CustomOptions;
216 AssertOption((int) UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1);
217 }
218
219 [Test]
220 public void MinValues()
221 {
222 var options = CustomOptionMinIntegerValues.Descriptor.CustomOptions;
223 AssertOption(false, options.TryGetBool, BoolOpt);
224 AssertOption(int.MinValue, options.TryGetInt32, Int32Opt);
225 AssertOption(long.MinValue, options.TryGetInt64, Int64Opt);
226 AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt);
227 AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt);
228 AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt);
229 AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt);
230 AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt);
231 AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt);
232 AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt);
233 AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt);
234 }
235
236 [Test]
237 public void MaxValues()
238 {
239 var options = CustomOptionMaxIntegerValues.Descriptor.CustomOptions;
240 AssertOption(true, options.TryGetBool, BoolOpt);
241 AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt);
242 AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt);
243 AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt);
244 AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt);
245 AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt);
246 AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt);
247 AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt);
248 AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt);
249 AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt);
250 AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt);
251 }
252
253 [Test]
254 public void AggregateOptions()
255 {
256 // Just two examples
257 var messageOptions = AggregateMessage.Descriptor.CustomOptions;
258 AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt);
259
260 var fieldOptions = AggregateMessage.Descriptor.Fields["fieldname"].CustomOptions;
261 AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt);
262 }
263
264 private void AssertOption<T>(T expected, OptionFetcher<T> fetcher, CustomOptionNumber field)
265 {
266 T actual;
267 Assert.IsTrue(fetcher((int) field, out actual));
268 Assert.AreEqual(expected, actual);
269 }
270 }
271}