diff options
Diffstat (limited to 'src/google/protobuf/generated_message_reflection_unittest.cc')
-rw-r--r-- | src/google/protobuf/generated_message_reflection_unittest.cc | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc new file mode 100644 index 00000000..bde7fac7 --- /dev/null +++ b/src/google/protobuf/generated_message_reflection_unittest.cc @@ -0,0 +1,251 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. +// http://code.google.com/p/protobuf/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// To test GeneratedMessageReflection, we actually let the protocol compiler +// generate a full protocol message implementation and then test its +// reflection interface. This is much easier and more maintainable than +// trying to create our own Message class for GeneratedMessageReflection +// to wrap. +// +// The tests here closely mirror some of the tests in +// compiler/cpp/unittest, except using the reflection interface +// rather than generated accessors. + +#include <google/protobuf/generated_message_reflection.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/test_util.h> +#include <google/protobuf/unittest.pb.h> + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { + +namespace { + +// Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes. +const FieldDescriptor* F(const string& name) { + const FieldDescriptor* result = + unittest::TestAllTypes::descriptor()->FindFieldByName(name); + GOOGLE_CHECK(result != NULL); + return result; +} + +TEST(GeneratedMessageReflectionTest, Defaults) { + // Check that all default values are set correctly in the initial message. + unittest::TestAllTypes message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllTypes::descriptor()); + + reflection_tester.ExpectClearViaReflection(*message.GetReflection()); + + const Message::Reflection& reflection = *message.GetReflection(); + + // Messages should return pointers to default instances until first use. + // (This is not checked by ExpectClear() since it is not actually true after + // the fields have been set and then cleared.) + EXPECT_EQ(&unittest::TestAllTypes::OptionalGroup::default_instance(), + &reflection.GetMessage(F("optionalgroup"))); + EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(), + &reflection.GetMessage(F("optional_nested_message"))); + EXPECT_EQ(&unittest::ForeignMessage::default_instance(), + &reflection.GetMessage(F("optional_foreign_message"))); + EXPECT_EQ(&unittest_import::ImportMessage::default_instance(), + &reflection.GetMessage(F("optional_import_message"))); +} + +TEST(GeneratedMessageReflectionTest, Accessors) { + // Set every field to a unique value then go back and check all those + // values. + unittest::TestAllTypes message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllTypes::descriptor()); + + reflection_tester.SetAllFieldsViaReflection(message.GetReflection()); + TestUtil::ExpectAllFieldsSet(message); + reflection_tester.ExpectAllFieldsSetViaReflection(*message.GetReflection()); + + reflection_tester.ModifyRepeatedFieldsViaReflection(message.GetReflection()); + TestUtil::ExpectRepeatedFieldsModified(message); +} + +TEST(GeneratedMessageReflectionTest, GetStringReference) { + // Test that GetStringReference() returns the underlying string when it is + // a normal string field. + unittest::TestAllTypes message; + message.set_optional_string("foo"); + message.add_repeated_string("foo"); + + const Message::Reflection& reflection = *message.GetReflection(); + string scratch; + + EXPECT_EQ(&message.optional_string(), + &reflection.GetStringReference(F("optional_string"), &scratch)) + << "For simple string fields, GetStringReference() should return a " + "reference to the underlying string."; + EXPECT_EQ(&message.repeated_string(0), + &reflection.GetRepeatedStringReference(F("repeated_string"), 0, &scratch)) + << "For simple string fields, GetRepeatedStringReference() should return " + "a reference to the underlying string."; +} + + +TEST(GeneratedMessageReflectionTest, DefaultsAfterClear) { + // Check that after setting all fields and then clearing, getting an + // embedded message does NOT return the default instance. + unittest::TestAllTypes message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllTypes::descriptor()); + + TestUtil::SetAllFields(&message); + message.Clear(); + + const Message::Reflection& reflection = *message.GetReflection(); + + EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(), + &reflection.GetMessage(F("optionalgroup"))); + EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(), + &reflection.GetMessage(F("optional_nested_message"))); + EXPECT_NE(&unittest::ForeignMessage::default_instance(), + &reflection.GetMessage(F("optional_foreign_message"))); + EXPECT_NE(&unittest_import::ImportMessage::default_instance(), + &reflection.GetMessage(F("optional_import_message"))); +} + +TEST(GeneratedMessageReflectionTest, Extensions) { + // Set every extension to a unique value then go back and check all those + // values. + unittest::TestAllExtensions message; + TestUtil::ReflectionTester reflection_tester( + unittest::TestAllExtensions::descriptor()); + + reflection_tester.SetAllFieldsViaReflection(message.GetReflection()); + TestUtil::ExpectAllExtensionsSet(message); + reflection_tester.ExpectAllFieldsSetViaReflection(*message.GetReflection()); + + reflection_tester.ModifyRepeatedFieldsViaReflection(message.GetReflection()); + TestUtil::ExpectRepeatedExtensionsModified(message); +} + +TEST(GeneratedMessageReflectionTest, FindExtensionTypeByNumber) { + const Message::Reflection& reflection = + *unittest::TestAllExtensions::default_instance().GetReflection(); + + const FieldDescriptor* extension1 = + unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName( + "optional_int32_extension"); + const FieldDescriptor* extension2 = + unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName( + "repeated_string_extension"); + + EXPECT_EQ(extension1, + reflection.FindKnownExtensionByNumber(extension1->number())); + EXPECT_EQ(extension2, + reflection.FindKnownExtensionByNumber(extension2->number())); + + // Non-existent extension. + EXPECT_TRUE(reflection.FindKnownExtensionByNumber(62341) == NULL); + + // Extensions of TestAllExtensions should not show up as extensions of + // other types. + EXPECT_TRUE(unittest::TestAllTypes::default_instance().GetReflection()-> + FindKnownExtensionByNumber(extension1->number()) == NULL); +} + +TEST(GeneratedMessageReflectionTest, FindKnownExtensionByName) { + const Message::Reflection& reflection = + *unittest::TestAllExtensions::default_instance().GetReflection(); + + const FieldDescriptor* extension1 = + unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName( + "optional_int32_extension"); + const FieldDescriptor* extension2 = + unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName( + "repeated_string_extension"); + + EXPECT_EQ(extension1, + reflection.FindKnownExtensionByName(extension1->full_name())); + EXPECT_EQ(extension2, + reflection.FindKnownExtensionByName(extension2->full_name())); + + // Non-existent extension. + EXPECT_TRUE(reflection.FindKnownExtensionByName("no_such_ext") == NULL); + + // Extensions of TestAllExtensions should not show up as extensions of + // other types. + EXPECT_TRUE(unittest::TestAllTypes::default_instance().GetReflection()-> + FindKnownExtensionByName(extension1->full_name()) == NULL); +} + +#ifdef GTEST_HAS_DEATH_TEST + +TEST(GeneratedMessageReflectionTest, UsageErrors) { + unittest::TestAllTypes message; + Message::Reflection* reflection = message.GetReflection(); + const Descriptor* descriptor = message.GetDescriptor(); + +#define f(NAME) descriptor->FindFieldByName(NAME) + + // Testing every single failure mode would be too much work. Let's just + // check a few. + EXPECT_DEATH( + reflection->GetInt32(descriptor->FindFieldByName("optional_int64")), + "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Message::Reflection::GetInt32\n" + " Message type: protobuf_unittest\\.TestAllTypes\n" + " Field : protobuf_unittest\\.TestAllTypes\\.optional_int64\n" + " Problem : Field is not the right type for this message:\n" + " Expected : CPPTYPE_INT32\n" + " Field type: CPPTYPE_INT64"); + EXPECT_DEATH( + reflection->GetInt32(descriptor->FindFieldByName("repeated_int32")), + "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Message::Reflection::GetInt32\n" + " Message type: protobuf_unittest.TestAllTypes\n" + " Field : protobuf_unittest.TestAllTypes.repeated_int32\n" + " Problem : Field is repeated; the method requires a singular field."); + EXPECT_DEATH( + reflection->GetInt32( + unittest::ForeignMessage::descriptor()->FindFieldByName("c")), + "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Message::Reflection::GetInt32\n" + " Message type: protobuf_unittest.TestAllTypes\n" + " Field : protobuf_unittest.ForeignMessage.c\n" + " Problem : Field does not match message type."); + EXPECT_DEATH( + reflection->HasField( + unittest::ForeignMessage::descriptor()->FindFieldByName("c")), + "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Message::Reflection::HasField\n" + " Message type: protobuf_unittest.TestAllTypes\n" + " Field : protobuf_unittest.ForeignMessage.c\n" + " Problem : Field does not match message type."); + +#undef f +} + +#endif // GTEST_HAS_DEATH_TEST + + +} // namespace +} // namespace protobuf +} // namespace google |