Implement AbslStringify for the Descriptor family of types.

Implementing this method allows descriptors to be used in contexts that support
ABSL's formatting, most notably gunit's PrintToString and absl's StrFormat. The
implementations are done on the concrete descriptor type, which appears to be more
idiomatic for AbslStringify. Implementing them on pointers-to-descriptors would be
nicer for users who typically interact with pointers, but that would conflict with
AbslStringify's built-in support for pointers.

The implementation simply forwards to DebugString for simplicity.

PiperOrigin-RevId: 558854354
pull/13622/head
pizzud 1 year ago committed by Copybara-Service
parent a2b347087e
commit 230232a041
  1. 49
      src/google/protobuf/descriptor.h
  2. 29
      src/google/protobuf/descriptor_unittest.cc

@ -69,6 +69,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
@ -347,6 +348,12 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase {
// include original user comments in output).
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const Descriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Returns true if this is a placeholder for an unknown type. This will
// only be the case if this descriptor comes from a DescriptorPool
// with AllowUnknownDependencies() set.
@ -981,6 +988,12 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase {
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const FieldDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Helper method to get the CppType for a particular Type.
static CppType TypeToCppType(Type type);
@ -1186,6 +1199,12 @@ class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase {
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const OneofDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Source Location ---------------------------------------------------
// Updates |*out_location| to the source location of the complete
@ -1307,6 +1326,12 @@ class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase {
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const EnumDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Returns true if this is a placeholder for an unknown enum. This will
// only be the case if this descriptor comes from a DescriptorPool
// with AllowUnknownDependencies() set.
@ -1500,6 +1525,12 @@ class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>,
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const EnumValueDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Source Location ---------------------------------------------------
// Updates |*out_location| to the source location of the complete
@ -1597,6 +1628,12 @@ class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase {
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const ServiceDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Source Location ---------------------------------------------------
// Updates |*out_location| to the source location of the complete
@ -1698,6 +1735,12 @@ class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase {
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const MethodDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Source Location ---------------------------------------------------
// Updates |*out_location| to the source location of the complete
@ -1913,6 +1956,12 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase {
// See Descriptor::DebugStringWithOptions().
std::string DebugStringWithOptions(const DebugStringOptions& options) const;
// Allows formatting with absl and gtest.
template <typename Sink>
friend void AbslStringify(Sink& sink, const FileDescriptor& d) {
absl::Format(&sink, "%s", d.DebugString());
}
// Returns true if this is a placeholder for an unknown file. This will
// only be the case if this descriptor comes from a DescriptorPool
// with AllowUnknownDependencies() set.

@ -39,6 +39,7 @@
#include <cstdlib>
#include <limits>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
@ -83,6 +84,7 @@
using ::testing::AnyOf;
using ::testing::ElementsAre;
using ::testing::HasSubstr;
using ::testing::NotNull;
namespace google {
@ -614,6 +616,13 @@ TEST_F(FileDescriptorTest, DebugStringRoundTrip) {
}
}
TEST_F(FileDescriptorTest, AbslStringifyWorks) {
std::string s = absl::StrFormat(
"%v",
*protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file());
EXPECT_THAT(s, HasSubstr("TestMessageWithCustomOptions"));
}
// ===================================================================
// Test simple flat messages and fields.
@ -1209,6 +1218,12 @@ TEST_F(DescriptorTest, FieldEnumType) {
EXPECT_EQ(enum_, bar_->enum_type());
}
TEST_F(DescriptorTest, AbslStringifyWorks) {
EXPECT_THAT(absl::StrFormat("%v", *message_),
HasSubstr(message_->full_name()));
EXPECT_THAT(absl::StrFormat("%v", *foo_), HasSubstr(foo_->name()));
}
// ===================================================================
@ -1302,6 +1317,10 @@ TEST_F(OneofDescriptorTest, FindByName) {
EXPECT_TRUE(oneof_message_->FindOneofByName("no_such_oneof") == nullptr);
}
TEST_F(OneofDescriptorTest, AbslStringifyWorks) {
EXPECT_THAT(absl::StrFormat("%v", *oneof_), HasSubstr(oneof_->name()));
}
// ===================================================================
class StylizedFieldNamesTest : public testing::Test {
@ -1650,6 +1669,11 @@ TEST_F(EnumDescriptorTest, IsClosed) {
EXPECT_FALSE(enum3->is_closed());
}
TEST_F(EnumDescriptorTest, AbslStringifyWorks) {
EXPECT_THAT(absl::StrFormat("%v", *enum_), HasSubstr(enum_->full_name()));
EXPECT_THAT(absl::StrFormat("%v", *foo_), HasSubstr(foo_->name()));
}
// ===================================================================
// Test service descriptors.
@ -1810,6 +1834,11 @@ TEST_F(ServiceDescriptorTest, MethodOutputType) {
EXPECT_EQ(bar_response_, bar_->output_type());
}
TEST_F(ServiceDescriptorTest, AbslStringifyWorks) {
EXPECT_THAT(absl::StrFormat("%v", *service_), HasSubstr(service_->name()));
EXPECT_THAT(absl::StrFormat("%v", *foo_), HasSubstr(foo_->name()));
}
// ===================================================================
// Test nested types.

Loading…
Cancel
Save