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