Brian Silverman | 9c614bc | 2016-02-15 20:20:02 -0500 | [diff] [blame^] | 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 | // Author: kenton@google.com (Kenton Varda) |
| 32 | // Based on original Protocol Buffers design by |
| 33 | // Sanjay Ghemawat, Jeff Dean, and others. |
| 34 | // |
| 35 | // Since the reflection interface for DynamicMessage is implemented by |
| 36 | // GenericMessageReflection, the only thing we really have to test is |
| 37 | // that DynamicMessage correctly sets up the information that |
| 38 | // GenericMessageReflection needs to use. So, we focus on that in this |
| 39 | // test. Other tests, such as generic_message_reflection_unittest and |
| 40 | // reflection_ops_unittest, cover the rest of the functionality used by |
| 41 | // DynamicMessage. |
| 42 | |
| 43 | #include <memory> |
| 44 | #ifndef _SHARED_PTR_H |
| 45 | #include <google/protobuf/stubs/shared_ptr.h> |
| 46 | #endif |
| 47 | |
| 48 | #include <google/protobuf/stubs/scoped_ptr.h> |
| 49 | #include <google/protobuf/stubs/common.h> |
| 50 | #include <google/protobuf/dynamic_message.h> |
| 51 | #include <google/protobuf/descriptor.h> |
| 52 | #include <google/protobuf/descriptor.pb.h> |
| 53 | #include <google/protobuf/test_util.h> |
| 54 | #include <google/protobuf/unittest.pb.h> |
| 55 | #include <google/protobuf/unittest_no_field_presence.pb.h> |
| 56 | |
| 57 | #include <google/protobuf/stubs/logging.h> |
| 58 | #include <google/protobuf/testing/googletest.h> |
| 59 | #include <gtest/gtest.h> |
| 60 | |
| 61 | namespace google { |
| 62 | namespace protobuf { |
| 63 | |
| 64 | class DynamicMessageTest : public testing::Test { |
| 65 | protected: |
| 66 | DescriptorPool pool_; |
| 67 | DynamicMessageFactory factory_; |
| 68 | const Descriptor* descriptor_; |
| 69 | const Message* prototype_; |
| 70 | const Descriptor* extensions_descriptor_; |
| 71 | const Message* extensions_prototype_; |
| 72 | const Descriptor* packed_descriptor_; |
| 73 | const Message* packed_prototype_; |
| 74 | const Descriptor* oneof_descriptor_; |
| 75 | const Message* oneof_prototype_; |
| 76 | const Descriptor* proto3_descriptor_; |
| 77 | const Message* proto3_prototype_; |
| 78 | |
| 79 | DynamicMessageTest(): factory_(&pool_) {} |
| 80 | |
| 81 | virtual void SetUp() { |
| 82 | // We want to make sure that DynamicMessage works (particularly with |
| 83 | // extensions) even if we use descriptors that are *not* from compiled-in |
| 84 | // types, so we make copies of the descriptors for unittest.proto and |
| 85 | // unittest_import.proto. |
| 86 | FileDescriptorProto unittest_file; |
| 87 | FileDescriptorProto unittest_import_file; |
| 88 | FileDescriptorProto unittest_import_public_file; |
| 89 | FileDescriptorProto unittest_no_field_presence_file; |
| 90 | |
| 91 | unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file); |
| 92 | unittest_import::ImportMessage::descriptor()->file()->CopyTo( |
| 93 | &unittest_import_file); |
| 94 | unittest_import::PublicImportMessage::descriptor()->file()->CopyTo( |
| 95 | &unittest_import_public_file); |
| 96 | proto2_nofieldpresence_unittest::TestAllTypes::descriptor()-> |
| 97 | file()->CopyTo(&unittest_no_field_presence_file); |
| 98 | |
| 99 | ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != NULL); |
| 100 | ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL); |
| 101 | ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL); |
| 102 | ASSERT_TRUE(pool_.BuildFile(unittest_no_field_presence_file) != NULL); |
| 103 | |
| 104 | descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes"); |
| 105 | ASSERT_TRUE(descriptor_ != NULL); |
| 106 | prototype_ = factory_.GetPrototype(descriptor_); |
| 107 | |
| 108 | extensions_descriptor_ = |
| 109 | pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions"); |
| 110 | ASSERT_TRUE(extensions_descriptor_ != NULL); |
| 111 | extensions_prototype_ = factory_.GetPrototype(extensions_descriptor_); |
| 112 | |
| 113 | packed_descriptor_ = |
| 114 | pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes"); |
| 115 | ASSERT_TRUE(packed_descriptor_ != NULL); |
| 116 | packed_prototype_ = factory_.GetPrototype(packed_descriptor_); |
| 117 | |
| 118 | oneof_descriptor_ = |
| 119 | pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2"); |
| 120 | ASSERT_TRUE(oneof_descriptor_ != NULL); |
| 121 | oneof_prototype_ = factory_.GetPrototype(oneof_descriptor_); |
| 122 | |
| 123 | proto3_descriptor_ = |
| 124 | pool_.FindMessageTypeByName( |
| 125 | "proto2_nofieldpresence_unittest.TestAllTypes"); |
| 126 | ASSERT_TRUE(proto3_descriptor_ != NULL); |
| 127 | proto3_prototype_ = factory_.GetPrototype(proto3_descriptor_); |
| 128 | } |
| 129 | }; |
| 130 | |
| 131 | TEST_F(DynamicMessageTest, Descriptor) { |
| 132 | // Check that the descriptor on the DynamicMessage matches the descriptor |
| 133 | // passed to GetPrototype(). |
| 134 | EXPECT_EQ(prototype_->GetDescriptor(), descriptor_); |
| 135 | } |
| 136 | |
| 137 | TEST_F(DynamicMessageTest, OnePrototype) { |
| 138 | // Check that requesting the same prototype twice produces the same object. |
| 139 | EXPECT_EQ(prototype_, factory_.GetPrototype(descriptor_)); |
| 140 | } |
| 141 | |
| 142 | TEST_F(DynamicMessageTest, Defaults) { |
| 143 | // Check that all default values are set correctly in the initial message. |
| 144 | TestUtil::ReflectionTester reflection_tester(descriptor_); |
| 145 | reflection_tester.ExpectClearViaReflection(*prototype_); |
| 146 | } |
| 147 | |
| 148 | TEST_F(DynamicMessageTest, IndependentOffsets) { |
| 149 | // Check that all fields have independent offsets by setting each |
| 150 | // one to a unique value then checking that they all still have those |
| 151 | // unique values (i.e. they don't stomp each other). |
| 152 | google::protobuf::scoped_ptr<Message> message(prototype_->New()); |
| 153 | TestUtil::ReflectionTester reflection_tester(descriptor_); |
| 154 | |
| 155 | reflection_tester.SetAllFieldsViaReflection(message.get()); |
| 156 | reflection_tester.ExpectAllFieldsSetViaReflection(*message); |
| 157 | } |
| 158 | |
| 159 | TEST_F(DynamicMessageTest, Extensions) { |
| 160 | // Check that extensions work. |
| 161 | google::protobuf::scoped_ptr<Message> message(extensions_prototype_->New()); |
| 162 | TestUtil::ReflectionTester reflection_tester(extensions_descriptor_); |
| 163 | |
| 164 | reflection_tester.SetAllFieldsViaReflection(message.get()); |
| 165 | reflection_tester.ExpectAllFieldsSetViaReflection(*message); |
| 166 | } |
| 167 | |
| 168 | TEST_F(DynamicMessageTest, PackedFields) { |
| 169 | // Check that packed fields work properly. |
| 170 | google::protobuf::scoped_ptr<Message> message(packed_prototype_->New()); |
| 171 | TestUtil::ReflectionTester reflection_tester(packed_descriptor_); |
| 172 | |
| 173 | reflection_tester.SetPackedFieldsViaReflection(message.get()); |
| 174 | reflection_tester.ExpectPackedFieldsSetViaReflection(*message); |
| 175 | } |
| 176 | |
| 177 | TEST_F(DynamicMessageTest, Oneof) { |
| 178 | // Check that oneof fields work properly. |
| 179 | google::protobuf::scoped_ptr<Message> message(oneof_prototype_->New()); |
| 180 | |
| 181 | // Check default values. |
| 182 | const Descriptor* descriptor = message->GetDescriptor(); |
| 183 | const Reflection* reflection = message->GetReflection(); |
| 184 | EXPECT_EQ(0, reflection->GetInt32( |
| 185 | *message, descriptor->FindFieldByName("foo_int"))); |
| 186 | EXPECT_EQ("", reflection->GetString( |
| 187 | *message, descriptor->FindFieldByName("foo_string"))); |
| 188 | EXPECT_EQ("", reflection->GetString( |
| 189 | *message, descriptor->FindFieldByName("foo_cord"))); |
| 190 | EXPECT_EQ("", reflection->GetString( |
| 191 | *message, descriptor->FindFieldByName("foo_string_piece"))); |
| 192 | EXPECT_EQ("", reflection->GetString( |
| 193 | *message, descriptor->FindFieldByName("foo_bytes"))); |
| 194 | EXPECT_EQ(unittest::TestOneof2::FOO, reflection->GetEnum( |
| 195 | *message, descriptor->FindFieldByName("foo_enum"))->number()); |
| 196 | const Descriptor* nested_descriptor; |
| 197 | const Message* nested_prototype; |
| 198 | nested_descriptor = |
| 199 | pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2.NestedMessage"); |
| 200 | nested_prototype = factory_.GetPrototype(nested_descriptor); |
| 201 | EXPECT_EQ(nested_prototype, |
| 202 | &reflection->GetMessage( |
| 203 | *message, descriptor->FindFieldByName("foo_message"))); |
| 204 | const Descriptor* foogroup_descriptor; |
| 205 | const Message* foogroup_prototype; |
| 206 | foogroup_descriptor = |
| 207 | pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2.FooGroup"); |
| 208 | foogroup_prototype = factory_.GetPrototype(foogroup_descriptor); |
| 209 | EXPECT_EQ(foogroup_prototype, |
| 210 | &reflection->GetMessage( |
| 211 | *message, descriptor->FindFieldByName("foogroup"))); |
| 212 | EXPECT_NE(foogroup_prototype, |
| 213 | &reflection->GetMessage( |
| 214 | *message, descriptor->FindFieldByName("foo_lazy_message"))); |
| 215 | EXPECT_EQ(5, reflection->GetInt32( |
| 216 | *message, descriptor->FindFieldByName("bar_int"))); |
| 217 | EXPECT_EQ("STRING", reflection->GetString( |
| 218 | *message, descriptor->FindFieldByName("bar_string"))); |
| 219 | EXPECT_EQ("CORD", reflection->GetString( |
| 220 | *message, descriptor->FindFieldByName("bar_cord"))); |
| 221 | EXPECT_EQ("SPIECE", reflection->GetString( |
| 222 | *message, descriptor->FindFieldByName("bar_string_piece"))); |
| 223 | EXPECT_EQ("BYTES", reflection->GetString( |
| 224 | *message, descriptor->FindFieldByName("bar_bytes"))); |
| 225 | EXPECT_EQ(unittest::TestOneof2::BAR, reflection->GetEnum( |
| 226 | *message, descriptor->FindFieldByName("bar_enum"))->number()); |
| 227 | |
| 228 | // Check set functions. |
| 229 | TestUtil::ReflectionTester reflection_tester(oneof_descriptor_); |
| 230 | reflection_tester.SetOneofViaReflection(message.get()); |
| 231 | reflection_tester.ExpectOneofSetViaReflection(*message); |
| 232 | } |
| 233 | |
| 234 | TEST_F(DynamicMessageTest, SpaceUsed) { |
| 235 | // Test that SpaceUsed() works properly |
| 236 | |
| 237 | // Since we share the implementation with generated messages, we don't need |
| 238 | // to test very much here. Just make sure it appears to be working. |
| 239 | |
| 240 | google::protobuf::scoped_ptr<Message> message(prototype_->New()); |
| 241 | TestUtil::ReflectionTester reflection_tester(descriptor_); |
| 242 | |
| 243 | int initial_space_used = message->SpaceUsed(); |
| 244 | |
| 245 | reflection_tester.SetAllFieldsViaReflection(message.get()); |
| 246 | EXPECT_LT(initial_space_used, message->SpaceUsed()); |
| 247 | } |
| 248 | |
| 249 | TEST_F(DynamicMessageTest, Arena) { |
| 250 | Arena arena; |
| 251 | Message* message = prototype_->New(&arena); |
| 252 | (void)message; // avoid unused-variable error. |
| 253 | // Return without freeing: should not leak. |
| 254 | } |
| 255 | |
| 256 | TEST_F(DynamicMessageTest, Proto3) { |
| 257 | Message* message = proto3_prototype_->New(); |
| 258 | const Reflection* refl = message->GetReflection(); |
| 259 | const Descriptor* desc = message->GetDescriptor(); |
| 260 | |
| 261 | // Just test a single primtive and single message field here to make sure we |
| 262 | // are getting the no-field-presence semantics elsewhere. DynamicMessage uses |
| 263 | // GeneratedMessageReflection under the hood, so the rest should be fine as |
| 264 | // long as GMR recognizes that we're using a proto3 message. |
| 265 | const FieldDescriptor* optional_int32 = |
| 266 | desc->FindFieldByName("optional_int32"); |
| 267 | const FieldDescriptor* optional_msg = |
| 268 | desc->FindFieldByName("optional_nested_message"); |
| 269 | EXPECT_TRUE(optional_int32 != NULL); |
| 270 | EXPECT_TRUE(optional_msg != NULL); |
| 271 | |
| 272 | EXPECT_EQ(false, refl->HasField(*message, optional_int32)); |
| 273 | refl->SetInt32(message, optional_int32, 42); |
| 274 | EXPECT_EQ(true, refl->HasField(*message, optional_int32)); |
| 275 | refl->SetInt32(message, optional_int32, 0); |
| 276 | EXPECT_EQ(false, refl->HasField(*message, optional_int32)); |
| 277 | |
| 278 | EXPECT_EQ(false, refl->HasField(*message, optional_msg)); |
| 279 | refl->MutableMessage(message, optional_msg); |
| 280 | EXPECT_EQ(true, refl->HasField(*message, optional_msg)); |
| 281 | delete refl->ReleaseMessage(message, optional_msg); |
| 282 | EXPECT_EQ(false, refl->HasField(*message, optional_msg)); |
| 283 | |
| 284 | // Also ensure that the default instance handles field presence properly. |
| 285 | EXPECT_EQ(false, refl->HasField(*proto3_prototype_, optional_msg)); |
| 286 | |
| 287 | delete message; |
| 288 | } |
| 289 | |
| 290 | |
| 291 | } // namespace protobuf |
| 292 | } // namespace google |