CustomOptionsTest.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. using Google.Protobuf.Reflection;
  33. using Google.Protobuf.WellKnownTypes;
  34. using NUnit.Framework;
  35. using System.IO;
  36. using System.Linq;
  37. using UnitTest.Issues.TestProtos;
  38. using static Google.Protobuf.WireFormat;
  39. using static UnitTest.Issues.TestProtos.ComplexOptionType2.Types;
  40. using static UnitTest.Issues.TestProtos.DummyMessageContainingEnum.Types;
  41. using static Google.Protobuf.Test.Reflection.CustomOptionNumber;
  42. namespace Google.Protobuf.Test.Reflection
  43. {
  44. // Internal enum to allow us to use "using static" for convenience.
  45. // These are the options defined in unittest_custom_options_proto3.proto
  46. internal enum CustomOptionNumber
  47. {
  48. FileOpt1 = 7736974,
  49. MessageOpt1 = 7739036,
  50. FieldOpt1 = 7740936,
  51. EnumOpt1 = 7753576,
  52. EnumValueOpt1 = 1560678,
  53. ServiceOpt1 = 7887650,
  54. MethodOpt1 = 7890860,
  55. // All message options...
  56. BoolOpt = 7706090,
  57. Int32Opt = 7705709,
  58. Int64Opt = 7705542,
  59. UInt32Opt = 7704880,
  60. UInt64Opt = 7702367,
  61. SInt32Opt = 7701568,
  62. SInt64Opt = 7700863,
  63. Fixed32Opt = 7700307,
  64. Fixed64Opt = 7700194,
  65. SFixed32Opt = 7698645,
  66. SFixed64Opt = 7685475,
  67. FloatOpt = 7675390,
  68. DoubleOpt = 7673293,
  69. StringOpt = 7673285,
  70. BytesOpt = 7673238,
  71. EnumOpt = 7673233,
  72. MessageTypeOpt = 7665967,
  73. // Miscellaneous
  74. ComplexOpt4 = 7633546,
  75. ComplexOpt1 = 7646756,
  76. ComplexOpt2 = 7636949,
  77. ComplexOpt3 = 7636463,
  78. // Aggregates
  79. AggregateFileOpt = 15478479,
  80. AggregateMsgOpt = 15480088,
  81. AggregateFieldOpt = 15481374,
  82. AggregateEnumOpt = 15483218,
  83. AggregateEnumValueOpt = 15486921,
  84. AggregateServiceOpt = 15497145,
  85. AggregateMethodOpt = 15512713,
  86. }
  87. /// <summary>
  88. /// The majority of the testing here is done via parsed descriptors. That's simpler to
  89. /// achieve (and more important) than constructing a CodedInputStream manually.
  90. /// </summary>
  91. public class CustomOptionsTest
  92. {
  93. delegate bool OptionFetcher<T>(int field, out T value);
  94. [Test]
  95. public void EmptyOptionsIsShared()
  96. {
  97. var structOptions = Struct.Descriptor.CustomOptions;
  98. var timestampOptions = Struct.Descriptor.CustomOptions;
  99. Assert.AreSame(structOptions, timestampOptions);
  100. }
  101. [Test]
  102. public void SimpleIntegerTest()
  103. {
  104. var stream = new MemoryStream();
  105. var output = new CodedOutputStream(stream);
  106. output.WriteTag(MakeTag(1, WireType.Varint));
  107. output.WriteInt32(1234567);
  108. output.Flush();
  109. stream.Position = 0;
  110. var input = new CodedInputStream(stream);
  111. input.ReadTag();
  112. var options = CustomOptions.Empty;
  113. options = options.ReadOrSkipUnknownField(input);
  114. int intValue;
  115. Assert.True(options.TryGetInt32(1, out intValue));
  116. Assert.AreEqual(1234567, intValue);
  117. string stringValue;
  118. // No ByteString stored values
  119. Assert.False(options.TryGetString(1, out stringValue));
  120. // Nothing stored for field 2
  121. Assert.False(options.TryGetInt32(2, out intValue));
  122. }
  123. [Test]
  124. public void SimpleStringTest()
  125. {
  126. var stream = new MemoryStream();
  127. var output = new CodedOutputStream(stream);
  128. output.WriteTag(MakeTag(1, WireType.LengthDelimited));
  129. output.WriteString("value");
  130. output.Flush();
  131. stream.Position = 0;
  132. var input = new CodedInputStream(stream);
  133. input.ReadTag();
  134. var options = CustomOptions.Empty;
  135. options = options.ReadOrSkipUnknownField(input);
  136. string stringValue;
  137. Assert.True(options.TryGetString(1, out stringValue));
  138. Assert.AreEqual("value", stringValue);
  139. int intValue;
  140. // No numeric stored values
  141. Assert.False(options.TryGetInt32(1, out intValue));
  142. // Nothing stored for field 2
  143. Assert.False(options.TryGetString(2, out stringValue));
  144. }
  145. [Test]
  146. public void ScalarOptions()
  147. {
  148. var options = CustomOptionOtherValues.Descriptor.CustomOptions;
  149. AssertOption(-100, options.TryGetInt32, Int32Opt);
  150. AssertOption(12.3456789f, options.TryGetFloat, FloatOpt);
  151. AssertOption(1.234567890123456789d, options.TryGetDouble, DoubleOpt);
  152. AssertOption("Hello, \"World\"", options.TryGetString, StringOpt);
  153. AssertOption(ByteString.CopyFromUtf8("Hello\0World"), options.TryGetBytes, BytesOpt);
  154. AssertOption((int) TestEnumType.TestOptionEnumType2, options.TryGetInt32, EnumOpt);
  155. }
  156. [Test]
  157. public void MessageOptions()
  158. {
  159. var options = VariousComplexOptions.Descriptor.CustomOptions;
  160. AssertOption(new ComplexOptionType1 { Foo = 42, Foo4 = { 99, 88 } }, options.TryGetMessage, ComplexOpt1);
  161. AssertOption(new ComplexOptionType2
  162. {
  163. Baz = 987, Bar = new ComplexOptionType1 { Foo = 743 },
  164. Fred = new ComplexOptionType4 { Waldo = 321 },
  165. Barney = { new ComplexOptionType4 { Waldo = 101 }, new ComplexOptionType4 { Waldo = 212 } }
  166. },
  167. options.TryGetMessage, ComplexOpt2);
  168. AssertOption(new ComplexOptionType3 { Qux = 9 }, options.TryGetMessage, ComplexOpt3);
  169. }
  170. [Test]
  171. public void OptionLocations()
  172. {
  173. var fileOptions = UnittestCustomOptionsProto3Reflection.Descriptor.CustomOptions;
  174. AssertOption(9876543210UL, fileOptions.TryGetUInt64, FileOpt1);
  175. var messageOptions = TestMessageWithCustomOptions.Descriptor.CustomOptions;
  176. AssertOption(-56, messageOptions.TryGetInt32, MessageOpt1);
  177. var fieldOptions = TestMessageWithCustomOptions.Descriptor.Fields["field1"] .CustomOptions;
  178. AssertOption(8765432109UL, fieldOptions.TryGetFixed64, FieldOpt1);
  179. var enumOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].CustomOptions;
  180. AssertOption(-789, enumOptions.TryGetSFixed32, EnumOpt1);
  181. var enumValueOptions = TestMessageWithCustomOptions.Descriptor.EnumTypes[0].FindValueByNumber(2).CustomOptions;
  182. AssertOption(123, enumValueOptions.TryGetInt32, EnumValueOpt1);
  183. var service = UnittestCustomOptionsProto3Reflection.Descriptor.Services
  184. .Single(s => s.Name == "TestServiceWithCustomOptions");
  185. var serviceOptions = service.CustomOptions;
  186. AssertOption(-9876543210, serviceOptions.TryGetSInt64, ServiceOpt1);
  187. var methodOptions = service.Methods[0].CustomOptions;
  188. AssertOption((int) UnitTest.Issues.TestProtos.MethodOpt1.Val2, methodOptions.TryGetInt32, CustomOptionNumber.MethodOpt1);
  189. }
  190. [Test]
  191. public void MinValues()
  192. {
  193. var options = CustomOptionMinIntegerValues.Descriptor.CustomOptions;
  194. AssertOption(false, options.TryGetBool, BoolOpt);
  195. AssertOption(int.MinValue, options.TryGetInt32, Int32Opt);
  196. AssertOption(long.MinValue, options.TryGetInt64, Int64Opt);
  197. AssertOption(uint.MinValue, options.TryGetUInt32, UInt32Opt);
  198. AssertOption(ulong.MinValue, options.TryGetUInt64, UInt64Opt);
  199. AssertOption(int.MinValue, options.TryGetSInt32, SInt32Opt);
  200. AssertOption(long.MinValue, options.TryGetSInt64, SInt64Opt);
  201. AssertOption(uint.MinValue, options.TryGetUInt32, Fixed32Opt);
  202. AssertOption(ulong.MinValue, options.TryGetUInt64, Fixed64Opt);
  203. AssertOption(int.MinValue, options.TryGetInt32, SFixed32Opt);
  204. AssertOption(long.MinValue, options.TryGetInt64, SFixed64Opt);
  205. }
  206. [Test]
  207. public void MaxValues()
  208. {
  209. var options = CustomOptionMaxIntegerValues.Descriptor.CustomOptions;
  210. AssertOption(true, options.TryGetBool, BoolOpt);
  211. AssertOption(int.MaxValue, options.TryGetInt32, Int32Opt);
  212. AssertOption(long.MaxValue, options.TryGetInt64, Int64Opt);
  213. AssertOption(uint.MaxValue, options.TryGetUInt32, UInt32Opt);
  214. AssertOption(ulong.MaxValue, options.TryGetUInt64, UInt64Opt);
  215. AssertOption(int.MaxValue, options.TryGetSInt32, SInt32Opt);
  216. AssertOption(long.MaxValue, options.TryGetSInt64, SInt64Opt);
  217. AssertOption(uint.MaxValue, options.TryGetFixed32, Fixed32Opt);
  218. AssertOption(ulong.MaxValue, options.TryGetFixed64, Fixed64Opt);
  219. AssertOption(int.MaxValue, options.TryGetSFixed32, SFixed32Opt);
  220. AssertOption(long.MaxValue, options.TryGetSFixed64, SFixed64Opt);
  221. }
  222. [Test]
  223. public void AggregateOptions()
  224. {
  225. // Just two examples
  226. var messageOptions = AggregateMessage.Descriptor.CustomOptions;
  227. AssertOption(new Aggregate { I = 101, S = "MessageAnnotation" }, messageOptions.TryGetMessage, AggregateMsgOpt);
  228. var fieldOptions = AggregateMessage.Descriptor.Fields["fieldname"].CustomOptions;
  229. AssertOption(new Aggregate { S = "FieldAnnotation" }, fieldOptions.TryGetMessage, AggregateFieldOpt);
  230. }
  231. private void AssertOption<T>(T expected, OptionFetcher<T> fetcher, CustomOptionNumber field)
  232. {
  233. T actual;
  234. Assert.IsTrue(fetcher((int) field, out actual));
  235. Assert.AreEqual(expected, actual);
  236. }
  237. }
  238. }