1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "google/protobuf/descriptor_visitor.h"
9
10 #include <string>
11 #include <vector>
12
13 #include <gmock/gmock.h>
14 #include <gtest/gtest.h>
15 #include "absl/strings/string_view.h"
16 #include "google/protobuf/unittest.pb.h"
17
18 namespace google {
19 namespace protobuf {
20 namespace {
21
22 using ::testing::Contains;
23 using ::testing::IsSupersetOf;
24 using ::testing::Not;
25
26 constexpr absl::string_view kUnittestProtoFile =
27 "google/protobuf/unittest.proto";
28
TEST(VisitDescriptorsTest,SingleTypeNoProto)29 TEST(VisitDescriptorsTest, SingleTypeNoProto) {
30 const FileDescriptor& file =
31 *protobuf_unittest::TestAllTypes::GetDescriptor()->file();
32 std::vector<absl::string_view> descriptors;
33 VisitDescriptors(file, [&](const Descriptor& descriptor) {
34 descriptors.push_back(descriptor.full_name());
35 });
36 EXPECT_THAT(descriptors,
37 IsSupersetOf({"protobuf_unittest.TestAllTypes",
38 "protobuf_unittest.TestAllTypes.NestedMessage"}));
39 }
40
TEST(VisitDescriptorsTest,SingleTypeWithProto)41 TEST(VisitDescriptorsTest, SingleTypeWithProto) {
42 const FileDescriptor& file =
43 *protobuf_unittest::TestAllTypes::GetDescriptor()->file();
44 FileDescriptorProto proto;
45 file.CopyTo(&proto);
46 std::vector<absl::string_view> descriptors;
47 VisitDescriptors(
48 file, proto,
49 [&](const Descriptor& descriptor, const DescriptorProto& proto) {
50 descriptors.push_back(descriptor.full_name());
51 EXPECT_EQ(descriptor.name(), proto.name());
52 });
53 EXPECT_THAT(descriptors,
54 IsSupersetOf({"protobuf_unittest.TestAllTypes",
55 "protobuf_unittest.TestAllTypes.NestedMessage"}));
56 }
57
TEST(VisitDescriptorsTest,SingleTypeMutableProto)58 TEST(VisitDescriptorsTest, SingleTypeMutableProto) {
59 const FileDescriptor& file =
60 *protobuf_unittest::TestAllTypes::GetDescriptor()->file();
61 FileDescriptorProto proto;
62 file.CopyTo(&proto);
63 std::vector<absl::string_view> descriptors;
64 VisitDescriptors(file, proto,
65 [&](const Descriptor& descriptor, DescriptorProto& proto) {
66 descriptors.push_back(descriptor.full_name());
67 EXPECT_EQ(descriptor.name(), proto.name());
68 proto.set_name("<redacted>");
69 });
70 EXPECT_THAT(descriptors,
71 IsSupersetOf({"protobuf_unittest.TestAllTypes",
72 "protobuf_unittest.TestAllTypes.NestedMessage"}));
73 EXPECT_EQ(proto.message_type(0).name(), "<redacted>");
74 }
75
TEST(VisitDescriptorsTest,AllTypesDeduce)76 TEST(VisitDescriptorsTest, AllTypesDeduce) {
77 const FileDescriptor& file =
78 *protobuf_unittest::TestAllTypes::GetDescriptor()->file();
79 std::vector<absl::string_view> descriptors;
80 VisitDescriptors(file, [&](const auto& descriptor) {
81 descriptors.push_back(descriptor.name());
82 });
83 EXPECT_THAT(descriptors, Contains(kUnittestProtoFile));
84 EXPECT_THAT(descriptors, IsSupersetOf({"TestAllTypes", "TestSparseEnum",
85 "SPARSE_C", "optional_int32",
86 "oneof_nested_message", "oneof_field",
87 "optional_nested_message_extension"}));
88 }
89
TEST(VisitDescriptorsTest,AllTypesDeduceSelective)90 TEST(VisitDescriptorsTest, AllTypesDeduceSelective) {
91 const FileDescriptor& file =
92 *protobuf_unittest::TestAllTypes::GetDescriptor()->file();
93 std::vector<absl::string_view> descriptors;
94 VisitDescriptors(
95 file,
96 // Only select on descriptors with a full_name method.
97 [&](const auto& descriptor)
98 -> std::enable_if_t<
99 !std::is_void<decltype(descriptor.full_name())>::value> {
100 descriptors.push_back(descriptor.full_name());
101 });
102 // FileDescriptor doesn't have a full_name method.
103 EXPECT_THAT(descriptors, Not(Contains(kUnittestProtoFile)));
104 EXPECT_THAT(descriptors,
105 IsSupersetOf(
106 {"protobuf_unittest.TestAllTypes",
107 "protobuf_unittest.TestSparseEnum", "protobuf_unittest.SPARSE_C",
108 "protobuf_unittest.TestAllTypes.optional_int32",
109 "protobuf_unittest.TestAllTypes.oneof_nested_message",
110 "protobuf_unittest.TestAllTypes.oneof_field",
111 "protobuf_unittest.optional_nested_message_extension"}));
112 }
113
TestHandle(const Descriptor & message,const DescriptorProto & proto,std::vector<absl::string_view> * result)114 void TestHandle(const Descriptor& message, const DescriptorProto& proto,
115 std::vector<absl::string_view>* result) {
116 if (result != nullptr) result->push_back(message.full_name());
117 EXPECT_EQ(message.name(), proto.name());
118 }
TestHandle(const EnumDescriptor & enm,const EnumDescriptorProto & proto,std::vector<absl::string_view> * result)119 void TestHandle(const EnumDescriptor& enm, const EnumDescriptorProto& proto,
120 std::vector<absl::string_view>* result) {
121 if (result != nullptr) result->push_back(enm.full_name());
122 EXPECT_EQ(enm.name(), proto.name());
123 }
TEST(VisitDescriptorsTest,AllTypesDeduceDelegate)124 TEST(VisitDescriptorsTest, AllTypesDeduceDelegate) {
125 const FileDescriptor& file =
126 *protobuf_unittest::TestAllTypes::GetDescriptor()->file();
127 FileDescriptorProto proto;
128 file.CopyTo(&proto);
129 std::vector<absl::string_view> descriptors;
130
131 VisitDescriptors(file, proto,
132 [&](const auto& descriptor, const auto& proto)
133 -> decltype(TestHandle(descriptor, proto, nullptr)) {
134 TestHandle(descriptor, proto, &descriptors);
135 });
136
137 EXPECT_THAT(descriptors, IsSupersetOf({"protobuf_unittest.TestAllTypes",
138 "protobuf_unittest.TestSparseEnum"}));
139 }
140
141 } // namespace
142 } // namespace protobuf
143 } // namespace google
144