Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     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 
     31 #include <google/protobuf/unittest.pb.h>
     32 #include <google/protobuf/unittest_preserve_unknown_enum.pb.h>
     33 #include <google/protobuf/unittest_preserve_unknown_enum2.pb.h>
     34 #include <google/protobuf/dynamic_message.h>
     35 #include <google/protobuf/descriptor.h>
     36 #include <gtest/gtest.h>
     37 
     38 namespace google {
     39 namespace protobuf {
     40 namespace {
     41 
     42 void FillMessage(
     43     proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra* message) {
     44   message->set_e(
     45       proto3_preserve_unknown_enum_unittest::E_EXTRA);
     46   message->add_repeated_e(
     47       proto3_preserve_unknown_enum_unittest::E_EXTRA);
     48   message->add_repeated_packed_e(
     49       proto3_preserve_unknown_enum_unittest::E_EXTRA);
     50   message->add_repeated_packed_unexpected_e(
     51       proto3_preserve_unknown_enum_unittest::E_EXTRA);
     52   message->set_oneof_e_1(
     53       proto3_preserve_unknown_enum_unittest::E_EXTRA);
     54 }
     55 
     56 void CheckMessage(
     57     const proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra& message) {
     58   EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
     59             message.e());
     60   EXPECT_EQ(1, message.repeated_e_size());
     61   EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
     62             message.repeated_e(0));
     63   EXPECT_EQ(1, message.repeated_packed_e_size());
     64   EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
     65             message.repeated_packed_e(0));
     66   EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
     67   EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
     68             message.repeated_packed_unexpected_e(0));
     69   EXPECT_EQ(proto3_preserve_unknown_enum_unittest::E_EXTRA,
     70             message.oneof_e_1());
     71 }
     72 
     73 void CheckMessage(
     74     const proto3_preserve_unknown_enum_unittest::MyMessage& message) {
     75   EXPECT_EQ(static_cast<int>(
     76               proto3_preserve_unknown_enum_unittest::E_EXTRA),
     77             static_cast<int>(message.e()));
     78   EXPECT_EQ(1, message.repeated_e_size());
     79   EXPECT_EQ(static_cast<int>(
     80               proto3_preserve_unknown_enum_unittest::E_EXTRA),
     81             static_cast<int>(message.repeated_e(0)));
     82   EXPECT_EQ(1, message.repeated_packed_e_size());
     83   EXPECT_EQ(static_cast<int>(
     84               proto3_preserve_unknown_enum_unittest::E_EXTRA),
     85             static_cast<int>(message.repeated_packed_e(0)));
     86   EXPECT_EQ(1, message.repeated_packed_unexpected_e_size());
     87   EXPECT_EQ(static_cast<int>(
     88               proto3_preserve_unknown_enum_unittest::E_EXTRA),
     89             static_cast<int>(message.repeated_packed_unexpected_e(0)));
     90   EXPECT_EQ(static_cast<int>(
     91               proto3_preserve_unknown_enum_unittest::E_EXTRA),
     92             static_cast<int>(message.oneof_e_1()));
     93 }
     94 
     95 }  // anonymous namespace
     96 
     97 // Test that parsing preserves an unknown value in the enum field and does not
     98 // punt it to the UnknownFieldSet.
     99 TEST(PreserveUnknownEnumTest, PreserveParseAndSerialize) {
    100   proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
    101   FillMessage(&orig_message);
    102   string serialized;
    103   orig_message.SerializeToString(&serialized);
    104 
    105   proto3_preserve_unknown_enum_unittest::MyMessage message;
    106   EXPECT_EQ(true, message.ParseFromString(serialized));
    107   CheckMessage(message);
    108 
    109   serialized.clear();
    110   message.SerializeToString(&serialized);
    111   EXPECT_EQ(true, orig_message.ParseFromString(serialized));
    112   CheckMessage(orig_message);
    113 }
    114 
    115 // Test that reflection based implementation also keeps unknown enum values and
    116 // doesn't put them into UnknownFieldSet.
    117 TEST(PreserveUnknownEnumTest, PreserveParseAndSerializeDynamicMessage) {
    118   proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
    119   FillMessage(&orig_message);
    120   string serialized = orig_message.SerializeAsString();
    121 
    122   google::protobuf::DynamicMessageFactory factory;
    123   google::protobuf::scoped_ptr<google::protobuf::Message> message(factory.GetPrototype(
    124       proto3_preserve_unknown_enum_unittest::MyMessage::descriptor())->New());
    125   EXPECT_EQ(true, message->ParseFromString(serialized));
    126   message->DiscardUnknownFields();
    127 
    128   serialized = message->SerializeAsString();
    129   EXPECT_EQ(true, orig_message.ParseFromString(serialized));
    130   CheckMessage(orig_message);
    131 }
    132 
    133 // Test that for proto2 messages, unknown values are in unknown fields.
    134 TEST(PreserveUnknownEnumTest, Proto2HidesUnknownValues) {
    135   proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
    136   FillMessage(&orig_message);
    137 
    138   string serialized;
    139   orig_message.SerializeToString(&serialized);
    140 
    141   proto2_preserve_unknown_enum_unittest::MyMessage message;
    142   EXPECT_EQ(true, message.ParseFromString(serialized));
    143   // The intermediate message has everything in its "unknown fields".
    144   proto2_preserve_unknown_enum_unittest::MyMessage message2 = message;
    145   message2.DiscardUnknownFields();
    146   EXPECT_EQ(0, message2.ByteSize());
    147 
    148   // But when we pass it to the correct structure, all values are there.
    149   serialized.clear();
    150   message.SerializeToString(&serialized);
    151   EXPECT_EQ(true, orig_message.ParseFromString(serialized));
    152   CheckMessage(orig_message);
    153 }
    154 
    155 // Same as before, for a dynamic message.
    156 TEST(PreserveUnknownEnumTest, DynamicProto2HidesUnknownValues) {
    157   proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
    158   FillMessage(&orig_message);
    159 
    160   string serialized;
    161   orig_message.SerializeToString(&serialized);
    162 
    163   google::protobuf::DynamicMessageFactory factory;
    164   google::protobuf::scoped_ptr<google::protobuf::Message> message(factory.GetPrototype(
    165       proto2_preserve_unknown_enum_unittest::MyMessage::descriptor())->New());
    166   EXPECT_EQ(true, message->ParseFromString(serialized));
    167   // The intermediate message has everything in its "unknown fields".
    168   proto2_preserve_unknown_enum_unittest::MyMessage message2;
    169   message2.CopyFrom(*message);
    170   message2.DiscardUnknownFields();
    171   EXPECT_EQ(0, message2.ByteSize());
    172 
    173   // But when we pass it to the correct structure, all values are there.
    174   serialized.clear();
    175   message->SerializeToString(&serialized);
    176   EXPECT_EQ(true, orig_message.ParseFromString(serialized));
    177   CheckMessage(orig_message);
    178 }
    179 
    180 // Test that reflection provides EnumValueDescriptors for unknown values.
    181 TEST(PreserveUnknownEnumTest, DynamicEnumValueDescriptors) {
    182   proto3_preserve_unknown_enum_unittest::MyMessagePlusExtra orig_message;
    183   FillMessage(&orig_message);
    184   string serialized;
    185   orig_message.SerializeToString(&serialized);
    186 
    187   proto3_preserve_unknown_enum_unittest::MyMessage message;
    188   EXPECT_EQ(true, message.ParseFromString(serialized));
    189   CheckMessage(message);
    190 
    191   const google::protobuf::Reflection* r = message.GetReflection();
    192   const google::protobuf::Descriptor* d = message.GetDescriptor();
    193   const google::protobuf::FieldDescriptor* field = d->FindFieldByName("e");
    194 
    195   // This should dynamically create an EnumValueDescriptor.
    196   const google::protobuf::EnumValueDescriptor* enum_value = r->GetEnum(message, field);
    197   EXPECT_EQ(enum_value->number(),
    198             static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA));
    199 
    200   // Fetching value for a second time should return the same pointer.
    201   const google::protobuf::EnumValueDescriptor* enum_value_second =
    202       r->GetEnum(message, field);
    203   EXPECT_EQ(enum_value, enum_value_second);
    204 
    205   // Check the repeated case too.
    206   const google::protobuf::FieldDescriptor* repeated_field =
    207       d->FindFieldByName("repeated_e");
    208   enum_value = r->GetRepeatedEnum(message, repeated_field, 0);
    209   EXPECT_EQ(enum_value->number(),
    210             static_cast<int>(proto3_preserve_unknown_enum_unittest::E_EXTRA));
    211   // Should reuse the same EnumValueDescriptor, even for a different field.
    212   EXPECT_EQ(enum_value, enum_value_second);
    213 
    214   // We should be able to use the returned value descriptor to set a value on
    215   // another message.
    216   google::protobuf::Message* m = message.New();
    217   r->SetEnum(m, field, enum_value);
    218   EXPECT_EQ(enum_value, r->GetEnum(*m, field));
    219   delete m;
    220 }
    221 
    222 // Test that the new integer-based enum reflection API works.
    223 TEST(PreserveUnknownEnumTest, IntegerEnumReflectionAPI) {
    224   proto3_preserve_unknown_enum_unittest::MyMessage message;
    225   const google::protobuf::Reflection* r = message.GetReflection();
    226   const google::protobuf::Descriptor* d = message.GetDescriptor();
    227 
    228   const google::protobuf::FieldDescriptor* singular_field = d->FindFieldByName("e");
    229   const google::protobuf::FieldDescriptor* repeated_field =
    230       d->FindFieldByName("repeated_e");
    231 
    232   r->SetEnumValue(&message, singular_field, 42);
    233   EXPECT_EQ(42, r->GetEnumValue(message, singular_field));
    234   r->AddEnumValue(&message, repeated_field, 42);
    235   r->AddEnumValue(&message, repeated_field, 42);
    236   EXPECT_EQ(42, r->GetRepeatedEnumValue(message, repeated_field, 0));
    237   r->SetRepeatedEnumValue(&message, repeated_field, 1, 84);
    238   EXPECT_EQ(84, r->GetRepeatedEnumValue(message, repeated_field, 1));
    239   const google::protobuf::EnumValueDescriptor* enum_value = r->GetEnum(message,
    240                                                              singular_field);
    241   EXPECT_EQ(42, enum_value->number());
    242 }
    243 
    244 // Test that the EnumValue API works properly for proto2 messages as well.
    245 TEST(PreserveUnknownEnumTest, Proto2CatchesUnknownValues) {
    246   protobuf_unittest::TestAllTypes message;  // proto2 message
    247   const google::protobuf::Reflection* r = message.GetReflection();
    248   const google::protobuf::Descriptor* d = message.GetDescriptor();
    249   const google::protobuf::FieldDescriptor* repeated_field =
    250       d->FindFieldByName("repeated_nested_enum");
    251   // Add one element to the repeated field so that we can test
    252   // SetRepeatedEnumValue.
    253   const google::protobuf::EnumValueDescriptor* enum_value =
    254       repeated_field->enum_type()->FindValueByName("BAR");
    255   EXPECT_TRUE(enum_value != NULL);
    256   r->AddEnum(&message, repeated_field, enum_value);
    257 
    258 #ifdef PROTOBUF_HAS_DEATH_TEST
    259   const google::protobuf::FieldDescriptor* singular_field =
    260       d->FindFieldByName("optional_nested_enum");
    261   // Enum-field integer-based setters GOOGLE_DCHECK-fail on invalid values, in order to
    262   // remain consistent with proto2 generated code.
    263   EXPECT_DEBUG_DEATH({
    264     r->SetEnumValue(&message, singular_field, 4242);
    265     r->GetEnum(message, singular_field)->number();
    266   }, "SetEnumValue accepts only valid integer values");
    267   EXPECT_DEBUG_DEATH({
    268     r->SetRepeatedEnumValue(&message, repeated_field, 0, 4242);
    269     r->GetRepeatedEnum(message, repeated_field, 0);
    270   }, "SetRepeatedEnumValue accepts only valid integer values");
    271   EXPECT_DEBUG_DEATH({
    272     r->AddEnumValue(&message, repeated_field, 4242);
    273     r->GetRepeatedEnum(message, repeated_field, 1);
    274   }, "AddEnumValue accepts only valid integer values");
    275 #endif  // PROTOBUF_HAS_DEATH_TEST
    276 }
    277 
    278 TEST(PreserveUnknownEnumTest, SupportsUnknownEnumValuesAPI) {
    279   protobuf_unittest::TestAllTypes proto2_message;
    280   proto3_preserve_unknown_enum_unittest::MyMessage new_message;
    281 
    282   const google::protobuf::Reflection* proto2_reflection = proto2_message.GetReflection();
    283   const google::protobuf::Reflection* new_reflection = new_message.GetReflection();
    284 
    285   EXPECT_FALSE(proto2_reflection->SupportsUnknownEnumValues());
    286   EXPECT_TRUE(new_reflection->SupportsUnknownEnumValues());
    287 }
    288 }  // namespace protobuf
    289 }  // namespace google
    290