Beispiel #1
0
inline string StripPrefixString(const string& str, const string& prefix) {
  if (HasPrefixString(str, prefix)) {
    return str.substr(prefix.size());
  } else {
    return str;
  }
}
TEST(ExtensionSetTest, DynamicExtensions) {
  // Test adding a dynamic extension to a compiled-in message object.

  FileDescriptorProto dynamic_proto;
  dynamic_proto.set_name("dynamic_extensions_test.proto");
  dynamic_proto.add_dependency(
      unittest::TestAllExtensions::descriptor()->file()->name());
  dynamic_proto.set_package("dynamic_extensions");

  // Copy the fields and nested types from TestDynamicExtensions into our new
  // proto, converting the fields into extensions.
  const Descriptor* template_descriptor =
      unittest::TestDynamicExtensions::descriptor();
  DescriptorProto template_descriptor_proto;
  template_descriptor->CopyTo(&template_descriptor_proto);
  dynamic_proto.mutable_message_type()->MergeFrom(
      template_descriptor_proto.nested_type());
  dynamic_proto.mutable_enum_type()->MergeFrom(
      template_descriptor_proto.enum_type());
  dynamic_proto.mutable_extension()->MergeFrom(
      template_descriptor_proto.field());

  // For each extension that we added...
  for (int i = 0; i < dynamic_proto.extension_size(); i++) {
    // Set its extendee to TestAllExtensions.
    FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i);
    extension->set_extendee(
        unittest::TestAllExtensions::descriptor()->full_name());

    // If the field refers to one of the types nested in TestDynamicExtensions,
    // make it refer to the type in our dynamic proto instead.
    string prefix = "." + template_descriptor->full_name() + ".";
    if (extension->has_type_name()) {
      string* type_name = extension->mutable_type_name();
      if (HasPrefixString(*type_name, prefix)) {
        type_name->replace(0, prefix.size(), ".dynamic_extensions.");
      }
    }
  }

  // Now build the file, using the generated pool as an underlay.
  DescriptorPool dynamic_pool(DescriptorPool::generated_pool());
  const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto);
  ASSERT_TRUE(file != NULL);
  DynamicMessageFactory dynamic_factory(&dynamic_pool);
  dynamic_factory.SetDelegateToGeneratedFactory(true);

  // Construct a message that we can parse with the extensions we defined.
  // Since the extensions were based off of the fields of TestDynamicExtensions,
  // we can use that message to create this test message.
  string data;
  {
    unittest::TestDynamicExtensions message;
    message.set_scalar_extension(123);
    message.set_enum_extension(unittest::FOREIGN_BAR);
    message.set_dynamic_enum_extension(
        unittest::TestDynamicExtensions::DYNAMIC_BAZ);
    message.mutable_message_extension()->set_c(456);
    message.mutable_dynamic_message_extension()->set_dynamic_field(789);
    message.add_repeated_extension("foo");
    message.add_repeated_extension("bar");
    message.add_packed_extension(12);
    message.add_packed_extension(-34);
    message.add_packed_extension(56);
    message.add_packed_extension(-78);

    // Also add some unknown fields.

    // An unknown enum value (for a known field).
    message.mutable_unknown_fields()->AddVarint(
      unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber,
      12345);
    // A regular unknown field.
    message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown");

    message.SerializeToString(&data);
  }

  // Now we can parse this using our dynamic extension definitions...
  unittest::TestAllExtensions message;
  {
    io::ArrayInputStream raw_input(data.data(), data.size());
    io::CodedInputStream input(&raw_input);
    input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
    ASSERT_TRUE(message.ParseFromCodedStream(&input));
    ASSERT_TRUE(input.ConsumedEntireMessage());
  }

  // Can we print it?
  EXPECT_EQ(
    "[dynamic_extensions.scalar_extension]: 123\n"
    "[dynamic_extensions.enum_extension]: FOREIGN_BAR\n"
    "[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n"
    "[dynamic_extensions.message_extension] {\n"
    "  c: 456\n"
    "}\n"
    "[dynamic_extensions.dynamic_message_extension] {\n"
    "  dynamic_field: 789\n"
    "}\n"
    "[dynamic_extensions.repeated_extension]: \"foo\"\n"
    "[dynamic_extensions.repeated_extension]: \"bar\"\n"
    "[dynamic_extensions.packed_extension]: 12\n"
    "[dynamic_extensions.packed_extension]: -34\n"
    "[dynamic_extensions.packed_extension]: 56\n"
    "[dynamic_extensions.packed_extension]: -78\n"
    "2002: 12345\n"
    "54321: \"unknown\"\n",
    message.DebugString());

  // Can we serialize it?
  // (Don't use EXPECT_EQ because we don't want to dump raw binary data to the
  // terminal on failure.)
  EXPECT_TRUE(message.SerializeAsString() == data);

  // What if we parse using the reflection-based parser?
  {
    unittest::TestAllExtensions message2;
    io::ArrayInputStream raw_input(data.data(), data.size());
    io::CodedInputStream input(&raw_input);
    input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
    ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2));
    ASSERT_TRUE(input.ConsumedEntireMessage());
    EXPECT_EQ(message.DebugString(), message2.DebugString());
  }

  // Are the embedded generated types actually using the generated objects?
  {
    const FieldDescriptor* message_extension =
        file->FindExtensionByName("message_extension");
    ASSERT_TRUE(message_extension != NULL);
    const Message& sub_message =
        message.GetReflection()->GetMessage(message, message_extension);
    const unittest::ForeignMessage* typed_sub_message =
        dynamic_cast<const unittest::ForeignMessage*>(&sub_message);
    ASSERT_TRUE(typed_sub_message != NULL);
    EXPECT_EQ(456, typed_sub_message->c());
  }

  // What does GetMessage() return for the embedded dynamic type if it isn't
  // present?
  {
    const FieldDescriptor* dynamic_message_extension =
        file->FindExtensionByName("dynamic_message_extension");
    ASSERT_TRUE(dynamic_message_extension != NULL);
    const Message& parent = unittest::TestAllExtensions::default_instance();
    const Message& sub_message =
        parent.GetReflection()->GetMessage(parent, dynamic_message_extension,
                                           &dynamic_factory);
    const Message* prototype =
        dynamic_factory.GetPrototype(dynamic_message_extension->message_type());
    EXPECT_EQ(prototype, &sub_message);
  }
}