FieldPresenceTest.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2015 Google Inc. All rights reserved.
  4. // Author: jieluo@google.com (Jie Luo)
  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. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #endregion
  31. using System;
  32. using Google.ProtocolBuffers.Descriptors;
  33. using Google.ProtocolBuffers.TestProtos.Proto3;
  34. using NUnit.Framework;
  35. namespace Google.ProtocolBuffers
  36. {
  37. public class FieldPresenceTest
  38. {
  39. private void CheckHasMethodRemoved(Type proto2Type, Type proto3Type, string name)
  40. {
  41. Assert.NotNull(proto2Type.GetProperty(name));
  42. Assert.NotNull(proto2Type.GetProperty("Has" + name));
  43. Assert.NotNull(proto3Type.GetProperty(name));
  44. Assert.Null(proto3Type.GetProperty("Has" + name));
  45. }
  46. [Test]
  47. public void TestHasMethod()
  48. {
  49. // Optional non-message fields don't have HasFoo method generated
  50. Type proto2Type = typeof(Google.ProtocolBuffers.TestProtos.TestAllTypes);
  51. Type proto3Type = typeof(TestAllTypes);
  52. CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalInt32");
  53. CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalString");
  54. CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalBytes");
  55. CheckHasMethodRemoved(proto2Type, proto3Type, "OptionalNestedEnum");
  56. Type proto2BuilderType = typeof(Google.ProtocolBuffers.TestProtos.TestAllTypes.Builder);
  57. Type proto3BuilderType = typeof(TestAllTypes.Builder);
  58. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OptionalInt32");
  59. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OptionalString");
  60. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OptionalBytes");
  61. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OptionalNestedEnum");
  62. // message fields still have the HasFoo method generated
  63. Assert.IsFalse(TestAllTypes.CreateBuilder().Build().HasOptionalNestedMessage);
  64. Assert.IsFalse(TestAllTypes.CreateBuilder().HasOptionalNestedMessage);
  65. // oneof fields don't have the HasFoo method (even for message types)
  66. CheckHasMethodRemoved(proto2Type, proto3Type, "OneofUint32");
  67. CheckHasMethodRemoved(proto2Type, proto3Type, "OneofString");
  68. CheckHasMethodRemoved(proto2Type, proto3Type, "OneofNestedMessage");
  69. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OneofUint32");
  70. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OneofString");
  71. CheckHasMethodRemoved(proto2BuilderType, proto3BuilderType, "OneofNestedMessage");
  72. }
  73. [Test]
  74. public void TestFieldPresence()
  75. {
  76. // Optional non-message fields set to their default value are treated the same
  77. // way as not set.
  78. // Serialization will ignore such fields.
  79. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  80. builder.SetOptionalInt32(0);
  81. builder.SetOptionalString("");
  82. builder.SetOptionalBytes(ByteString.Empty);
  83. builder.SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.FOO);
  84. TestAllTypes message = builder.Build();
  85. Assert.AreEqual(0, message.SerializedSize);
  86. // Test merge
  87. TestAllTypes.Builder a = TestAllTypes.CreateBuilder();
  88. a.SetOptionalInt32(1);
  89. a.SetOptionalString("x");
  90. a.SetOptionalBytes(ByteString.CopyFromUtf8("y"));
  91. a.SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.BAR);
  92. a.MergeFrom(message);
  93. TestAllTypes messageA = a.Build();
  94. Assert.AreEqual(1, messageA.OptionalInt32);
  95. Assert.AreEqual("x", messageA.OptionalString);
  96. Assert.AreEqual(ByteString.CopyFromUtf8("y"), messageA.OptionalBytes);
  97. Assert.AreEqual(TestAllTypes.Types.NestedEnum.BAR, messageA.OptionalNestedEnum);
  98. // equals/hashCode should produce the same results
  99. TestAllTypes empty = TestAllTypes.CreateBuilder().Build();
  100. Assert.IsTrue(empty.Equals(message));
  101. Assert.IsTrue(message.Equals(empty));
  102. Assert.AreEqual(empty.GetHashCode(), message.GetHashCode());
  103. }
  104. [Test]
  105. public void TestFieldPresenceReflection()
  106. {
  107. MessageDescriptor descriptor = TestAllTypes.Descriptor;
  108. FieldDescriptor optionalInt32Field = descriptor.FindFieldByName("optional_int32");
  109. FieldDescriptor optionalStringField = descriptor.FindFieldByName("optional_string");
  110. FieldDescriptor optionalBytesField = descriptor.FindFieldByName("optional_bytes");
  111. FieldDescriptor optionalNestedEnumField = descriptor.FindFieldByName("optional_nested_enum");
  112. FieldDescriptor oneofUint32Field = descriptor.FindFieldByName("oneof_uint32");
  113. TestAllTypes message = TestAllTypes.CreateBuilder().Build();
  114. Assert.IsFalse(message.HasField(optionalInt32Field));
  115. Assert.IsFalse(message.HasField(optionalStringField));
  116. Assert.IsFalse(message.HasField(optionalBytesField));
  117. Assert.IsFalse(message.HasField(optionalNestedEnumField));
  118. // Set to default value is seen as not present for optional fields.
  119. // Set to default value is seen as present for oneof fields.
  120. message = TestAllTypes.CreateBuilder()
  121. .SetOptionalInt32(0)
  122. .SetOptionalString("")
  123. .SetOptionalBytes(ByteString.Empty)
  124. .SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.FOO)
  125. .SetOneofUint32(0U)
  126. .Build();
  127. Assert.IsFalse(message.HasField(optionalInt32Field));
  128. Assert.IsFalse(message.HasField(optionalStringField));
  129. Assert.IsFalse(message.HasField(optionalBytesField));
  130. Assert.IsFalse(message.HasField(optionalNestedEnumField));
  131. Assert.IsTrue(message.HasField(oneofUint32Field));
  132. Assert.AreEqual(1, message.AllFields.Count);
  133. // Set to non-defalut value is seen as present
  134. message = TestAllTypes.CreateBuilder()
  135. .SetOptionalInt32(1)
  136. .SetOptionalString("x")
  137. .SetOptionalBytes(ByteString.CopyFromUtf8("y"))
  138. .SetOptionalNestedEnum(TestAllTypes.Types.NestedEnum.BAR)
  139. .Build();
  140. Assert.IsTrue(message.HasField(optionalInt32Field));
  141. Assert.IsTrue(message.HasField(optionalStringField));
  142. Assert.IsTrue(message.HasField(optionalBytesField));
  143. Assert.IsTrue(message.HasField(optionalNestedEnumField));
  144. Assert.AreEqual(4, message.AllFields.Count);
  145. }
  146. [Test]
  147. public void TestMessageField()
  148. {
  149. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  150. Assert.IsFalse(builder.HasOptionalNestedMessage);
  151. Assert.IsFalse(builder.Build().HasOptionalNestedMessage);
  152. // Unlike non-message fields, if we set default value to message field, the field
  153. // shoule be seem as present.
  154. builder.SetOptionalNestedMessage(TestAllTypes.Types.NestedMessage.DefaultInstance);
  155. Assert.IsTrue(builder.HasOptionalNestedMessage);
  156. Assert.IsTrue(builder.Build().HasOptionalNestedMessage);
  157. }
  158. [Test]
  159. public void TestSerializeAndParse()
  160. {
  161. TestAllTypes.Builder builder = TestAllTypes.CreateBuilder();
  162. builder.SetOptionalInt32(1234);
  163. builder.SetOptionalString("hello");
  164. builder.SetOptionalNestedMessage(TestAllTypes.Types.NestedMessage.DefaultInstance);
  165. builder.SetOneofUint32(0U);
  166. ByteString data = builder.Build().ToByteString();
  167. TestAllTypes message = TestAllTypes.ParseFrom(data);
  168. Assert.AreEqual(1234, message.OptionalInt32);
  169. Assert.AreEqual("hello", message.OptionalString);
  170. Assert.AreEqual(ByteString.Empty, message.OptionalBytes);
  171. Assert.AreEqual(TestAllTypes.Types.NestedEnum.FOO, message.OptionalNestedEnum);
  172. Assert.IsTrue(message.HasOptionalNestedMessage);
  173. Assert.AreEqual(0, message.OptionalNestedMessage.Bb);
  174. Assert.AreEqual(TestAllTypes.OneofFieldOneofCase.OneofUint32, message.OneofFieldCase);
  175. }
  176. }
  177. }