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/util/type_resolver_util.h> 32 33 #include <limits> 34 #include <memory> 35 #ifndef _SHARED_PTR_H 36 #include <google/protobuf/stubs/shared_ptr.h> 37 #endif 38 #include <string> 39 #include <vector> 40 41 #include <google/protobuf/type.pb.h> 42 #include <google/protobuf/wrappers.pb.h> 43 #include <google/protobuf/map_unittest.pb.h> 44 #include <google/protobuf/test_util.h> 45 #include <google/protobuf/unittest.pb.h> 46 #include <google/protobuf/util/json_format_proto3.pb.h> 47 #include <google/protobuf/util/type_resolver.h> 48 #include <google/protobuf/testing/googletest.h> 49 #include <gtest/gtest.h> 50 51 namespace google { 52 namespace protobuf { 53 namespace util { 54 namespace { 55 using google::protobuf::Type; 56 using google::protobuf::Enum; 57 using google::protobuf::Field; 58 using google::protobuf::Option; 59 using google::protobuf::BoolValue; 60 61 static const char kUrlPrefix[] = "type.googleapis.com"; 62 63 class DescriptorPoolTypeResolverTest : public testing::Test { 64 public: 65 DescriptorPoolTypeResolverTest() { 66 resolver_.reset(NewTypeResolverForDescriptorPool( 67 kUrlPrefix, DescriptorPool::generated_pool())); 68 } 69 70 const Field* FindField(const Type& type, const string& name) { 71 for (int i = 0; i < type.fields_size(); ++i) { 72 const Field& field = type.fields(i); 73 if (field.name() == name) { 74 return &field; 75 } 76 } 77 return NULL; 78 } 79 80 bool HasField(const Type& type, const string& name) { 81 return FindField(type, name) != NULL; 82 } 83 84 bool HasField(const Type& type, Field::Cardinality cardinality, 85 Field::Kind kind, const string& name, int number) { 86 const Field* field = FindField(type, name); 87 if (field == NULL) { 88 return false; 89 } 90 return field->cardinality() == cardinality && 91 field->kind() == kind && field->number() == number; 92 } 93 94 bool CheckFieldTypeUrl(const Type& type, const string& name, 95 const string& type_url) { 96 const Field* field = FindField(type, name); 97 if (field == NULL) { 98 return false; 99 } 100 return field->type_url() == type_url; 101 } 102 103 bool FieldInOneof(const Type& type, const string& name, 104 const string& oneof_name) { 105 const Field* field = FindField(type, name); 106 if (field == NULL || field->oneof_index() <= 0 || 107 field->oneof_index() > type.oneofs_size()) { 108 return false; 109 } 110 return type.oneofs(field->oneof_index() - 1) == oneof_name; 111 } 112 113 bool IsPacked(const Type& type, const string& name) { 114 const Field* field = FindField(type, name); 115 if (field == NULL) { 116 return false; 117 } 118 return field->packed(); 119 } 120 121 bool EnumHasValue(const Enum& type, const string& name, int number) { 122 for (int i = 0; i < type.enumvalue_size(); ++i) { 123 if (type.enumvalue(i).name() == name && 124 type.enumvalue(i).number() == number) { 125 return true; 126 } 127 } 128 return false; 129 } 130 131 bool HasBoolOption(const RepeatedPtrField<Option>& options, 132 const string& name, bool value) { 133 for (int i = 0; i < options.size(); ++i) { 134 const Option& option = options.Get(i); 135 if (option.name() == name) { 136 BoolValue bool_value; 137 if (option.value().UnpackTo(&bool_value) && 138 bool_value.value() == value) { 139 return true; 140 } 141 } 142 } 143 return false; 144 } 145 146 string GetTypeUrl(string full_name) { 147 return kUrlPrefix + string("/") + full_name; 148 } 149 150 template<typename T> 151 string GetTypeUrl() { 152 return GetTypeUrl(T::descriptor()->full_name()); 153 } 154 155 protected: 156 google::protobuf::scoped_ptr<TypeResolver> resolver_; 157 }; 158 159 TEST_F(DescriptorPoolTypeResolverTest, TestAllTypes) { 160 Type type; 161 ASSERT_TRUE(resolver_->ResolveMessageType( 162 GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type).ok()); 163 // Check all optional fields. 164 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 165 Field::TYPE_INT32, "optional_int32", 1)); 166 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 167 Field::TYPE_INT64, "optional_int64", 2)); 168 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 169 Field::TYPE_UINT32, "optional_uint32", 3)); 170 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 171 Field::TYPE_UINT64, "optional_uint64", 4)); 172 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 173 Field::TYPE_SINT32, "optional_sint32", 5)); 174 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 175 Field::TYPE_SINT64, "optional_sint64", 6)); 176 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 177 Field::TYPE_FIXED32, "optional_fixed32", 7)); 178 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 179 Field::TYPE_FIXED64, "optional_fixed64", 8)); 180 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 181 Field::TYPE_SFIXED32, "optional_sfixed32", 9)); 182 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 183 Field::TYPE_SFIXED64, "optional_sfixed64", 10)); 184 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 185 Field::TYPE_FLOAT, "optional_float", 11)); 186 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 187 Field::TYPE_DOUBLE, "optional_double", 12)); 188 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 189 Field::TYPE_BOOL, "optional_bool", 13)); 190 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 191 Field::TYPE_STRING, "optional_string", 14)); 192 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 193 Field::TYPE_BYTES, "optional_bytes", 15)); 194 195 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 196 Field::TYPE_MESSAGE, "optional_nested_message", 18)); 197 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 198 Field::TYPE_MESSAGE, "optional_foreign_message", 19)); 199 200 EXPECT_TRUE(CheckFieldTypeUrl( 201 type, "optional_nested_message", 202 GetTypeUrl<protobuf_unittest::TestAllTypes::NestedMessage>())); 203 EXPECT_TRUE(CheckFieldTypeUrl( 204 type, "optional_foreign_message", 205 GetTypeUrl<protobuf_unittest::ForeignMessage>())); 206 207 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 208 Field::TYPE_ENUM, "optional_nested_enum", 21)); 209 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 210 Field::TYPE_ENUM, "optional_foreign_enum", 22)); 211 212 EXPECT_TRUE(CheckFieldTypeUrl( 213 type, "optional_nested_enum", 214 GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum"))); 215 EXPECT_TRUE(CheckFieldTypeUrl( 216 type, "optional_foreign_enum", 217 GetTypeUrl("protobuf_unittest.ForeignEnum"))); 218 219 // Check all repeated fields. 220 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 221 Field::TYPE_INT32, "repeated_int32", 31)); 222 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 223 Field::TYPE_INT64, "repeated_int64", 32)); 224 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 225 Field::TYPE_UINT32, "repeated_uint32", 33)); 226 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 227 Field::TYPE_UINT64, "repeated_uint64", 34)); 228 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 229 Field::TYPE_SINT32, "repeated_sint32", 35)); 230 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 231 Field::TYPE_SINT64, "repeated_sint64", 36)); 232 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 233 Field::TYPE_FIXED32, "repeated_fixed32", 37)); 234 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 235 Field::TYPE_FIXED64, "repeated_fixed64", 38)); 236 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 237 Field::TYPE_SFIXED32, "repeated_sfixed32", 39)); 238 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 239 Field::TYPE_SFIXED64, "repeated_sfixed64", 40)); 240 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 241 Field::TYPE_FLOAT, "repeated_float", 41)); 242 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 243 Field::TYPE_DOUBLE, "repeated_double", 42)); 244 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 245 Field::TYPE_BOOL, "repeated_bool", 43)); 246 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 247 Field::TYPE_STRING, "repeated_string", 44)); 248 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 249 Field::TYPE_BYTES, "repeated_bytes", 45)); 250 251 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 252 Field::TYPE_MESSAGE, "repeated_nested_message", 48)); 253 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 254 Field::TYPE_MESSAGE, "repeated_foreign_message", 49)); 255 256 EXPECT_TRUE(CheckFieldTypeUrl( 257 type, "repeated_nested_message", 258 GetTypeUrl<protobuf_unittest::TestAllTypes::NestedMessage>())); 259 EXPECT_TRUE(CheckFieldTypeUrl( 260 type, "repeated_foreign_message", 261 GetTypeUrl<protobuf_unittest::ForeignMessage>())); 262 263 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 264 Field::TYPE_ENUM, "repeated_nested_enum", 51)); 265 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 266 Field::TYPE_ENUM, "repeated_foreign_enum", 52)); 267 268 EXPECT_TRUE(CheckFieldTypeUrl( 269 type, "repeated_nested_enum", 270 GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum"))); 271 EXPECT_TRUE(CheckFieldTypeUrl( 272 type, "repeated_foreign_enum", 273 GetTypeUrl("protobuf_unittest.ForeignEnum"))); 274 275 // Groups are discarded when converting to Type. 276 const Descriptor* descriptor = protobuf_unittest::TestAllTypes::descriptor(); 277 EXPECT_TRUE(descriptor->FindFieldByName("optionalgroup") != NULL); 278 EXPECT_TRUE(descriptor->FindFieldByName("repeatedgroup") != NULL); 279 ASSERT_FALSE(HasField(type, "optionalgroup")); 280 ASSERT_FALSE(HasField(type, "repeatedgroup")); 281 } 282 283 TEST_F(DescriptorPoolTypeResolverTest, TestPackedField) { 284 Type type; 285 ASSERT_TRUE(resolver_->ResolveMessageType( 286 GetTypeUrl<protobuf_unittest::TestPackedTypes>(), &type).ok()); 287 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 288 Field::TYPE_INT32, "packed_int32", 90)); 289 EXPECT_TRUE(IsPacked(type, "packed_int32")); 290 } 291 292 TEST_F(DescriptorPoolTypeResolverTest, TestOneof) { 293 Type type; 294 ASSERT_TRUE(resolver_->ResolveMessageType( 295 GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type).ok()); 296 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 297 Field::TYPE_UINT32, "oneof_uint32", 111)); 298 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 299 Field::TYPE_MESSAGE, "oneof_nested_message", 112)); 300 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 301 Field::TYPE_STRING, "oneof_string", 113)); 302 EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, 303 Field::TYPE_BYTES, "oneof_bytes", 114)); 304 EXPECT_TRUE(FieldInOneof(type, "oneof_uint32", "oneof_field")); 305 EXPECT_TRUE(FieldInOneof(type, "oneof_nested_message", "oneof_field")); 306 EXPECT_TRUE(FieldInOneof(type, "oneof_string", "oneof_field")); 307 EXPECT_TRUE(FieldInOneof(type, "oneof_bytes", "oneof_field")); 308 } 309 310 TEST_F(DescriptorPoolTypeResolverTest, TestMap) { 311 Type type; 312 ASSERT_TRUE(resolver_->ResolveMessageType( 313 GetTypeUrl<protobuf_unittest::TestMap>(), &type).ok()); 314 EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, 315 Field::TYPE_MESSAGE, "map_int32_int32", 1)); 316 EXPECT_TRUE(CheckFieldTypeUrl( 317 type, "map_int32_int32", 318 GetTypeUrl("protobuf_unittest.TestMap.MapInt32Int32Entry"))); 319 320 ASSERT_TRUE(resolver_->ResolveMessageType( 321 GetTypeUrl("protobuf_unittest.TestMap.MapInt32Int32Entry"), 322 &type).ok()); 323 EXPECT_TRUE(HasBoolOption(type.options(), "map_entry", true)); 324 } 325 326 TEST_F(DescriptorPoolTypeResolverTest, TestEnum) { 327 Enum type; 328 ASSERT_TRUE(resolver_->ResolveEnumType( 329 GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum"), &type).ok()); 330 EnumHasValue(type, "FOO", 1); 331 EnumHasValue(type, "BAR", 2); 332 EnumHasValue(type, "BAZ", 3); 333 EnumHasValue(type, "NEG", -1); 334 } 335 336 TEST_F(DescriptorPoolTypeResolverTest, TestJsonName) { 337 Type type; 338 ASSERT_TRUE(resolver_->ResolveMessageType( 339 GetTypeUrl<protobuf_unittest::TestAllTypes>(), &type) 340 .ok()); 341 EXPECT_EQ("optionalInt32", FindField(type, "optional_int32")->json_name()); 342 343 ASSERT_TRUE(resolver_->ResolveMessageType( 344 GetTypeUrl<proto3::TestCustomJsonName>(), &type) 345 .ok()); 346 EXPECT_EQ("@value", FindField(type, "value")->json_name()); 347 } 348 349 } // namespace 350 } // namespace util 351 } // namespace protobuf 352 } // namespace google 353