• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 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 // Author: kenton@google.com (Kenton Varda)
9 //  Based on original Protocol Buffers design by
10 //  Sanjay Ghemawat, Jeff Dean, and others.
11 //
12 // This file makes extensive use of RFC 3092.  :)
13 
14 #include "google/protobuf/descriptor.h"
15 
16 #include <limits.h>
17 
18 #include <atomic>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <deque>
22 #include <functional>
23 #include <limits>
24 #include <memory>
25 #include <string>
26 #include <tuple>
27 #include <utility>
28 #include <vector>
29 
30 #include "google/protobuf/any.pb.h"
31 #include "google/protobuf/descriptor.pb.h"
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34 #include "absl/base/log_severity.h"
35 #include "absl/container/btree_set.h"
36 #include "absl/container/flat_hash_set.h"
37 #include "absl/flags/flag.h"
38 #include "absl/functional/any_invocable.h"
39 #include "absl/log/absl_check.h"
40 #include "absl/log/absl_log.h"
41 #include "absl/log/die_if_null.h"
42 #include "absl/log/scoped_mock_log.h"
43 #include "absl/status/status.h"
44 #include "absl/status/statusor.h"
45 #include "absl/strings/numbers.h"
46 #include "absl/strings/str_cat.h"
47 #include "absl/strings/str_format.h"
48 #include "absl/strings/str_split.h"
49 #include "absl/strings/string_view.h"
50 #include "absl/strings/strip.h"
51 #include "absl/strings/substitute.h"
52 #include "absl/synchronization/notification.h"
53 #include "google/protobuf/compiler/importer.h"
54 #include "google/protobuf/compiler/parser.h"
55 #include "google/protobuf/cpp_features.pb.h"
56 #include "google/protobuf/descriptor_database.h"
57 #include "google/protobuf/descriptor_legacy.h"
58 #include "google/protobuf/dynamic_message.h"
59 #include "google/protobuf/feature_resolver.h"
60 #include "google/protobuf/io/coded_stream.h"
61 #include "google/protobuf/io/tokenizer.h"
62 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
63 #include "google/protobuf/test_textproto.h"
64 #include "google/protobuf/text_format.h"
65 #include "google/protobuf/unittest.pb.h"
66 #include "google/protobuf/unittest_custom_options.pb.h"
67 #include "google/protobuf/unittest_delimited.pb.h"
68 #include "google/protobuf/unittest_delimited_import.pb.h"
69 #include "google/protobuf/unittest_features.pb.h"
70 #include "google/protobuf/unittest_lazy_dependencies.pb.h"
71 #include "google/protobuf/unittest_lazy_dependencies_custom_option.pb.h"
72 #include "google/protobuf/unittest_lazy_dependencies_enum.pb.h"
73 #include "google/protobuf/unittest_proto3_arena.pb.h"
74 #include "google/protobuf/unittest_string_type.pb.h"
75 
76 
77 // Must be included last.
78 #include "google/protobuf/port_def.inc"
79 
80 using ::google::protobuf::internal::cpp::GetUtf8CheckMode;
81 using ::google::protobuf::internal::cpp::HasPreservingUnknownEnumSemantics;
82 using ::google::protobuf::internal::cpp::Utf8CheckMode;
83 using ::testing::AnyOf;
84 using ::testing::AtLeast;
85 using ::testing::ElementsAre;
86 using ::testing::HasSubstr;
87 using ::testing::NotNull;
88 using ::testing::Return;
89 
GetStatus(const absl::Status & s)90 absl::Status GetStatus(const absl::Status& s) { return s; }
91 template <typename T>
GetStatus(const absl::StatusOr<T> & s)92 absl::Status GetStatus(const absl::StatusOr<T>& s) {
93   return s.status();
94 }
95 MATCHER_P2(StatusIs, status, message,
96            absl::StrCat(".status() is ", testing::PrintToString(status))) {
97   return GetStatus(arg).code() == status &&
98          testing::ExplainMatchResult(message, GetStatus(arg).message(),
99                                      result_listener);
100 }
101 #define EXPECT_OK(x) EXPECT_THAT(x, StatusIs(absl::StatusCode::kOk, testing::_))
102 #define ASSERT_OK(x) ASSERT_THAT(x, StatusIs(absl::StatusCode::kOk, testing::_))
103 
104 namespace google {
105 namespace protobuf {
106 
107 // Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
108 namespace descriptor_unittest {
109 
110 // Some helpers to make assembling descriptors faster.
AddMessage(FileDescriptorProto * file,const std::string & name)111 DescriptorProto* AddMessage(FileDescriptorProto* file,
112                             const std::string& name) {
113   DescriptorProto* result = file->add_message_type();
114   result->set_name(name);
115   return result;
116 }
117 
AddNestedMessage(DescriptorProto * parent,const std::string & name)118 DescriptorProto* AddNestedMessage(DescriptorProto* parent,
119                                   const std::string& name) {
120   DescriptorProto* result = parent->add_nested_type();
121   result->set_name(name);
122   return result;
123 }
124 
AddEnum(FileDescriptorProto * file,absl::string_view name)125 EnumDescriptorProto* AddEnum(FileDescriptorProto* file,
126                              absl::string_view name) {
127   EnumDescriptorProto* result = file->add_enum_type();
128   result->set_name(name);
129   return result;
130 }
131 
AddNestedEnum(DescriptorProto * parent,const std::string & name)132 EnumDescriptorProto* AddNestedEnum(DescriptorProto* parent,
133                                    const std::string& name) {
134   EnumDescriptorProto* result = parent->add_enum_type();
135   result->set_name(name);
136   return result;
137 }
138 
AddService(FileDescriptorProto * file,const std::string & name)139 ServiceDescriptorProto* AddService(FileDescriptorProto* file,
140                                    const std::string& name) {
141   ServiceDescriptorProto* result = file->add_service();
142   result->set_name(name);
143   return result;
144 }
145 
AddField(DescriptorProto * parent,const std::string & name,int number,FieldDescriptorProto::Label label,FieldDescriptorProto::Type type)146 FieldDescriptorProto* AddField(DescriptorProto* parent, const std::string& name,
147                                int number, FieldDescriptorProto::Label label,
148                                FieldDescriptorProto::Type type) {
149   FieldDescriptorProto* result = parent->add_field();
150   result->set_name(name);
151   result->set_number(number);
152   result->set_label(label);
153   result->set_type(type);
154   return result;
155 }
156 
AddExtension(FileDescriptorProto * file,const std::string & extendee,const std::string & name,int number,FieldDescriptorProto::Label label,FieldDescriptorProto::Type type)157 FieldDescriptorProto* AddExtension(FileDescriptorProto* file,
158                                    const std::string& extendee,
159                                    const std::string& name, int number,
160                                    FieldDescriptorProto::Label label,
161                                    FieldDescriptorProto::Type type) {
162   FieldDescriptorProto* result = file->add_extension();
163   result->set_name(name);
164   result->set_number(number);
165   result->set_label(label);
166   result->set_type(type);
167   result->set_extendee(extendee);
168   return result;
169 }
170 
AddNestedExtension(DescriptorProto * parent,const std::string & extendee,const std::string & name,int number,FieldDescriptorProto::Label label,FieldDescriptorProto::Type type)171 FieldDescriptorProto* AddNestedExtension(DescriptorProto* parent,
172                                          const std::string& extendee,
173                                          const std::string& name, int number,
174                                          FieldDescriptorProto::Label label,
175                                          FieldDescriptorProto::Type type) {
176   FieldDescriptorProto* result = parent->add_extension();
177   result->set_name(name);
178   result->set_number(number);
179   result->set_label(label);
180   result->set_type(type);
181   result->set_extendee(extendee);
182   return result;
183 }
184 
AddExtensionRange(DescriptorProto * parent,int start,int end)185 DescriptorProto::ExtensionRange* AddExtensionRange(DescriptorProto* parent,
186                                                    int start, int end) {
187   DescriptorProto::ExtensionRange* result = parent->add_extension_range();
188   result->set_start(start);
189   result->set_end(end);
190   return result;
191 }
192 
AddReservedRange(DescriptorProto * parent,int start,int end)193 DescriptorProto::ReservedRange* AddReservedRange(DescriptorProto* parent,
194                                                  int start, int end) {
195   DescriptorProto::ReservedRange* result = parent->add_reserved_range();
196   result->set_start(start);
197   result->set_end(end);
198   return result;
199 }
200 
AddReservedRange(EnumDescriptorProto * parent,int start,int end)201 EnumDescriptorProto::EnumReservedRange* AddReservedRange(
202     EnumDescriptorProto* parent, int start, int end) {
203   EnumDescriptorProto::EnumReservedRange* result = parent->add_reserved_range();
204   result->set_start(start);
205   result->set_end(end);
206   return result;
207 }
208 
AddEnumValue(EnumDescriptorProto * enum_proto,const std::string & name,int number)209 EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
210                                        const std::string& name, int number) {
211   EnumValueDescriptorProto* result = enum_proto->add_value();
212   result->set_name(name);
213   result->set_number(number);
214   return result;
215 }
216 
AddMethod(ServiceDescriptorProto * service,const std::string & name,const std::string & input_type,const std::string & output_type)217 MethodDescriptorProto* AddMethod(ServiceDescriptorProto* service,
218                                  const std::string& name,
219                                  const std::string& input_type,
220                                  const std::string& output_type) {
221   MethodDescriptorProto* result = service->add_method();
222   result->set_name(name);
223   result->set_input_type(input_type);
224   result->set_output_type(output_type);
225   return result;
226 }
227 
228 // Empty enums technically aren't allowed.  We need to insert a dummy value
229 // into them.
AddEmptyEnum(FileDescriptorProto * file,absl::string_view name)230 void AddEmptyEnum(FileDescriptorProto* file, absl::string_view name) {
231   AddEnumValue(AddEnum(file, name), absl::StrCat(name, "_DUMMY"), 1);
232 }
233 
234 class MockErrorCollector : public DescriptorPool::ErrorCollector {
235  public:
236   MockErrorCollector() = default;
237   ~MockErrorCollector() override = default;
238 
239   std::string text_;
240   std::string warning_text_;
241 
242   // implements ErrorCollector ---------------------------------------
RecordError(absl::string_view filename,absl::string_view element_name,const Message * descriptor,ErrorLocation location,absl::string_view message)243   void RecordError(absl::string_view filename, absl::string_view element_name,
244                    const Message* descriptor, ErrorLocation location,
245                    absl::string_view message) override {
246     absl::SubstituteAndAppend(&text_, "$0: $1: $2: $3\n", filename,
247                               element_name, ErrorLocationName(location),
248                               message);
249   }
250 
251   // implements ErrorCollector ---------------------------------------
RecordWarning(absl::string_view filename,absl::string_view element_name,const Message * descriptor,ErrorLocation location,absl::string_view message)252   void RecordWarning(absl::string_view filename, absl::string_view element_name,
253                      const Message* descriptor, ErrorLocation location,
254                      absl::string_view message) override {
255     absl::SubstituteAndAppend(&warning_text_, "$0: $1: $2: $3\n", filename,
256                               element_name, ErrorLocationName(location),
257                               message);
258   }
259 };
260 
261 // ===================================================================
262 
263 // Test simple files.
264 class FileDescriptorTest : public testing::Test {
265  protected:
SetUp()266   void SetUp() override {
267     // Build descriptors for the following definitions:
268     //
269     //   // in "foo.proto"
270     //   message FooMessage { extensions 1; }
271     //   enum FooEnum {FOO_ENUM_VALUE = 1;}
272     //   service FooService {}
273     //   extend FooMessage { optional int32 foo_extension = 1; }
274     //
275     //   // in "bar.proto"
276     //   package bar_package;
277     //   message BarMessage { extensions 1; }
278     //   enum BarEnum {BAR_ENUM_VALUE = 1;}
279     //   service BarService {}
280     //   extend BarMessage { optional int32 bar_extension = 1; }
281     //
282     // Also, we have an empty file "baz.proto".  This file's purpose is to
283     // make sure that even though it has the same package as foo.proto,
284     // searching it for members of foo.proto won't work.
285 
286     FileDescriptorProto foo_file;
287     foo_file.set_name("foo.proto");
288     AddExtensionRange(AddMessage(&foo_file, "FooMessage"), 1, 2);
289     AddEnumValue(AddEnum(&foo_file, "FooEnum"), "FOO_ENUM_VALUE", 1);
290     AddService(&foo_file, "FooService");
291     AddExtension(&foo_file, "FooMessage", "foo_extension", 1,
292                  FieldDescriptorProto::LABEL_OPTIONAL,
293                  FieldDescriptorProto::TYPE_INT32);
294 
295     FileDescriptorProto bar_file;
296     bar_file.set_name("bar.proto");
297     bar_file.set_package("bar_package");
298     bar_file.add_dependency("foo.proto");
299     AddExtensionRange(AddMessage(&bar_file, "BarMessage"), 1, 2);
300     AddEnumValue(AddEnum(&bar_file, "BarEnum"), "BAR_ENUM_VALUE", 1);
301     AddService(&bar_file, "BarService");
302     AddExtension(&bar_file, "bar_package.BarMessage", "bar_extension", 1,
303                  FieldDescriptorProto::LABEL_OPTIONAL,
304                  FieldDescriptorProto::TYPE_INT32);
305 
306     FileDescriptorProto baz_file;
307     baz_file.set_name("baz.proto");
308 
309     // Build the descriptors and get the pointers.
310     foo_file_ = pool_.BuildFile(foo_file);
311     ASSERT_TRUE(foo_file_ != nullptr);
312 
313     bar_file_ = pool_.BuildFile(bar_file);
314     ASSERT_TRUE(bar_file_ != nullptr);
315 
316     baz_file_ = pool_.BuildFile(baz_file);
317     ASSERT_TRUE(baz_file_ != nullptr);
318 
319     ASSERT_EQ(1, foo_file_->message_type_count());
320     foo_message_ = foo_file_->message_type(0);
321     ASSERT_EQ(1, foo_file_->enum_type_count());
322     foo_enum_ = foo_file_->enum_type(0);
323     ASSERT_EQ(1, foo_enum_->value_count());
324     foo_enum_value_ = foo_enum_->value(0);
325     ASSERT_EQ(1, foo_file_->service_count());
326     foo_service_ = foo_file_->service(0);
327     ASSERT_EQ(1, foo_file_->extension_count());
328     foo_extension_ = foo_file_->extension(0);
329 
330     ASSERT_EQ(1, bar_file_->message_type_count());
331     bar_message_ = bar_file_->message_type(0);
332     ASSERT_EQ(1, bar_file_->enum_type_count());
333     bar_enum_ = bar_file_->enum_type(0);
334     ASSERT_EQ(1, bar_enum_->value_count());
335     bar_enum_value_ = bar_enum_->value(0);
336     ASSERT_EQ(1, bar_file_->service_count());
337     bar_service_ = bar_file_->service(0);
338     ASSERT_EQ(1, bar_file_->extension_count());
339     bar_extension_ = bar_file_->extension(0);
340   }
341 
342   DescriptorPool pool_;
343 
344   const FileDescriptor* foo_file_;
345   const FileDescriptor* bar_file_;
346   const FileDescriptor* baz_file_;
347 
348   const Descriptor* foo_message_;
349   const EnumDescriptor* foo_enum_;
350   const EnumValueDescriptor* foo_enum_value_;
351   const ServiceDescriptor* foo_service_;
352   const FieldDescriptor* foo_extension_;
353 
354   const Descriptor* bar_message_;
355   const EnumDescriptor* bar_enum_;
356   const EnumValueDescriptor* bar_enum_value_;
357   const ServiceDescriptor* bar_service_;
358   const FieldDescriptor* bar_extension_;
359 };
360 
TEST_F(FileDescriptorTest,Name)361 TEST_F(FileDescriptorTest, Name) {
362   EXPECT_EQ("foo.proto", foo_file_->name());
363   EXPECT_EQ("bar.proto", bar_file_->name());
364   EXPECT_EQ("baz.proto", baz_file_->name());
365 }
366 
TEST_F(FileDescriptorTest,Package)367 TEST_F(FileDescriptorTest, Package) {
368   EXPECT_EQ("", foo_file_->package());
369   EXPECT_EQ("bar_package", bar_file_->package());
370 }
371 
TEST_F(FileDescriptorTest,Dependencies)372 TEST_F(FileDescriptorTest, Dependencies) {
373   EXPECT_EQ(0, foo_file_->dependency_count());
374   EXPECT_EQ(1, bar_file_->dependency_count());
375   EXPECT_EQ(foo_file_, bar_file_->dependency(0));
376 }
377 
TEST_F(FileDescriptorTest,FindMessageTypeByName)378 TEST_F(FileDescriptorTest, FindMessageTypeByName) {
379   EXPECT_EQ(foo_message_, foo_file_->FindMessageTypeByName("FooMessage"));
380   EXPECT_EQ(bar_message_, bar_file_->FindMessageTypeByName("BarMessage"));
381 
382   EXPECT_TRUE(foo_file_->FindMessageTypeByName("BarMessage") == nullptr);
383   EXPECT_TRUE(bar_file_->FindMessageTypeByName("FooMessage") == nullptr);
384   EXPECT_TRUE(baz_file_->FindMessageTypeByName("FooMessage") == nullptr);
385 
386   EXPECT_TRUE(foo_file_->FindMessageTypeByName("NoSuchMessage") == nullptr);
387   EXPECT_TRUE(foo_file_->FindMessageTypeByName("FooEnum") == nullptr);
388 }
389 
TEST_F(FileDescriptorTest,FindEnumTypeByName)390 TEST_F(FileDescriptorTest, FindEnumTypeByName) {
391   EXPECT_EQ(foo_enum_, foo_file_->FindEnumTypeByName("FooEnum"));
392   EXPECT_EQ(bar_enum_, bar_file_->FindEnumTypeByName("BarEnum"));
393 
394   EXPECT_TRUE(foo_file_->FindEnumTypeByName("BarEnum") == nullptr);
395   EXPECT_TRUE(bar_file_->FindEnumTypeByName("FooEnum") == nullptr);
396   EXPECT_TRUE(baz_file_->FindEnumTypeByName("FooEnum") == nullptr);
397 
398   EXPECT_TRUE(foo_file_->FindEnumTypeByName("NoSuchEnum") == nullptr);
399   EXPECT_TRUE(foo_file_->FindEnumTypeByName("FooMessage") == nullptr);
400 }
401 
TEST_F(FileDescriptorTest,FindEnumValueByName)402 TEST_F(FileDescriptorTest, FindEnumValueByName) {
403   EXPECT_EQ(foo_enum_value_, foo_file_->FindEnumValueByName("FOO_ENUM_VALUE"));
404   EXPECT_EQ(bar_enum_value_, bar_file_->FindEnumValueByName("BAR_ENUM_VALUE"));
405 
406   EXPECT_TRUE(foo_file_->FindEnumValueByName("BAR_ENUM_VALUE") == nullptr);
407   EXPECT_TRUE(bar_file_->FindEnumValueByName("FOO_ENUM_VALUE") == nullptr);
408   EXPECT_TRUE(baz_file_->FindEnumValueByName("FOO_ENUM_VALUE") == nullptr);
409 
410   EXPECT_TRUE(foo_file_->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
411   EXPECT_TRUE(foo_file_->FindEnumValueByName("FooMessage") == nullptr);
412 }
413 
TEST_F(FileDescriptorTest,FindServiceByName)414 TEST_F(FileDescriptorTest, FindServiceByName) {
415   EXPECT_EQ(foo_service_, foo_file_->FindServiceByName("FooService"));
416   EXPECT_EQ(bar_service_, bar_file_->FindServiceByName("BarService"));
417 
418   EXPECT_TRUE(foo_file_->FindServiceByName("BarService") == nullptr);
419   EXPECT_TRUE(bar_file_->FindServiceByName("FooService") == nullptr);
420   EXPECT_TRUE(baz_file_->FindServiceByName("FooService") == nullptr);
421 
422   EXPECT_TRUE(foo_file_->FindServiceByName("NoSuchService") == nullptr);
423   EXPECT_TRUE(foo_file_->FindServiceByName("FooMessage") == nullptr);
424 }
425 
TEST_F(FileDescriptorTest,FindExtensionByName)426 TEST_F(FileDescriptorTest, FindExtensionByName) {
427   EXPECT_EQ(foo_extension_, foo_file_->FindExtensionByName("foo_extension"));
428   EXPECT_EQ(bar_extension_, bar_file_->FindExtensionByName("bar_extension"));
429 
430   EXPECT_TRUE(foo_file_->FindExtensionByName("bar_extension") == nullptr);
431   EXPECT_TRUE(bar_file_->FindExtensionByName("foo_extension") == nullptr);
432   EXPECT_TRUE(baz_file_->FindExtensionByName("foo_extension") == nullptr);
433 
434   EXPECT_TRUE(foo_file_->FindExtensionByName("no_such_extension") == nullptr);
435   EXPECT_TRUE(foo_file_->FindExtensionByName("FooMessage") == nullptr);
436 }
437 
TEST_F(FileDescriptorTest,FindExtensionByNumber)438 TEST_F(FileDescriptorTest, FindExtensionByNumber) {
439   EXPECT_EQ(foo_extension_, pool_.FindExtensionByNumber(foo_message_, 1));
440   EXPECT_EQ(bar_extension_, pool_.FindExtensionByNumber(bar_message_, 1));
441 
442   EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == nullptr);
443 }
444 
445 
TEST_F(FileDescriptorTest,BuildAgain)446 TEST_F(FileDescriptorTest, BuildAgain) {
447   // Test that if we call BuildFile again on the same input we get the same
448   // FileDescriptor back.
449   FileDescriptorProto file;
450   foo_file_->CopyTo(&file);
451   EXPECT_EQ(foo_file_, pool_.BuildFile(file));
452 
453   // But if we change the file then it won't work.
454   file.set_package("some.other.package");
455   EXPECT_TRUE(pool_.BuildFile(file) == nullptr);
456 }
457 
TEST_F(FileDescriptorTest,BuildAgainWithSyntax)458 TEST_F(FileDescriptorTest, BuildAgainWithSyntax) {
459   // Test that if we call BuildFile again on the same input we get the same
460   // FileDescriptor back even if syntax param is specified.
461   FileDescriptorProto proto_syntax2;
462   proto_syntax2.set_name("foo_syntax2");
463   proto_syntax2.set_syntax("proto2");
464 
465   const FileDescriptor* proto2_descriptor = pool_.BuildFile(proto_syntax2);
466   EXPECT_TRUE(proto2_descriptor != nullptr);
467   EXPECT_EQ(proto2_descriptor, pool_.BuildFile(proto_syntax2));
468 
469   FileDescriptorProto implicit_proto2;
470   implicit_proto2.set_name("foo_implicit_syntax2");
471 
472   const FileDescriptor* implicit_proto2_descriptor =
473       pool_.BuildFile(implicit_proto2);
474   EXPECT_TRUE(implicit_proto2_descriptor != nullptr);
475   // We get the same FileDescriptor back if syntax param is explicitly
476   // specified.
477   implicit_proto2.set_syntax("proto2");
478   EXPECT_EQ(implicit_proto2_descriptor, pool_.BuildFile(implicit_proto2));
479 
480   FileDescriptorProto proto_syntax3;
481   proto_syntax3.set_name("foo_syntax3");
482   proto_syntax3.set_syntax("proto3");
483 
484   const FileDescriptor* proto3_descriptor = pool_.BuildFile(proto_syntax3);
485   EXPECT_TRUE(proto3_descriptor != nullptr);
486   EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3));
487 }
488 
TEST_F(FileDescriptorTest,Edition)489 TEST_F(FileDescriptorTest, Edition) {
490   FileDescriptorProto proto;
491   proto.set_name("foo");
492   {
493     proto.set_syntax("proto2");
494     DescriptorPool pool;
495     const FileDescriptor* file = pool.BuildFile(proto);
496     ASSERT_TRUE(file != nullptr);
497     EXPECT_EQ(FileDescriptorLegacy(file).edition(), Edition::EDITION_PROTO2);
498     FileDescriptorProto other;
499     file->CopyTo(&other);
500     EXPECT_EQ("", other.syntax());
501     EXPECT_FALSE(other.has_edition());
502   }
503   {
504     proto.set_syntax("proto3");
505     DescriptorPool pool;
506     const FileDescriptor* file = pool.BuildFile(proto);
507     ASSERT_TRUE(file != nullptr);
508     EXPECT_EQ(FileDescriptorLegacy(file).edition(), Edition::EDITION_PROTO3);
509     FileDescriptorProto other;
510     file->CopyTo(&other);
511     EXPECT_EQ("proto3", other.syntax());
512     EXPECT_FALSE(other.has_edition());
513   }
514   {
515     proto.set_syntax("editions");
516     proto.set_edition(EDITION_2023);
517     DescriptorPool pool;
518     const FileDescriptor* file = pool.BuildFile(proto);
519     ASSERT_TRUE(file != nullptr);
520     EXPECT_EQ(FileDescriptorLegacy(file).edition(), Edition::EDITION_2023);
521     FileDescriptorProto other;
522     file->CopyTo(&other);
523     EXPECT_EQ("editions", other.syntax());
524     EXPECT_EQ(other.edition(), EDITION_2023);
525   }
526 }
527 
TEST_F(FileDescriptorTest,CopyHeadingTo)528 TEST_F(FileDescriptorTest, CopyHeadingTo) {
529   FileDescriptorProto proto;
530   proto.set_name("foo.proto");
531   proto.set_package("foo.bar.baz");
532   proto.set_syntax("proto3");
533   proto.mutable_options()->set_java_package("foo.bar.baz");
534 
535   // Won't be copied.
536   proto.add_message_type()->set_name("Foo");
537 
538   DescriptorPool pool;
539   const FileDescriptor* file = pool.BuildFile(proto);
540   ASSERT_NE(file, nullptr);
541 
542   FileDescriptorProto other;
543   file->CopyHeadingTo(&other);
544   EXPECT_EQ(other.name(), "foo.proto");
545   EXPECT_EQ(other.package(), "foo.bar.baz");
546   EXPECT_EQ(other.syntax(), "proto3");
547   EXPECT_EQ(other.options().java_package(), "foo.bar.baz");
548   EXPECT_TRUE(other.message_type().empty());
549   EXPECT_EQ(&other.options().features(), &FeatureSet::default_instance());
550   {
551     proto.set_syntax("editions");
552     proto.set_edition(EDITION_2023);
553 
554     DescriptorPool pool;
555     const FileDescriptor* file = pool.BuildFile(proto);
556     ASSERT_NE(file, nullptr);
557 
558     FileDescriptorProto other;
559     file->CopyHeadingTo(&other);
560     EXPECT_EQ(other.name(), "foo.proto");
561     EXPECT_EQ(other.package(), "foo.bar.baz");
562     EXPECT_EQ(other.syntax(), "editions");
563     EXPECT_EQ(other.edition(), EDITION_2023);
564     EXPECT_EQ(other.options().java_package(), "foo.bar.baz");
565     EXPECT_TRUE(other.message_type().empty());
566     EXPECT_EQ(&other.options().features(), &FeatureSet::default_instance());
567   }
568 }
569 
ExtractDebugString(const FileDescriptor * file,absl::flat_hash_set<absl::string_view> * visited,std::vector<std::pair<absl::string_view,std::string>> * debug_strings)570 void ExtractDebugString(
571     const FileDescriptor* file, absl::flat_hash_set<absl::string_view>* visited,
572     std::vector<std::pair<absl::string_view, std::string>>* debug_strings) {
573   if (!visited->insert(file->name()).second) {
574     return;
575   }
576   for (int i = 0; i < file->dependency_count(); ++i) {
577     ExtractDebugString(file->dependency(i), visited, debug_strings);
578   }
579   debug_strings->push_back({file->name(), file->DebugString()});
580 }
581 
582 class SimpleErrorCollector : public io::ErrorCollector {
583  public:
584   // implements ErrorCollector ---------------------------------------
RecordError(int line,int column,absl::string_view message)585   void RecordError(int line, int column, absl::string_view message) override {
586     last_error_ = absl::StrFormat("%d:%d:%s", line, column, message);
587   }
588 
last_error()589   const std::string& last_error() { return last_error_; }
590 
591  private:
592   std::string last_error_;
593 };
594 // Test that the result of FileDescriptor::DebugString() can be used to create
595 // the original descriptors.
TEST_F(FileDescriptorTest,DebugStringRoundTrip)596 TEST_F(FileDescriptorTest, DebugStringRoundTrip) {
597   absl::flat_hash_set<absl::string_view> visited;
598   std::vector<std::pair<absl::string_view, std::string>> debug_strings;
599   ExtractDebugString(protobuf_unittest::TestAllTypes::descriptor()->file(),
600                      &visited, &debug_strings);
601   ExtractDebugString(
602       protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file(),
603       &visited, &debug_strings);
604   ExtractDebugString(proto3_arena_unittest::TestAllTypes::descriptor()->file(),
605                      &visited, &debug_strings);
606   ASSERT_GE(debug_strings.size(), 3);
607 
608   DescriptorPool pool;
609   for (size_t i = 0; i < debug_strings.size(); ++i) {
610     const absl::string_view name = debug_strings[i].first;
611     const std::string& content = debug_strings[i].second;
612     io::ArrayInputStream input_stream(content.data(), content.size());
613     SimpleErrorCollector error_collector;
614     io::Tokenizer tokenizer(&input_stream, &error_collector);
615     compiler::Parser parser;
616     parser.RecordErrorsTo(&error_collector);
617     FileDescriptorProto proto;
618     ASSERT_TRUE(parser.Parse(&tokenizer, &proto))
619         << error_collector.last_error() << "\n"
620         << content;
621     ASSERT_EQ("", error_collector.last_error());
622     proto.set_name(name);
623     const FileDescriptor* descriptor = pool.BuildFile(proto);
624     ASSERT_TRUE(descriptor != nullptr) << error_collector.last_error();
625     EXPECT_EQ(content, descriptor->DebugString());
626   }
627 }
628 
TEST_F(FileDescriptorTest,AbslStringifyWorks)629 TEST_F(FileDescriptorTest, AbslStringifyWorks) {
630   std::string s = absl::StrFormat(
631       "%v",
632       *protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file());
633   EXPECT_THAT(s, HasSubstr("TestMessageWithCustomOptions"));
634 }
635 
636 // ===================================================================
637 
638 // Test simple flat messages and fields.
639 class DescriptorTest : public testing::Test {
640  protected:
SetUp()641   void SetUp() override {
642     // Build descriptors for the following definitions:
643     //
644     //   // in "foo.proto"
645     //   message TestForeign {}
646     //   enum TestEnum {}
647     //
648     //   message TestMessage {
649     //     required string      foo = 1;
650     //     optional TestEnum    bar = 6;
651     //     repeated TestForeign baz = 500000000;
652     //     optional group       moo = 15 {}
653     //   }
654     //
655     //   // in "bar.proto"
656     //   package corge.grault;
657     //   message TestMessage2 {
658     //     required string foo = 1;
659     //     required string bar = 2;
660     //     required string mooo = 6;
661     //   }
662     //
663     //   // in "map.proto"
664     //   message TestMessage3 {
665     //     map<int32, int32> map_int32_int32 = 1;
666     //   }
667     //
668     //   // in "json.proto"
669     //   message TestMessage4 {
670     //     optional int32 field_name1 = 1;
671     //     optional int32 fieldName2 = 2;
672     //     optional int32 FieldName3 = 3;
673     //     optional int32 _field_name4 = 4;
674     //     optional int32 FIELD_NAME5 = 5;
675     //     optional int32 field_name6 = 6 [json_name = "@type"];
676     //   }
677     //
678     // We cheat and use TestForeign as the type for moo rather than create
679     // an actual nested type.
680     //
681     // Since all primitive types (including string) use the same building
682     // code, there's no need to test each one individually.
683     //
684     // TestMessage2 is primarily here to test FindFieldByName and friends.
685     // All messages created from the same DescriptorPool share the same lookup
686     // table, so we need to insure that they don't interfere.
687 
688     FileDescriptorProto foo_file;
689     foo_file.set_name("foo.proto");
690     AddMessage(&foo_file, "TestForeign");
691     AddEmptyEnum(&foo_file, "TestEnum");
692 
693     DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
694     AddField(message, "foo", 1, FieldDescriptorProto::LABEL_REQUIRED,
695              FieldDescriptorProto::TYPE_STRING);
696     AddField(message, "bar", 6, FieldDescriptorProto::LABEL_OPTIONAL,
697              FieldDescriptorProto::TYPE_ENUM)
698         ->set_type_name("TestEnum");
699     AddField(message, "baz", 500000000, FieldDescriptorProto::LABEL_REPEATED,
700              FieldDescriptorProto::TYPE_MESSAGE)
701         ->set_type_name("TestForeign");
702     AddField(message, "moo", 15, FieldDescriptorProto::LABEL_OPTIONAL,
703              FieldDescriptorProto::TYPE_GROUP)
704         ->set_type_name("TestForeign");
705 
706     FileDescriptorProto bar_file;
707     bar_file.set_name("bar.proto");
708     bar_file.set_package("corge.grault");
709 
710     DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
711     AddField(message2, "foo", 1, FieldDescriptorProto::LABEL_REQUIRED,
712              FieldDescriptorProto::TYPE_STRING);
713     AddField(message2, "bar", 2, FieldDescriptorProto::LABEL_REQUIRED,
714              FieldDescriptorProto::TYPE_STRING);
715     AddField(message2, "mooo", 6, FieldDescriptorProto::LABEL_REQUIRED,
716              FieldDescriptorProto::TYPE_STRING);
717 
718     FileDescriptorProto map_file;
719     map_file.set_name("map.proto");
720     DescriptorProto* message3 = AddMessage(&map_file, "TestMessage3");
721 
722     DescriptorProto* entry = AddNestedMessage(message3, "MapInt32Int32Entry");
723     AddField(entry, "key", 1, FieldDescriptorProto::LABEL_OPTIONAL,
724              FieldDescriptorProto::TYPE_INT32);
725     AddField(entry, "value", 2, FieldDescriptorProto::LABEL_OPTIONAL,
726              FieldDescriptorProto::TYPE_INT32);
727     entry->mutable_options()->set_map_entry(true);
728 
729     AddField(message3, "map_int32_int32", 1,
730              FieldDescriptorProto::LABEL_REPEATED,
731              FieldDescriptorProto::TYPE_MESSAGE)
732         ->set_type_name("MapInt32Int32Entry");
733 
734     FileDescriptorProto json_file;
735     json_file.set_name("json.proto");
736     json_file.set_syntax("proto3");
737     DescriptorProto* message4 = AddMessage(&json_file, "TestMessage4");
738     AddField(message4, "field_name1", 1, FieldDescriptorProto::LABEL_OPTIONAL,
739              FieldDescriptorProto::TYPE_INT32);
740     AddField(message4, "fieldName2", 2, FieldDescriptorProto::LABEL_OPTIONAL,
741              FieldDescriptorProto::TYPE_INT32);
742     AddField(message4, "FieldName3", 3, FieldDescriptorProto::LABEL_OPTIONAL,
743              FieldDescriptorProto::TYPE_INT32);
744     AddField(message4, "_field_name4", 4, FieldDescriptorProto::LABEL_OPTIONAL,
745              FieldDescriptorProto::TYPE_INT32);
746     AddField(message4, "FIELD_NAME5", 5, FieldDescriptorProto::LABEL_OPTIONAL,
747              FieldDescriptorProto::TYPE_INT32);
748     AddField(message4, "field_name6", 6, FieldDescriptorProto::LABEL_OPTIONAL,
749              FieldDescriptorProto::TYPE_INT32)
750         ->set_json_name("@type");
751     AddField(message4, "fieldname7", 7, FieldDescriptorProto::LABEL_OPTIONAL,
752              FieldDescriptorProto::TYPE_INT32);
753 
754     // Build the descriptors and get the pointers.
755     foo_file_ = pool_.BuildFile(foo_file);
756     ASSERT_TRUE(foo_file_ != nullptr);
757 
758     bar_file_ = pool_.BuildFile(bar_file);
759     ASSERT_TRUE(bar_file_ != nullptr);
760 
761     map_file_ = pool_.BuildFile(map_file);
762     ASSERT_TRUE(map_file_ != nullptr);
763 
764     json_file_ = pool_.BuildFile(json_file);
765     ASSERT_TRUE(json_file_ != nullptr);
766 
767     ASSERT_EQ(1, foo_file_->enum_type_count());
768     enum_ = foo_file_->enum_type(0);
769 
770     ASSERT_EQ(2, foo_file_->message_type_count());
771     foreign_ = foo_file_->message_type(0);
772     message_ = foo_file_->message_type(1);
773 
774     ASSERT_EQ(4, message_->field_count());
775     foo_ = message_->field(0);
776     bar_ = message_->field(1);
777     baz_ = message_->field(2);
778     moo_ = message_->field(3);
779 
780     ASSERT_EQ(1, bar_file_->message_type_count());
781     message2_ = bar_file_->message_type(0);
782 
783     ASSERT_EQ(3, message2_->field_count());
784     foo2_ = message2_->field(0);
785     bar2_ = message2_->field(1);
786     mooo2_ = message2_->field(2);
787 
788     ASSERT_EQ(1, map_file_->message_type_count());
789     message3_ = map_file_->message_type(0);
790 
791     ASSERT_EQ(1, message3_->field_count());
792     map_ = message3_->field(0);
793 
794     ASSERT_EQ(1, json_file_->message_type_count());
795     message4_ = json_file_->message_type(0);
796   }
797 
CopyWithJsonName(const Descriptor * message,DescriptorProto * proto)798   void CopyWithJsonName(const Descriptor* message, DescriptorProto* proto) {
799     message->CopyTo(proto);
800     message->CopyJsonNameTo(proto);
801   }
802 
FindValueByNumberCreatingIfUnknown(const EnumDescriptor * desc,int number)803   const EnumValueDescriptor* FindValueByNumberCreatingIfUnknown(
804       const EnumDescriptor* desc, int number) {
805     return desc->FindValueByNumberCreatingIfUnknown(number);
806   }
807 
808   DescriptorPool pool_;
809 
810   const FileDescriptor* foo_file_;
811   const FileDescriptor* bar_file_;
812   const FileDescriptor* map_file_;
813   const FileDescriptor* json_file_;
814 
815   const Descriptor* message_;
816   const Descriptor* message2_;
817   const Descriptor* message3_;
818   const Descriptor* message4_;
819   const Descriptor* foreign_;
820   const EnumDescriptor* enum_;
821 
822   const FieldDescriptor* foo_;
823   const FieldDescriptor* bar_;
824   const FieldDescriptor* baz_;
825   const FieldDescriptor* moo_;
826 
827   const FieldDescriptor* foo2_;
828   const FieldDescriptor* bar2_;
829   const FieldDescriptor* mooo2_;
830 
831   const FieldDescriptor* map_;
832 };
833 
TEST_F(DescriptorTest,Name)834 TEST_F(DescriptorTest, Name) {
835   EXPECT_EQ("TestMessage", message_->name());
836   EXPECT_EQ("TestMessage", message_->full_name());
837   EXPECT_EQ(foo_file_, message_->file());
838 
839   EXPECT_EQ("TestMessage2", message2_->name());
840   EXPECT_EQ("corge.grault.TestMessage2", message2_->full_name());
841   EXPECT_EQ(bar_file_, message2_->file());
842 }
843 
TEST_F(DescriptorTest,ContainingType)844 TEST_F(DescriptorTest, ContainingType) {
845   EXPECT_TRUE(message_->containing_type() == nullptr);
846   EXPECT_TRUE(message2_->containing_type() == nullptr);
847 }
848 
TEST_F(DescriptorTest,FieldNamesDedup)849 TEST_F(DescriptorTest, FieldNamesDedup) {
850   const auto collect_unique_names = [](const FieldDescriptor* field) {
851     absl::btree_set<absl::string_view> names{
852         field->name(), field->lowercase_name(), field->camelcase_name(),
853         field->json_name()};
854     // Verify that we have the same number of string objects as we have string
855     // values. That is, duplicate names use the same std::string object.
856     // This is for memory efficiency.
857     EXPECT_EQ(names.size(),
858               (absl::flat_hash_set<const void*>{
859                   field->name().data(), field->lowercase_name().data(),
860                   field->camelcase_name().data(), field->json_name().data()}
861                    .size()))
862         << testing::PrintToString(names);
863     return names;
864   };
865 
866   // field_name1
867   EXPECT_THAT(collect_unique_names(message4_->field(0)),
868               ElementsAre("fieldName1", "field_name1"));
869   // fieldName2
870   EXPECT_THAT(collect_unique_names(message4_->field(1)),
871               ElementsAre("fieldName2", "fieldname2"));
872   // FieldName3
873   EXPECT_THAT(collect_unique_names(message4_->field(2)),
874               ElementsAre("FieldName3", "fieldName3", "fieldname3"));
875   // _field_name4
876   EXPECT_THAT(collect_unique_names(message4_->field(3)),
877               ElementsAre("FieldName4", "_field_name4", "fieldName4"));
878   // FIELD_NAME5
879   EXPECT_THAT(
880       collect_unique_names(message4_->field(4)),
881       ElementsAre("FIELDNAME5", "FIELD_NAME5", "fIELDNAME5", "field_name5"));
882   // field_name6, with json name @type
883   EXPECT_THAT(collect_unique_names(message4_->field(5)),
884               ElementsAre("@type", "fieldName6", "field_name6"));
885   // fieldname7
886   EXPECT_THAT(collect_unique_names(message4_->field(6)),
887               ElementsAre("fieldname7"));
888 }
889 
TEST_F(DescriptorTest,FieldNameDedupJsonEqFull)890 TEST_F(DescriptorTest, FieldNameDedupJsonEqFull) {
891   // Test a regression where json_name == full_name
892   FileDescriptorProto proto;
893   proto.set_name("file");
894   auto* message = AddMessage(&proto, "Name1");
895   auto* field =
896       AddField(message, "Name2", 1, FieldDescriptorProto::LABEL_OPTIONAL,
897                FieldDescriptorProto::TYPE_INT32);
898   field->set_json_name("Name1.Name2");
899   auto* file = pool_.BuildFile(proto);
900   EXPECT_EQ(file->message_type(0)->name(), "Name1");
901   EXPECT_EQ(file->message_type(0)->field(0)->name(), "Name2");
902   EXPECT_EQ(file->message_type(0)->field(0)->full_name(), "Name1.Name2");
903   EXPECT_EQ(file->message_type(0)->field(0)->json_name(), "Name1.Name2");
904 }
905 
TEST_F(DescriptorTest,FieldsByIndex)906 TEST_F(DescriptorTest, FieldsByIndex) {
907   ASSERT_EQ(4, message_->field_count());
908   EXPECT_EQ(foo_, message_->field(0));
909   EXPECT_EQ(bar_, message_->field(1));
910   EXPECT_EQ(baz_, message_->field(2));
911   EXPECT_EQ(moo_, message_->field(3));
912 }
913 
TEST_F(DescriptorTest,FindFieldByName)914 TEST_F(DescriptorTest, FindFieldByName) {
915   // All messages in the same DescriptorPool share a single lookup table for
916   // fields.  So, in addition to testing that FindFieldByName finds the fields
917   // of the message, we need to test that it does *not* find the fields of
918   // *other* messages.
919 
920   EXPECT_EQ(foo_, message_->FindFieldByName("foo"));
921   EXPECT_EQ(bar_, message_->FindFieldByName("bar"));
922   EXPECT_EQ(baz_, message_->FindFieldByName("baz"));
923   EXPECT_EQ(moo_, message_->FindFieldByName("moo"));
924   EXPECT_TRUE(message_->FindFieldByName("no_such_field") == nullptr);
925   EXPECT_TRUE(message_->FindFieldByName("mooo") == nullptr);
926 
927   EXPECT_EQ(foo2_, message2_->FindFieldByName("foo"));
928   EXPECT_EQ(bar2_, message2_->FindFieldByName("bar"));
929   EXPECT_EQ(mooo2_, message2_->FindFieldByName("mooo"));
930   EXPECT_TRUE(message2_->FindFieldByName("baz") == nullptr);
931   EXPECT_TRUE(message2_->FindFieldByName("moo") == nullptr);
932 }
933 
TEST_F(DescriptorTest,FindFieldByNumber)934 TEST_F(DescriptorTest, FindFieldByNumber) {
935   EXPECT_EQ(foo_, message_->FindFieldByNumber(1));
936   EXPECT_EQ(bar_, message_->FindFieldByNumber(6));
937   EXPECT_EQ(baz_, message_->FindFieldByNumber(500000000));
938   EXPECT_EQ(moo_, message_->FindFieldByNumber(15));
939   EXPECT_TRUE(message_->FindFieldByNumber(837592) == nullptr);
940   EXPECT_TRUE(message_->FindFieldByNumber(2) == nullptr);
941 
942   EXPECT_EQ(foo2_, message2_->FindFieldByNumber(1));
943   EXPECT_EQ(bar2_, message2_->FindFieldByNumber(2));
944   EXPECT_EQ(mooo2_, message2_->FindFieldByNumber(6));
945   EXPECT_TRUE(message2_->FindFieldByNumber(15) == nullptr);
946   EXPECT_TRUE(message2_->FindFieldByNumber(500000000) == nullptr);
947 }
948 
TEST_F(DescriptorTest,FieldName)949 TEST_F(DescriptorTest, FieldName) {
950   EXPECT_EQ("foo", foo_->name());
951   EXPECT_EQ("bar", bar_->name());
952   EXPECT_EQ("baz", baz_->name());
953   EXPECT_EQ("moo", moo_->name());
954 }
955 
TEST_F(DescriptorTest,FieldFullName)956 TEST_F(DescriptorTest, FieldFullName) {
957   EXPECT_EQ("TestMessage.foo", foo_->full_name());
958   EXPECT_EQ("TestMessage.bar", bar_->full_name());
959   EXPECT_EQ("TestMessage.baz", baz_->full_name());
960   EXPECT_EQ("TestMessage.moo", moo_->full_name());
961 
962   EXPECT_EQ("corge.grault.TestMessage2.foo", foo2_->full_name());
963   EXPECT_EQ("corge.grault.TestMessage2.bar", bar2_->full_name());
964   EXPECT_EQ("corge.grault.TestMessage2.mooo", mooo2_->full_name());
965 }
966 
TEST_F(DescriptorTest,PrintableNameIsFullNameForNonExtensionFields)967 TEST_F(DescriptorTest, PrintableNameIsFullNameForNonExtensionFields) {
968   EXPECT_EQ("TestMessage.foo", foo_->PrintableNameForExtension());
969   EXPECT_EQ("TestMessage.bar", bar_->PrintableNameForExtension());
970   EXPECT_EQ("TestMessage.baz", baz_->PrintableNameForExtension());
971   EXPECT_EQ("TestMessage.moo", moo_->PrintableNameForExtension());
972 
973   EXPECT_EQ("corge.grault.TestMessage2.foo",
974             foo2_->PrintableNameForExtension());
975   EXPECT_EQ("corge.grault.TestMessage2.bar",
976             bar2_->PrintableNameForExtension());
977   EXPECT_EQ("corge.grault.TestMessage2.mooo",
978             mooo2_->PrintableNameForExtension());
979 }
980 
TEST_F(DescriptorTest,PrintableNameIsFullNameForNonMessageSetExtension)981 TEST_F(DescriptorTest, PrintableNameIsFullNameForNonMessageSetExtension) {
982   EXPECT_EQ("protobuf_unittest.Aggregate.nested",
983             protobuf_unittest::Aggregate::descriptor()
984                 ->FindExtensionByName("nested")
985                 ->PrintableNameForExtension());
986 }
987 
TEST_F(DescriptorTest,PrintableNameIsExtendingTypeForMessageSetExtension)988 TEST_F(DescriptorTest, PrintableNameIsExtendingTypeForMessageSetExtension) {
989   EXPECT_EQ("protobuf_unittest.AggregateMessageSetElement",
990             protobuf_unittest::AggregateMessageSetElement::descriptor()
991                 ->FindExtensionByName("message_set_extension")
992                 ->PrintableNameForExtension());
993 }
994 
TEST_F(DescriptorTest,FieldJsonName)995 TEST_F(DescriptorTest, FieldJsonName) {
996   EXPECT_EQ("fieldName1", message4_->field(0)->json_name());
997   EXPECT_EQ("fieldName2", message4_->field(1)->json_name());
998   EXPECT_EQ("FieldName3", message4_->field(2)->json_name());
999   EXPECT_EQ("FieldName4", message4_->field(3)->json_name());
1000   EXPECT_EQ("FIELDNAME5", message4_->field(4)->json_name());
1001   EXPECT_EQ("@type", message4_->field(5)->json_name());
1002 
1003   DescriptorProto proto;
1004   message4_->CopyTo(&proto);
1005   ASSERT_EQ(7, proto.field_size());
1006   EXPECT_FALSE(proto.field(0).has_json_name());
1007   EXPECT_FALSE(proto.field(1).has_json_name());
1008   EXPECT_FALSE(proto.field(2).has_json_name());
1009   EXPECT_FALSE(proto.field(3).has_json_name());
1010   EXPECT_FALSE(proto.field(4).has_json_name());
1011   EXPECT_EQ("@type", proto.field(5).json_name());
1012   EXPECT_FALSE(proto.field(6).has_json_name());
1013 
1014   proto.Clear();
1015   CopyWithJsonName(message4_, &proto);
1016   ASSERT_EQ(7, proto.field_size());
1017   EXPECT_EQ("fieldName1", proto.field(0).json_name());
1018   EXPECT_EQ("fieldName2", proto.field(1).json_name());
1019   EXPECT_EQ("FieldName3", proto.field(2).json_name());
1020   EXPECT_EQ("FieldName4", proto.field(3).json_name());
1021   EXPECT_EQ("FIELDNAME5", proto.field(4).json_name());
1022   EXPECT_EQ("@type", proto.field(5).json_name());
1023   EXPECT_EQ("fieldname7", proto.field(6).json_name());
1024 
1025   // Test generated descriptor.
1026   const Descriptor* generated = protobuf_unittest::TestJsonName::descriptor();
1027   ASSERT_EQ(7, generated->field_count());
1028   EXPECT_EQ("fieldName1", generated->field(0)->json_name());
1029   EXPECT_EQ("fieldName2", generated->field(1)->json_name());
1030   EXPECT_EQ("FieldName3", generated->field(2)->json_name());
1031   EXPECT_EQ("FieldName4", generated->field(3)->json_name());
1032   EXPECT_EQ("FIELDNAME5", generated->field(4)->json_name());
1033   EXPECT_EQ("@type", generated->field(5)->json_name());
1034   EXPECT_EQ("fieldname7", generated->field(6)->json_name());
1035 }
1036 
TEST_F(DescriptorTest,FieldFile)1037 TEST_F(DescriptorTest, FieldFile) {
1038   EXPECT_EQ(foo_file_, foo_->file());
1039   EXPECT_EQ(foo_file_, bar_->file());
1040   EXPECT_EQ(foo_file_, baz_->file());
1041   EXPECT_EQ(foo_file_, moo_->file());
1042 
1043   EXPECT_EQ(bar_file_, foo2_->file());
1044   EXPECT_EQ(bar_file_, bar2_->file());
1045   EXPECT_EQ(bar_file_, mooo2_->file());
1046 }
1047 
TEST_F(DescriptorTest,FieldIndex)1048 TEST_F(DescriptorTest, FieldIndex) {
1049   EXPECT_EQ(0, foo_->index());
1050   EXPECT_EQ(1, bar_->index());
1051   EXPECT_EQ(2, baz_->index());
1052   EXPECT_EQ(3, moo_->index());
1053 }
1054 
TEST_F(DescriptorTest,FieldNumber)1055 TEST_F(DescriptorTest, FieldNumber) {
1056   EXPECT_EQ(1, foo_->number());
1057   EXPECT_EQ(6, bar_->number());
1058   EXPECT_EQ(500000000, baz_->number());
1059   EXPECT_EQ(15, moo_->number());
1060 }
1061 
TEST_F(DescriptorTest,FieldType)1062 TEST_F(DescriptorTest, FieldType) {
1063   EXPECT_EQ(FieldDescriptor::TYPE_STRING, foo_->type());
1064   EXPECT_EQ(FieldDescriptor::TYPE_ENUM, bar_->type());
1065   EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_->type());
1066   EXPECT_EQ(FieldDescriptor::TYPE_GROUP, moo_->type());
1067 }
1068 
TEST_F(DescriptorTest,FieldLabel)1069 TEST_F(DescriptorTest, FieldLabel) {
1070   EXPECT_EQ(FieldDescriptor::LABEL_REQUIRED, foo_->label());
1071   EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->label());
1072   EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, baz_->label());
1073   EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, moo_->label());
1074 
1075   EXPECT_TRUE(foo_->is_required());
1076   EXPECT_FALSE(foo_->is_optional());
1077   EXPECT_FALSE(foo_->is_repeated());
1078 
1079   EXPECT_FALSE(bar_->is_required());
1080   EXPECT_TRUE(bar_->is_optional());
1081   EXPECT_FALSE(bar_->is_repeated());
1082 
1083   EXPECT_FALSE(baz_->is_required());
1084   EXPECT_FALSE(baz_->is_optional());
1085   EXPECT_TRUE(baz_->is_repeated());
1086 }
1087 
TEST_F(DescriptorTest,NeedsUtf8Check)1088 TEST_F(DescriptorTest, NeedsUtf8Check) {
1089   EXPECT_FALSE(foo_->requires_utf8_validation());
1090   EXPECT_FALSE(bar_->requires_utf8_validation());
1091 
1092   // Build a copy of the file in proto3.
1093   FileDescriptorProto foo_file3;
1094   foo_file_->CopyTo(&foo_file3);
1095   foo_file3.set_syntax("proto3");
1096 
1097   // Make this valid proto3 by removing `required` and the one group field.
1098   for (auto& f : *foo_file3.mutable_message_type(1)->mutable_field()) {
1099     f.clear_label();
1100     if (f.type() == FieldDescriptorProto::TYPE_GROUP) {
1101       f.set_type(FieldDescriptorProto::TYPE_MESSAGE);
1102     }
1103   }
1104   // Make this valid proto3 by making the first enum value be zero.
1105   foo_file3.mutable_enum_type(0)->mutable_value(0)->set_number(0);
1106 
1107   DescriptorPool pool3;
1108   const Descriptor* message3 = pool3.BuildFile(foo_file3)->message_type(1);
1109   const FieldDescriptor* foo3 = message3->field(0);
1110   const FieldDescriptor* bar3 = message3->field(1);
1111 
1112   EXPECT_TRUE(foo3->requires_utf8_validation());
1113   EXPECT_FALSE(bar3->requires_utf8_validation());
1114 }
1115 
TEST_F(DescriptorTest,EnumFieldTreatedAsClosed)1116 TEST_F(DescriptorTest, EnumFieldTreatedAsClosed) {
1117   // Make an open enum definition.
1118   FileDescriptorProto open_enum_file;
1119   open_enum_file.set_name("open_enum.proto");
1120   open_enum_file.set_syntax("proto3");
1121   AddEnumValue(AddEnum(&open_enum_file, "TestEnumOpen"), "TestEnumOpen_VALUE0",
1122                0);
1123 
1124   const EnumDescriptor* open_enum =
1125       pool_.BuildFile(open_enum_file)->enum_type(0);
1126   EXPECT_FALSE(open_enum->is_closed());
1127 
1128   // Create a message that treats enum fields as closed.
1129   FileDescriptorProto closed_file;
1130   closed_file.set_name("closed_enum_field.proto");
1131   closed_file.add_dependency("open_enum.proto");
1132   closed_file.add_dependency("foo.proto");
1133 
1134   DescriptorProto* message = AddMessage(&closed_file, "TestClosedEnumField");
1135   AddField(message, "int_field", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1136            FieldDescriptorProto::TYPE_INT32);
1137   AddField(message, "open_enum", 2, FieldDescriptorProto::LABEL_OPTIONAL,
1138            FieldDescriptorProto::TYPE_ENUM)
1139       ->set_type_name("TestEnumOpen");
1140   AddField(message, "closed_enum", 3, FieldDescriptorProto::LABEL_OPTIONAL,
1141            FieldDescriptorProto::TYPE_ENUM)
1142       ->set_type_name("TestEnum");
1143   const Descriptor* closed_message =
1144       pool_.BuildFile(closed_file)->message_type(0);
1145 
1146   EXPECT_FALSE(closed_message->FindFieldByName("int_field")
1147                    ->legacy_enum_field_treated_as_closed());
1148   EXPECT_TRUE(closed_message->FindFieldByName("closed_enum")
1149                   ->legacy_enum_field_treated_as_closed());
1150   EXPECT_TRUE(closed_message->FindFieldByName("open_enum")
1151                   ->legacy_enum_field_treated_as_closed());
1152 }
1153 
TEST_F(DescriptorTest,EnumFieldTreatedAsOpen)1154 TEST_F(DescriptorTest, EnumFieldTreatedAsOpen) {
1155   FileDescriptorProto open_enum_file;
1156   open_enum_file.set_name("open_enum.proto");
1157   open_enum_file.set_syntax("proto3");
1158   AddEnumValue(AddEnum(&open_enum_file, "TestEnumOpen"), "TestEnumOpen_VALUE0",
1159                0);
1160   DescriptorProto* message = AddMessage(&open_enum_file, "TestOpenEnumField");
1161   AddField(message, "int_field", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1162            FieldDescriptorProto::TYPE_INT32);
1163   AddField(message, "open_enum", 2, FieldDescriptorProto::LABEL_OPTIONAL,
1164            FieldDescriptorProto::TYPE_ENUM)
1165       ->set_type_name("TestEnumOpen");
1166   const FileDescriptor* open_enum_file_desc = pool_.BuildFile(open_enum_file);
1167   const Descriptor* open_message = open_enum_file_desc->message_type(0);
1168   const EnumDescriptor* open_enum = open_enum_file_desc->enum_type(0);
1169   EXPECT_FALSE(open_enum->is_closed());
1170   EXPECT_FALSE(open_message->FindFieldByName("int_field")
1171                    ->legacy_enum_field_treated_as_closed());
1172   EXPECT_FALSE(open_message->FindFieldByName("open_enum")
1173                    ->legacy_enum_field_treated_as_closed());
1174 }
1175 
TEST_F(DescriptorTest,IsMap)1176 TEST_F(DescriptorTest, IsMap) {
1177   EXPECT_TRUE(map_->is_map());
1178   EXPECT_FALSE(baz_->is_map());
1179   EXPECT_TRUE(map_->message_type()->options().map_entry());
1180 }
1181 
TEST_F(DescriptorTest,GetMap)1182 TEST_F(DescriptorTest, GetMap) {
1183   const Descriptor* map_desc = map_->message_type();
1184   const FieldDescriptor* map_key = map_desc->map_key();
1185   ASSERT_TRUE(map_key != nullptr);
1186   EXPECT_EQ(map_key->name(), "key");
1187   EXPECT_EQ(map_key->number(), 1);
1188 
1189   const FieldDescriptor* map_value = map_desc->map_value();
1190   ASSERT_TRUE(map_value != nullptr);
1191   EXPECT_EQ(map_value->name(), "value");
1192   EXPECT_EQ(map_value->number(), 2);
1193 
1194   EXPECT_EQ(message_->map_key(), nullptr);
1195   EXPECT_EQ(message_->map_value(), nullptr);
1196 }
1197 
TEST_F(DescriptorTest,FieldHasDefault)1198 TEST_F(DescriptorTest, FieldHasDefault) {
1199   EXPECT_FALSE(foo_->has_default_value());
1200   EXPECT_FALSE(bar_->has_default_value());
1201   EXPECT_FALSE(baz_->has_default_value());
1202   EXPECT_FALSE(moo_->has_default_value());
1203 }
1204 
TEST_F(DescriptorTest,FieldContainingType)1205 TEST_F(DescriptorTest, FieldContainingType) {
1206   EXPECT_EQ(message_, foo_->containing_type());
1207   EXPECT_EQ(message_, bar_->containing_type());
1208   EXPECT_EQ(message_, baz_->containing_type());
1209   EXPECT_EQ(message_, moo_->containing_type());
1210 
1211   EXPECT_EQ(message2_, foo2_->containing_type());
1212   EXPECT_EQ(message2_, bar2_->containing_type());
1213   EXPECT_EQ(message2_, mooo2_->containing_type());
1214 }
1215 
TEST_F(DescriptorTest,FieldMessageType)1216 TEST_F(DescriptorTest, FieldMessageType) {
1217   EXPECT_TRUE(foo_->message_type() == nullptr);
1218   EXPECT_TRUE(bar_->message_type() == nullptr);
1219 
1220   EXPECT_EQ(foreign_, baz_->message_type());
1221   EXPECT_EQ(foreign_, moo_->message_type());
1222 }
1223 
TEST_F(DescriptorTest,FieldEnumType)1224 TEST_F(DescriptorTest, FieldEnumType) {
1225   EXPECT_TRUE(foo_->enum_type() == nullptr);
1226   EXPECT_TRUE(baz_->enum_type() == nullptr);
1227   EXPECT_TRUE(moo_->enum_type() == nullptr);
1228 
1229   EXPECT_EQ(enum_, bar_->enum_type());
1230 }
1231 
TEST_F(DescriptorTest,AbslStringifyWorks)1232 TEST_F(DescriptorTest, AbslStringifyWorks) {
1233   EXPECT_THAT(absl::StrFormat("%v", *message_),
1234               HasSubstr(message_->full_name()));
1235   EXPECT_THAT(absl::StrFormat("%v", *foo_), HasSubstr(foo_->name()));
1236 }
1237 
1238 
1239 // ===================================================================
1240 
1241 // Test simple flat messages and fields.
1242 class OneofDescriptorTest : public testing::Test {
1243  protected:
SetUp()1244   void SetUp() override {
1245     // Build descriptors for the following definitions:
1246     //
1247     //   package garply;
1248     //   message TestOneof {
1249     //     optional int32 a = 1;
1250     //     oneof foo {
1251     //       string b = 2;
1252     //       TestOneof c = 3;
1253     //     }
1254     //     oneof bar {
1255     //       float d = 4;
1256     //     }
1257     //   }
1258 
1259     FileDescriptorProto baz_file;
1260     baz_file.set_name("baz.proto");
1261     baz_file.set_package("garply");
1262 
1263     DescriptorProto* oneof_message = AddMessage(&baz_file, "TestOneof");
1264     oneof_message->add_oneof_decl()->set_name("foo");
1265     oneof_message->add_oneof_decl()->set_name("bar");
1266 
1267     AddField(oneof_message, "a", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1268              FieldDescriptorProto::TYPE_INT32);
1269     AddField(oneof_message, "b", 2, FieldDescriptorProto::LABEL_OPTIONAL,
1270              FieldDescriptorProto::TYPE_STRING);
1271     oneof_message->mutable_field(1)->set_oneof_index(0);
1272     AddField(oneof_message, "c", 3, FieldDescriptorProto::LABEL_OPTIONAL,
1273              FieldDescriptorProto::TYPE_MESSAGE);
1274     oneof_message->mutable_field(2)->set_oneof_index(0);
1275     oneof_message->mutable_field(2)->set_type_name("TestOneof");
1276 
1277     AddField(oneof_message, "d", 4, FieldDescriptorProto::LABEL_OPTIONAL,
1278              FieldDescriptorProto::TYPE_FLOAT);
1279     oneof_message->mutable_field(3)->set_oneof_index(1);
1280 
1281     // Build the descriptors and get the pointers.
1282     baz_file_ = pool_.BuildFile(baz_file);
1283     ASSERT_TRUE(baz_file_ != nullptr);
1284 
1285     ASSERT_EQ(1, baz_file_->message_type_count());
1286     oneof_message_ = baz_file_->message_type(0);
1287 
1288     ASSERT_EQ(2, oneof_message_->oneof_decl_count());
1289     oneof_ = oneof_message_->oneof_decl(0);
1290     oneof2_ = oneof_message_->oneof_decl(1);
1291 
1292     ASSERT_EQ(4, oneof_message_->field_count());
1293     a_ = oneof_message_->field(0);
1294     b_ = oneof_message_->field(1);
1295     c_ = oneof_message_->field(2);
1296     d_ = oneof_message_->field(3);
1297   }
1298 
1299   DescriptorPool pool_;
1300 
1301   const FileDescriptor* baz_file_;
1302 
1303   const Descriptor* oneof_message_;
1304 
1305   const OneofDescriptor* oneof_;
1306   const OneofDescriptor* oneof2_;
1307   const FieldDescriptor* a_;
1308   const FieldDescriptor* b_;
1309   const FieldDescriptor* c_;
1310   const FieldDescriptor* d_;
1311 };
1312 
TEST_F(OneofDescriptorTest,Normal)1313 TEST_F(OneofDescriptorTest, Normal) {
1314   EXPECT_EQ("foo", oneof_->name());
1315   EXPECT_EQ("garply.TestOneof.foo", oneof_->full_name());
1316   EXPECT_EQ(0, oneof_->index());
1317   ASSERT_EQ(2, oneof_->field_count());
1318   EXPECT_EQ(b_, oneof_->field(0));
1319   EXPECT_EQ(c_, oneof_->field(1));
1320   EXPECT_TRUE(a_->containing_oneof() == nullptr);
1321   EXPECT_EQ(oneof_, b_->containing_oneof());
1322   EXPECT_EQ(oneof_, c_->containing_oneof());
1323 }
1324 
TEST_F(OneofDescriptorTest,FindByName)1325 TEST_F(OneofDescriptorTest, FindByName) {
1326   EXPECT_EQ(oneof_, oneof_message_->FindOneofByName("foo"));
1327   EXPECT_EQ(oneof2_, oneof_message_->FindOneofByName("bar"));
1328   EXPECT_TRUE(oneof_message_->FindOneofByName("no_such_oneof") == nullptr);
1329 }
1330 
TEST_F(OneofDescriptorTest,AbslStringifyWorks)1331 TEST_F(OneofDescriptorTest, AbslStringifyWorks) {
1332   EXPECT_THAT(absl::StrFormat("%v", *oneof_), HasSubstr(oneof_->name()));
1333 }
1334 
1335 // ===================================================================
1336 
1337 class StylizedFieldNamesTest : public testing::Test {
1338  protected:
SetUp()1339   void SetUp() override {
1340     FileDescriptorProto file;
1341     file.set_name("foo.proto");
1342 
1343     AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000);
1344 
1345     DescriptorProto* message = AddMessage(&file, "TestMessage");
1346     PROTOBUF_IGNORE_DEPRECATION_START
1347     message->mutable_options()->set_deprecated_legacy_json_field_conflicts(
1348         true);
1349     PROTOBUF_IGNORE_DEPRECATION_STOP
1350     AddField(message, "foo_foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
1351              FieldDescriptorProto::TYPE_INT32);
1352     AddField(message, "FooBar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
1353              FieldDescriptorProto::TYPE_INT32);
1354     AddField(message, "fooBaz", 3, FieldDescriptorProto::LABEL_OPTIONAL,
1355              FieldDescriptorProto::TYPE_INT32);
1356     AddField(message, "fooFoo", 4,  // Camel-case conflict with foo_foo.
1357              FieldDescriptorProto::LABEL_OPTIONAL,
1358              FieldDescriptorProto::TYPE_INT32);
1359     AddField(message, "foobar", 5,  // Lower-case conflict with FooBar.
1360              FieldDescriptorProto::LABEL_OPTIONAL,
1361              FieldDescriptorProto::TYPE_INT32);
1362 
1363     AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1,
1364                        FieldDescriptorProto::LABEL_OPTIONAL,
1365                        FieldDescriptorProto::TYPE_INT32);
1366     AddNestedExtension(message, "ExtendableMessage", "BarBar", 2,
1367                        FieldDescriptorProto::LABEL_OPTIONAL,
1368                        FieldDescriptorProto::TYPE_INT32);
1369     AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3,
1370                        FieldDescriptorProto::LABEL_OPTIONAL,
1371                        FieldDescriptorProto::TYPE_INT32);
1372     AddNestedExtension(message, "ExtendableMessage", "barFoo", 4,  // Conflict
1373                        FieldDescriptorProto::LABEL_OPTIONAL,
1374                        FieldDescriptorProto::TYPE_INT32);
1375     AddNestedExtension(message, "ExtendableMessage", "barbar", 5,  // Conflict
1376                        FieldDescriptorProto::LABEL_OPTIONAL,
1377                        FieldDescriptorProto::TYPE_INT32);
1378 
1379     AddExtension(&file, "ExtendableMessage", "baz_foo", 11,
1380                  FieldDescriptorProto::LABEL_OPTIONAL,
1381                  FieldDescriptorProto::TYPE_INT32);
1382     AddExtension(&file, "ExtendableMessage", "BazBar", 12,
1383                  FieldDescriptorProto::LABEL_OPTIONAL,
1384                  FieldDescriptorProto::TYPE_INT32);
1385     AddExtension(&file, "ExtendableMessage", "BazBaz", 13,
1386                  FieldDescriptorProto::LABEL_OPTIONAL,
1387                  FieldDescriptorProto::TYPE_INT32);
1388     AddExtension(&file, "ExtendableMessage", "bazFoo", 14,  // Conflict
1389                  FieldDescriptorProto::LABEL_OPTIONAL,
1390                  FieldDescriptorProto::TYPE_INT32);
1391     AddExtension(&file, "ExtendableMessage", "bazbar", 15,  // Conflict
1392                  FieldDescriptorProto::LABEL_OPTIONAL,
1393                  FieldDescriptorProto::TYPE_INT32);
1394 
1395     file_ = pool_.BuildFile(file);
1396     ASSERT_TRUE(file_ != nullptr);
1397     ASSERT_EQ(2, file_->message_type_count());
1398     message_ = file_->message_type(1);
1399     ASSERT_EQ("TestMessage", message_->name());
1400     ASSERT_EQ(5, message_->field_count());
1401     ASSERT_EQ(5, message_->extension_count());
1402     ASSERT_EQ(5, file_->extension_count());
1403   }
1404 
1405   DescriptorPool pool_;
1406   const FileDescriptor* file_;
1407   const Descriptor* message_;
1408 };
1409 
TEST_F(StylizedFieldNamesTest,LowercaseName)1410 TEST_F(StylizedFieldNamesTest, LowercaseName) {
1411   EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name());
1412   EXPECT_EQ("foobar", message_->field(1)->lowercase_name());
1413   EXPECT_EQ("foobaz", message_->field(2)->lowercase_name());
1414   EXPECT_EQ("foofoo", message_->field(3)->lowercase_name());
1415   EXPECT_EQ("foobar", message_->field(4)->lowercase_name());
1416 
1417   EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name());
1418   EXPECT_EQ("barbar", message_->extension(1)->lowercase_name());
1419   EXPECT_EQ("barbaz", message_->extension(2)->lowercase_name());
1420   EXPECT_EQ("barfoo", message_->extension(3)->lowercase_name());
1421   EXPECT_EQ("barbar", message_->extension(4)->lowercase_name());
1422 
1423   EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name());
1424   EXPECT_EQ("bazbar", file_->extension(1)->lowercase_name());
1425   EXPECT_EQ("bazbaz", file_->extension(2)->lowercase_name());
1426   EXPECT_EQ("bazfoo", file_->extension(3)->lowercase_name());
1427   EXPECT_EQ("bazbar", file_->extension(4)->lowercase_name());
1428 }
1429 
TEST_F(StylizedFieldNamesTest,CamelcaseName)1430 TEST_F(StylizedFieldNamesTest, CamelcaseName) {
1431   EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name());
1432   EXPECT_EQ("fooBar", message_->field(1)->camelcase_name());
1433   EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name());
1434   EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name());
1435   EXPECT_EQ("foobar", message_->field(4)->camelcase_name());
1436 
1437   EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name());
1438   EXPECT_EQ("barBar", message_->extension(1)->camelcase_name());
1439   EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name());
1440   EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name());
1441   EXPECT_EQ("barbar", message_->extension(4)->camelcase_name());
1442 
1443   EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name());
1444   EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name());
1445   EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name());
1446   EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name());
1447   EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name());
1448 }
1449 
TEST_F(StylizedFieldNamesTest,FindByLowercaseName)1450 TEST_F(StylizedFieldNamesTest, FindByLowercaseName) {
1451   EXPECT_EQ(message_->field(0), message_->FindFieldByLowercaseName("foo_foo"));
1452   EXPECT_THAT(message_->FindFieldByLowercaseName("foobar"),
1453               AnyOf(message_->field(1), message_->field(4)));
1454   EXPECT_EQ(message_->field(2), message_->FindFieldByLowercaseName("foobaz"));
1455   EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == nullptr);
1456   EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == nullptr);
1457   EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == nullptr);
1458   EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == nullptr);
1459 
1460   EXPECT_EQ(message_->extension(0),
1461             message_->FindExtensionByLowercaseName("bar_foo"));
1462   EXPECT_THAT(message_->FindExtensionByLowercaseName("barbar"),
1463               AnyOf(message_->extension(1), message_->extension(4)));
1464   EXPECT_EQ(message_->extension(2),
1465             message_->FindExtensionByLowercaseName("barbaz"));
1466   EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == nullptr);
1467   EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == nullptr);
1468   EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == nullptr);
1469   EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == nullptr);
1470 
1471   EXPECT_EQ(file_->extension(0),
1472             file_->FindExtensionByLowercaseName("baz_foo"));
1473   EXPECT_THAT(file_->FindExtensionByLowercaseName("bazbar"),
1474               AnyOf(file_->extension(1), file_->extension(4)));
1475   EXPECT_EQ(file_->extension(2), file_->FindExtensionByLowercaseName("bazbaz"));
1476   EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == nullptr);
1477   EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == nullptr);
1478   EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == nullptr);
1479 }
1480 
TEST_F(StylizedFieldNamesTest,FindByCamelcaseName)1481 TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) {
1482   // Conflict (here, foo_foo and fooFoo) always resolves to the field with
1483   // the lower field number.
1484   EXPECT_EQ(message_->field(0), message_->FindFieldByCamelcaseName("fooFoo"));
1485   EXPECT_EQ(message_->field(1), message_->FindFieldByCamelcaseName("fooBar"));
1486   EXPECT_EQ(message_->field(2), message_->FindFieldByCamelcaseName("fooBaz"));
1487   EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == nullptr);
1488   EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == nullptr);
1489   EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == nullptr);
1490   EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == nullptr);
1491 
1492   // Conflict (here, bar_foo and barFoo) always resolves to the field with
1493   // the lower field number.
1494   EXPECT_EQ(message_->extension(0),
1495             message_->FindExtensionByCamelcaseName("barFoo"));
1496   EXPECT_EQ(message_->extension(1),
1497             message_->FindExtensionByCamelcaseName("barBar"));
1498   EXPECT_EQ(message_->extension(2),
1499             message_->FindExtensionByCamelcaseName("barBaz"));
1500   EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == nullptr);
1501   EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == nullptr);
1502   EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == nullptr);
1503   EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == nullptr);
1504 
1505   // Conflict (here, baz_foo and bazFoo) always resolves to the field with
1506   // the lower field number.
1507   EXPECT_EQ(file_->extension(0), file_->FindExtensionByCamelcaseName("bazFoo"));
1508   EXPECT_EQ(file_->extension(1), file_->FindExtensionByCamelcaseName("bazBar"));
1509   EXPECT_EQ(file_->extension(2), file_->FindExtensionByCamelcaseName("bazBaz"));
1510   EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == nullptr);
1511   EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == nullptr);
1512   EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == nullptr);
1513 }
1514 
1515 // ===================================================================
1516 
1517 // Test enum descriptors.
1518 class EnumDescriptorTest : public testing::Test {
1519  protected:
SetUp()1520   void SetUp() override {
1521     // Build descriptors for the following definitions:
1522     //
1523     //   // in "foo.proto"
1524     //   enum TestEnum {
1525     //     FOO = 1;
1526     //     BAR = 2;
1527     //   }
1528     //
1529     //   // in "bar.proto"
1530     //   package corge.grault;
1531     //   enum TestEnum2 {
1532     //     FOO = 1;
1533     //     BAZ = 3;
1534     //   }
1535     //
1536     // TestEnum2 is primarily here to test FindValueByName and friends.
1537     // All enums created from the same DescriptorPool share the same lookup
1538     // table, so we need to insure that they don't interfere.
1539 
1540     // TestEnum
1541     FileDescriptorProto foo_file;
1542     foo_file.set_name("foo.proto");
1543 
1544     EnumDescriptorProto* enum_proto = AddEnum(&foo_file, "TestEnum");
1545     AddEnumValue(enum_proto, "FOO", 1);
1546     AddEnumValue(enum_proto, "BAR", 2);
1547 
1548     // TestEnum2
1549     FileDescriptorProto bar_file;
1550     bar_file.set_name("bar.proto");
1551     bar_file.set_package("corge.grault");
1552 
1553     EnumDescriptorProto* enum2_proto = AddEnum(&bar_file, "TestEnum2");
1554     AddEnumValue(enum2_proto, "FOO", 1);
1555     AddEnumValue(enum2_proto, "BAZ", 3);
1556 
1557     // Build the descriptors and get the pointers.
1558     foo_file_ = pool_.BuildFile(foo_file);
1559     ASSERT_TRUE(foo_file_ != nullptr);
1560 
1561     bar_file_ = pool_.BuildFile(bar_file);
1562     ASSERT_TRUE(bar_file_ != nullptr);
1563 
1564     ASSERT_EQ(1, foo_file_->enum_type_count());
1565     enum_ = foo_file_->enum_type(0);
1566 
1567     ASSERT_EQ(2, enum_->value_count());
1568     foo_ = enum_->value(0);
1569     bar_ = enum_->value(1);
1570 
1571     ASSERT_EQ(1, bar_file_->enum_type_count());
1572     enum2_ = bar_file_->enum_type(0);
1573 
1574     ASSERT_EQ(2, enum2_->value_count());
1575     foo2_ = enum2_->value(0);
1576     baz2_ = enum2_->value(1);
1577   }
1578 
1579   DescriptorPool pool_;
1580 
1581   const FileDescriptor* foo_file_;
1582   const FileDescriptor* bar_file_;
1583 
1584   const EnumDescriptor* enum_;
1585   const EnumDescriptor* enum2_;
1586 
1587   const EnumValueDescriptor* foo_;
1588   const EnumValueDescriptor* bar_;
1589 
1590   const EnumValueDescriptor* foo2_;
1591   const EnumValueDescriptor* baz2_;
1592 };
1593 
TEST_F(EnumDescriptorTest,Name)1594 TEST_F(EnumDescriptorTest, Name) {
1595   EXPECT_EQ("TestEnum", enum_->name());
1596   EXPECT_EQ("TestEnum", enum_->full_name());
1597   EXPECT_EQ(foo_file_, enum_->file());
1598 
1599   EXPECT_EQ("TestEnum2", enum2_->name());
1600   EXPECT_EQ("corge.grault.TestEnum2", enum2_->full_name());
1601   EXPECT_EQ(bar_file_, enum2_->file());
1602 }
1603 
TEST_F(EnumDescriptorTest,ContainingType)1604 TEST_F(EnumDescriptorTest, ContainingType) {
1605   EXPECT_TRUE(enum_->containing_type() == nullptr);
1606   EXPECT_TRUE(enum2_->containing_type() == nullptr);
1607 }
1608 
TEST_F(EnumDescriptorTest,ValuesByIndex)1609 TEST_F(EnumDescriptorTest, ValuesByIndex) {
1610   ASSERT_EQ(2, enum_->value_count());
1611   EXPECT_EQ(foo_, enum_->value(0));
1612   EXPECT_EQ(bar_, enum_->value(1));
1613 }
1614 
TEST_F(EnumDescriptorTest,FindValueByName)1615 TEST_F(EnumDescriptorTest, FindValueByName) {
1616   EXPECT_EQ(foo_, enum_->FindValueByName("FOO"));
1617   EXPECT_EQ(bar_, enum_->FindValueByName("BAR"));
1618   EXPECT_EQ(foo2_, enum2_->FindValueByName("FOO"));
1619   EXPECT_EQ(baz2_, enum2_->FindValueByName("BAZ"));
1620 
1621   EXPECT_TRUE(enum_->FindValueByName("NO_SUCH_VALUE") == nullptr);
1622   EXPECT_TRUE(enum_->FindValueByName("BAZ") == nullptr);
1623   EXPECT_TRUE(enum2_->FindValueByName("BAR") == nullptr);
1624 }
1625 
TEST_F(EnumDescriptorTest,FindValueByNumber)1626 TEST_F(EnumDescriptorTest, FindValueByNumber) {
1627   EXPECT_EQ(foo_, enum_->FindValueByNumber(1));
1628   EXPECT_EQ(bar_, enum_->FindValueByNumber(2));
1629   EXPECT_EQ(foo2_, enum2_->FindValueByNumber(1));
1630   EXPECT_EQ(baz2_, enum2_->FindValueByNumber(3));
1631 
1632   EXPECT_TRUE(enum_->FindValueByNumber(416) == nullptr);
1633   EXPECT_TRUE(enum_->FindValueByNumber(3) == nullptr);
1634   EXPECT_TRUE(enum2_->FindValueByNumber(2) == nullptr);
1635 }
1636 
TEST_F(EnumDescriptorTest,ValueName)1637 TEST_F(EnumDescriptorTest, ValueName) {
1638   EXPECT_EQ("FOO", foo_->name());
1639   EXPECT_EQ("BAR", bar_->name());
1640 }
1641 
TEST_F(EnumDescriptorTest,ValueFullName)1642 TEST_F(EnumDescriptorTest, ValueFullName) {
1643   EXPECT_EQ("FOO", foo_->full_name());
1644   EXPECT_EQ("BAR", bar_->full_name());
1645   EXPECT_EQ("corge.grault.FOO", foo2_->full_name());
1646   EXPECT_EQ("corge.grault.BAZ", baz2_->full_name());
1647 }
1648 
TEST_F(EnumDescriptorTest,ValueIndex)1649 TEST_F(EnumDescriptorTest, ValueIndex) {
1650   EXPECT_EQ(0, foo_->index());
1651   EXPECT_EQ(1, bar_->index());
1652 }
1653 
TEST_F(EnumDescriptorTest,ValueNumber)1654 TEST_F(EnumDescriptorTest, ValueNumber) {
1655   EXPECT_EQ(1, foo_->number());
1656   EXPECT_EQ(2, bar_->number());
1657 }
1658 
TEST_F(EnumDescriptorTest,ValueType)1659 TEST_F(EnumDescriptorTest, ValueType) {
1660   EXPECT_EQ(enum_, foo_->type());
1661   EXPECT_EQ(enum_, bar_->type());
1662   EXPECT_EQ(enum2_, foo2_->type());
1663   EXPECT_EQ(enum2_, baz2_->type());
1664 }
1665 
TEST_F(EnumDescriptorTest,IsClosed)1666 TEST_F(EnumDescriptorTest, IsClosed) {
1667   // enum_ is proto2.
1668   EXPECT_TRUE(enum_->is_closed());
1669 
1670   // Make a proto3 version of enum_.
1671   FileDescriptorProto foo_file3;
1672   foo_file_->CopyTo(&foo_file3);
1673   foo_file3.set_syntax("proto3");
1674 
1675   // Make this valid proto3 by making the first enum value be zero.
1676   foo_file3.mutable_enum_type(0)->mutable_value(0)->set_number(0);
1677 
1678   DescriptorPool pool3;
1679   const EnumDescriptor* enum3 = pool3.BuildFile(foo_file3)->enum_type(0);
1680   EXPECT_FALSE(enum3->is_closed());
1681 }
1682 
TEST_F(EnumDescriptorTest,AbslStringifyWorks)1683 TEST_F(EnumDescriptorTest, AbslStringifyWorks) {
1684   EXPECT_THAT(absl::StrFormat("%v", *enum_), HasSubstr(enum_->full_name()));
1685   EXPECT_THAT(absl::StrFormat("%v", *foo_), HasSubstr(foo_->name()));
1686 }
1687 
1688 // ===================================================================
1689 
1690 // Test service descriptors.
1691 class ServiceDescriptorTest : public testing::Test {
1692  protected:
SetUp()1693   void SetUp() override {
1694     // Build descriptors for the following messages and service:
1695     //    // in "foo.proto"
1696     //    message FooRequest  {}
1697     //    message FooResponse {}
1698     //    message BarRequest  {}
1699     //    message BarResponse {}
1700     //    message BazRequest  {}
1701     //    message BazResponse {}
1702     //
1703     //    service TestService {
1704     //      rpc Foo(FooRequest) returns (FooResponse);
1705     //      rpc Bar(BarRequest) returns (BarResponse);
1706     //    }
1707     //
1708     //    // in "bar.proto"
1709     //    package corge.grault
1710     //    service TestService2 {
1711     //      rpc Foo(FooRequest) returns (FooResponse);
1712     //      rpc Baz(BazRequest) returns (BazResponse);
1713     //    }
1714 
1715     FileDescriptorProto foo_file;
1716     foo_file.set_name("foo.proto");
1717 
1718     AddMessage(&foo_file, "FooRequest");
1719     AddMessage(&foo_file, "FooResponse");
1720     AddMessage(&foo_file, "BarRequest");
1721     AddMessage(&foo_file, "BarResponse");
1722     AddMessage(&foo_file, "BazRequest");
1723     AddMessage(&foo_file, "BazResponse");
1724 
1725     ServiceDescriptorProto* service = AddService(&foo_file, "TestService");
1726     AddMethod(service, "Foo", "FooRequest", "FooResponse");
1727     AddMethod(service, "Bar", "BarRequest", "BarResponse");
1728 
1729     FileDescriptorProto bar_file;
1730     bar_file.set_name("bar.proto");
1731     bar_file.set_package("corge.grault");
1732     bar_file.add_dependency("foo.proto");
1733 
1734     ServiceDescriptorProto* service2 = AddService(&bar_file, "TestService2");
1735     AddMethod(service2, "Foo", "FooRequest", "FooResponse");
1736     AddMethod(service2, "Baz", "BazRequest", "BazResponse");
1737 
1738     // Build the descriptors and get the pointers.
1739     foo_file_ = pool_.BuildFile(foo_file);
1740     ASSERT_TRUE(foo_file_ != nullptr);
1741 
1742     bar_file_ = pool_.BuildFile(bar_file);
1743     ASSERT_TRUE(bar_file_ != nullptr);
1744 
1745     ASSERT_EQ(6, foo_file_->message_type_count());
1746     foo_request_ = foo_file_->message_type(0);
1747     foo_response_ = foo_file_->message_type(1);
1748     bar_request_ = foo_file_->message_type(2);
1749     bar_response_ = foo_file_->message_type(3);
1750     baz_request_ = foo_file_->message_type(4);
1751     baz_response_ = foo_file_->message_type(5);
1752 
1753     ASSERT_EQ(1, foo_file_->service_count());
1754     service_ = foo_file_->service(0);
1755 
1756     ASSERT_EQ(2, service_->method_count());
1757     foo_ = service_->method(0);
1758     bar_ = service_->method(1);
1759 
1760     ASSERT_EQ(1, bar_file_->service_count());
1761     service2_ = bar_file_->service(0);
1762 
1763     ASSERT_EQ(2, service2_->method_count());
1764     foo2_ = service2_->method(0);
1765     baz2_ = service2_->method(1);
1766   }
1767 
1768   DescriptorPool pool_;
1769 
1770   const FileDescriptor* foo_file_;
1771   const FileDescriptor* bar_file_;
1772 
1773   const Descriptor* foo_request_;
1774   const Descriptor* foo_response_;
1775   const Descriptor* bar_request_;
1776   const Descriptor* bar_response_;
1777   const Descriptor* baz_request_;
1778   const Descriptor* baz_response_;
1779 
1780   const ServiceDescriptor* service_;
1781   const ServiceDescriptor* service2_;
1782 
1783   const MethodDescriptor* foo_;
1784   const MethodDescriptor* bar_;
1785 
1786   const MethodDescriptor* foo2_;
1787   const MethodDescriptor* baz2_;
1788 };
1789 
TEST_F(ServiceDescriptorTest,Name)1790 TEST_F(ServiceDescriptorTest, Name) {
1791   EXPECT_EQ("TestService", service_->name());
1792   EXPECT_EQ("TestService", service_->full_name());
1793   EXPECT_EQ(foo_file_, service_->file());
1794 
1795   EXPECT_EQ("TestService2", service2_->name());
1796   EXPECT_EQ("corge.grault.TestService2", service2_->full_name());
1797   EXPECT_EQ(bar_file_, service2_->file());
1798 }
1799 
TEST_F(ServiceDescriptorTest,MethodsByIndex)1800 TEST_F(ServiceDescriptorTest, MethodsByIndex) {
1801   ASSERT_EQ(2, service_->method_count());
1802   EXPECT_EQ(foo_, service_->method(0));
1803   EXPECT_EQ(bar_, service_->method(1));
1804 }
1805 
TEST_F(ServiceDescriptorTest,FindMethodByName)1806 TEST_F(ServiceDescriptorTest, FindMethodByName) {
1807   EXPECT_EQ(foo_, service_->FindMethodByName("Foo"));
1808   EXPECT_EQ(bar_, service_->FindMethodByName("Bar"));
1809   EXPECT_EQ(foo2_, service2_->FindMethodByName("Foo"));
1810   EXPECT_EQ(baz2_, service2_->FindMethodByName("Baz"));
1811 
1812   EXPECT_TRUE(service_->FindMethodByName("NoSuchMethod") == nullptr);
1813   EXPECT_TRUE(service_->FindMethodByName("Baz") == nullptr);
1814   EXPECT_TRUE(service2_->FindMethodByName("Bar") == nullptr);
1815 }
1816 
TEST_F(ServiceDescriptorTest,MethodName)1817 TEST_F(ServiceDescriptorTest, MethodName) {
1818   EXPECT_EQ("Foo", foo_->name());
1819   EXPECT_EQ("Bar", bar_->name());
1820 }
TEST_F(ServiceDescriptorTest,MethodFullName)1821 TEST_F(ServiceDescriptorTest, MethodFullName) {
1822   EXPECT_EQ("TestService.Foo", foo_->full_name());
1823   EXPECT_EQ("TestService.Bar", bar_->full_name());
1824   EXPECT_EQ("corge.grault.TestService2.Foo", foo2_->full_name());
1825   EXPECT_EQ("corge.grault.TestService2.Baz", baz2_->full_name());
1826 }
1827 
TEST_F(ServiceDescriptorTest,MethodIndex)1828 TEST_F(ServiceDescriptorTest, MethodIndex) {
1829   EXPECT_EQ(0, foo_->index());
1830   EXPECT_EQ(1, bar_->index());
1831 }
1832 
TEST_F(ServiceDescriptorTest,MethodParent)1833 TEST_F(ServiceDescriptorTest, MethodParent) {
1834   EXPECT_EQ(service_, foo_->service());
1835   EXPECT_EQ(service_, bar_->service());
1836 }
1837 
TEST_F(ServiceDescriptorTest,MethodInputType)1838 TEST_F(ServiceDescriptorTest, MethodInputType) {
1839   EXPECT_EQ(foo_request_, foo_->input_type());
1840   EXPECT_EQ(bar_request_, bar_->input_type());
1841 }
1842 
TEST_F(ServiceDescriptorTest,MethodOutputType)1843 TEST_F(ServiceDescriptorTest, MethodOutputType) {
1844   EXPECT_EQ(foo_response_, foo_->output_type());
1845   EXPECT_EQ(bar_response_, bar_->output_type());
1846 }
1847 
TEST_F(ServiceDescriptorTest,AbslStringifyWorks)1848 TEST_F(ServiceDescriptorTest, AbslStringifyWorks) {
1849   EXPECT_THAT(absl::StrFormat("%v", *service_), HasSubstr(service_->name()));
1850   EXPECT_THAT(absl::StrFormat("%v", *foo_), HasSubstr(foo_->name()));
1851 }
1852 
1853 // ===================================================================
1854 
1855 // Test nested types.
1856 class NestedDescriptorTest : public testing::Test {
1857  protected:
SetUp()1858   void SetUp() override {
1859     // Build descriptors for the following definitions:
1860     //
1861     //   // in "foo.proto"
1862     //   message TestMessage {
1863     //     message Foo {}
1864     //     message Bar {}
1865     //     enum Baz { A = 1; }
1866     //     enum Moo { B = 1; }
1867     //   }
1868     //
1869     //   // in "bar.proto"
1870     //   package corge.grault;
1871     //   message TestMessage2 {
1872     //     message Foo {}
1873     //     message Baz {}
1874     //     enum Moo  { A = 1; }
1875     //     enum Mooo { C = 1; }
1876     //   }
1877     //
1878     // TestMessage2 is primarily here to test FindNestedTypeByName and friends.
1879     // All messages created from the same DescriptorPool share the same lookup
1880     // table, so we need to insure that they don't interfere.
1881     //
1882     // We add enum values to the enums in order to test searching for enum
1883     // values across a message's scope.
1884 
1885     FileDescriptorProto foo_file;
1886     foo_file.set_name("foo.proto");
1887 
1888     DescriptorProto* message = AddMessage(&foo_file, "TestMessage");
1889     AddNestedMessage(message, "Foo");
1890     AddNestedMessage(message, "Bar");
1891     EnumDescriptorProto* baz = AddNestedEnum(message, "Baz");
1892     AddEnumValue(baz, "A", 1);
1893     EnumDescriptorProto* moo = AddNestedEnum(message, "Moo");
1894     AddEnumValue(moo, "B", 1);
1895 
1896     FileDescriptorProto bar_file;
1897     bar_file.set_name("bar.proto");
1898     bar_file.set_package("corge.grault");
1899 
1900     DescriptorProto* message2 = AddMessage(&bar_file, "TestMessage2");
1901     AddNestedMessage(message2, "Foo");
1902     AddNestedMessage(message2, "Baz");
1903     EnumDescriptorProto* moo2 = AddNestedEnum(message2, "Moo");
1904     AddEnumValue(moo2, "A", 1);
1905     EnumDescriptorProto* mooo2 = AddNestedEnum(message2, "Mooo");
1906     AddEnumValue(mooo2, "C", 1);
1907 
1908     // Build the descriptors and get the pointers.
1909     foo_file_ = pool_.BuildFile(foo_file);
1910     ASSERT_TRUE(foo_file_ != nullptr);
1911 
1912     bar_file_ = pool_.BuildFile(bar_file);
1913     ASSERT_TRUE(bar_file_ != nullptr);
1914 
1915     ASSERT_EQ(1, foo_file_->message_type_count());
1916     message_ = foo_file_->message_type(0);
1917 
1918     ASSERT_EQ(2, message_->nested_type_count());
1919     foo_ = message_->nested_type(0);
1920     bar_ = message_->nested_type(1);
1921 
1922     ASSERT_EQ(2, message_->enum_type_count());
1923     baz_ = message_->enum_type(0);
1924     moo_ = message_->enum_type(1);
1925 
1926     ASSERT_EQ(1, baz_->value_count());
1927     a_ = baz_->value(0);
1928     ASSERT_EQ(1, moo_->value_count());
1929     b_ = moo_->value(0);
1930 
1931     ASSERT_EQ(1, bar_file_->message_type_count());
1932     message2_ = bar_file_->message_type(0);
1933 
1934     ASSERT_EQ(2, message2_->nested_type_count());
1935     foo2_ = message2_->nested_type(0);
1936     baz2_ = message2_->nested_type(1);
1937 
1938     ASSERT_EQ(2, message2_->enum_type_count());
1939     moo2_ = message2_->enum_type(0);
1940     mooo2_ = message2_->enum_type(1);
1941 
1942     ASSERT_EQ(1, moo2_->value_count());
1943     a2_ = moo2_->value(0);
1944     ASSERT_EQ(1, mooo2_->value_count());
1945     c2_ = mooo2_->value(0);
1946   }
1947 
1948   DescriptorPool pool_;
1949 
1950   const FileDescriptor* foo_file_;
1951   const FileDescriptor* bar_file_;
1952 
1953   const Descriptor* message_;
1954   const Descriptor* message2_;
1955 
1956   const Descriptor* foo_;
1957   const Descriptor* bar_;
1958   const EnumDescriptor* baz_;
1959   const EnumDescriptor* moo_;
1960   const EnumValueDescriptor* a_;
1961   const EnumValueDescriptor* b_;
1962 
1963   const Descriptor* foo2_;
1964   const Descriptor* baz2_;
1965   const EnumDescriptor* moo2_;
1966   const EnumDescriptor* mooo2_;
1967   const EnumValueDescriptor* a2_;
1968   const EnumValueDescriptor* c2_;
1969 };
1970 
TEST_F(NestedDescriptorTest,MessageName)1971 TEST_F(NestedDescriptorTest, MessageName) {
1972   EXPECT_EQ("Foo", foo_->name());
1973   EXPECT_EQ("Bar", bar_->name());
1974   EXPECT_EQ("Foo", foo2_->name());
1975   EXPECT_EQ("Baz", baz2_->name());
1976 
1977   EXPECT_EQ("TestMessage.Foo", foo_->full_name());
1978   EXPECT_EQ("TestMessage.Bar", bar_->full_name());
1979   EXPECT_EQ("corge.grault.TestMessage2.Foo", foo2_->full_name());
1980   EXPECT_EQ("corge.grault.TestMessage2.Baz", baz2_->full_name());
1981 }
1982 
TEST_F(NestedDescriptorTest,MessageContainingType)1983 TEST_F(NestedDescriptorTest, MessageContainingType) {
1984   EXPECT_EQ(message_, foo_->containing_type());
1985   EXPECT_EQ(message_, bar_->containing_type());
1986   EXPECT_EQ(message2_, foo2_->containing_type());
1987   EXPECT_EQ(message2_, baz2_->containing_type());
1988 }
1989 
TEST_F(NestedDescriptorTest,NestedMessagesByIndex)1990 TEST_F(NestedDescriptorTest, NestedMessagesByIndex) {
1991   ASSERT_EQ(2, message_->nested_type_count());
1992   EXPECT_EQ(foo_, message_->nested_type(0));
1993   EXPECT_EQ(bar_, message_->nested_type(1));
1994 }
1995 
TEST_F(NestedDescriptorTest,FindFieldByNameDoesntFindNestedTypes)1996 TEST_F(NestedDescriptorTest, FindFieldByNameDoesntFindNestedTypes) {
1997   EXPECT_TRUE(message_->FindFieldByName("Foo") == nullptr);
1998   EXPECT_TRUE(message_->FindFieldByName("Moo") == nullptr);
1999   EXPECT_TRUE(message_->FindExtensionByName("Foo") == nullptr);
2000   EXPECT_TRUE(message_->FindExtensionByName("Moo") == nullptr);
2001 }
2002 
TEST_F(NestedDescriptorTest,FindNestedTypeByName)2003 TEST_F(NestedDescriptorTest, FindNestedTypeByName) {
2004   EXPECT_EQ(foo_, message_->FindNestedTypeByName("Foo"));
2005   EXPECT_EQ(bar_, message_->FindNestedTypeByName("Bar"));
2006   EXPECT_EQ(foo2_, message2_->FindNestedTypeByName("Foo"));
2007   EXPECT_EQ(baz2_, message2_->FindNestedTypeByName("Baz"));
2008 
2009   EXPECT_TRUE(message_->FindNestedTypeByName("NoSuchType") == nullptr);
2010   EXPECT_TRUE(message_->FindNestedTypeByName("Baz") == nullptr);
2011   EXPECT_TRUE(message2_->FindNestedTypeByName("Bar") == nullptr);
2012 
2013   EXPECT_TRUE(message_->FindNestedTypeByName("Moo") == nullptr);
2014 }
2015 
TEST_F(NestedDescriptorTest,EnumName)2016 TEST_F(NestedDescriptorTest, EnumName) {
2017   EXPECT_EQ("Baz", baz_->name());
2018   EXPECT_EQ("Moo", moo_->name());
2019   EXPECT_EQ("Moo", moo2_->name());
2020   EXPECT_EQ("Mooo", mooo2_->name());
2021 
2022   EXPECT_EQ("TestMessage.Baz", baz_->full_name());
2023   EXPECT_EQ("TestMessage.Moo", moo_->full_name());
2024   EXPECT_EQ("corge.grault.TestMessage2.Moo", moo2_->full_name());
2025   EXPECT_EQ("corge.grault.TestMessage2.Mooo", mooo2_->full_name());
2026 }
2027 
TEST_F(NestedDescriptorTest,EnumContainingType)2028 TEST_F(NestedDescriptorTest, EnumContainingType) {
2029   EXPECT_EQ(message_, baz_->containing_type());
2030   EXPECT_EQ(message_, moo_->containing_type());
2031   EXPECT_EQ(message2_, moo2_->containing_type());
2032   EXPECT_EQ(message2_, mooo2_->containing_type());
2033 }
2034 
TEST_F(NestedDescriptorTest,NestedEnumsByIndex)2035 TEST_F(NestedDescriptorTest, NestedEnumsByIndex) {
2036   ASSERT_EQ(2, message_->nested_type_count());
2037   EXPECT_EQ(foo_, message_->nested_type(0));
2038   EXPECT_EQ(bar_, message_->nested_type(1));
2039 }
2040 
TEST_F(NestedDescriptorTest,FindEnumTypeByName)2041 TEST_F(NestedDescriptorTest, FindEnumTypeByName) {
2042   EXPECT_EQ(baz_, message_->FindEnumTypeByName("Baz"));
2043   EXPECT_EQ(moo_, message_->FindEnumTypeByName("Moo"));
2044   EXPECT_EQ(moo2_, message2_->FindEnumTypeByName("Moo"));
2045   EXPECT_EQ(mooo2_, message2_->FindEnumTypeByName("Mooo"));
2046 
2047   EXPECT_TRUE(message_->FindEnumTypeByName("NoSuchType") == nullptr);
2048   EXPECT_TRUE(message_->FindEnumTypeByName("Mooo") == nullptr);
2049   EXPECT_TRUE(message2_->FindEnumTypeByName("Baz") == nullptr);
2050 
2051   EXPECT_TRUE(message_->FindEnumTypeByName("Foo") == nullptr);
2052 }
2053 
TEST_F(NestedDescriptorTest,FindEnumValueByName)2054 TEST_F(NestedDescriptorTest, FindEnumValueByName) {
2055   EXPECT_EQ(a_, message_->FindEnumValueByName("A"));
2056   EXPECT_EQ(b_, message_->FindEnumValueByName("B"));
2057   EXPECT_EQ(a2_, message2_->FindEnumValueByName("A"));
2058   EXPECT_EQ(c2_, message2_->FindEnumValueByName("C"));
2059 
2060   EXPECT_TRUE(message_->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
2061   EXPECT_TRUE(message_->FindEnumValueByName("C") == nullptr);
2062   EXPECT_TRUE(message2_->FindEnumValueByName("B") == nullptr);
2063 
2064   EXPECT_TRUE(message_->FindEnumValueByName("Foo") == nullptr);
2065 }
2066 
2067 // ===================================================================
2068 
2069 // Test extensions.
2070 class ExtensionDescriptorTest : public testing::Test {
2071  protected:
SetUp()2072   void SetUp() override {
2073     // Build descriptors for the following definitions:
2074     //
2075     //   enum Baz {}
2076     //   message Moo {}
2077     //
2078     //   message Foo {
2079     //     extensions 10 to 19;
2080     //     extensions 30 to 39;
2081     //   }
2082     //   extend Foo {
2083     //     optional int32 foo_int32 = 10;
2084     //   }
2085     //   extend Foo {
2086     //     repeated TestEnum foo_enum = 19;
2087     //   }
2088     //   message Bar {
2089     //     optional int32 non_ext_int32 = 1;
2090     //     extend Foo {
2091     //       optional Moo foo_message = 30;
2092     //       repeated Moo foo_group = 39;  // (but internally set to TYPE_GROUP)
2093     //     }
2094     //   }
2095 
2096     FileDescriptorProto foo_file;
2097     foo_file.set_name("foo.proto");
2098 
2099     AddEmptyEnum(&foo_file, "Baz");
2100     AddMessage(&foo_file, "Moo");
2101 
2102     DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2103     AddExtensionRange(foo, 10, 20);
2104     AddExtensionRange(foo, 30, 40);
2105 
2106     AddExtension(&foo_file, "Foo", "foo_int32", 10,
2107                  FieldDescriptorProto::LABEL_OPTIONAL,
2108                  FieldDescriptorProto::TYPE_INT32);
2109     AddExtension(&foo_file, "Foo", "foo_enum", 19,
2110                  FieldDescriptorProto::LABEL_REPEATED,
2111                  FieldDescriptorProto::TYPE_ENUM)
2112         ->set_type_name("Baz");
2113 
2114     DescriptorProto* bar = AddMessage(&foo_file, "Bar");
2115     AddField(bar, "non_ext_int32", 1, FieldDescriptorProto::LABEL_OPTIONAL,
2116              FieldDescriptorProto::TYPE_INT32);
2117     AddNestedExtension(bar, "Foo", "foo_message", 30,
2118                        FieldDescriptorProto::LABEL_OPTIONAL,
2119                        FieldDescriptorProto::TYPE_MESSAGE)
2120         ->set_type_name("Moo");
2121     AddNestedExtension(bar, "Foo", "foo_group", 39,
2122                        FieldDescriptorProto::LABEL_REPEATED,
2123                        FieldDescriptorProto::TYPE_GROUP)
2124         ->set_type_name("Moo");
2125 
2126     // Build the descriptors and get the pointers.
2127     foo_file_ = pool_.BuildFile(foo_file);
2128     ASSERT_TRUE(foo_file_ != nullptr);
2129 
2130     ASSERT_EQ(1, foo_file_->enum_type_count());
2131     baz_ = foo_file_->enum_type(0);
2132 
2133     ASSERT_EQ(3, foo_file_->message_type_count());
2134     moo_ = foo_file_->message_type(0);
2135     foo_ = foo_file_->message_type(1);
2136     bar_ = foo_file_->message_type(2);
2137   }
2138 
2139   DescriptorPool pool_;
2140 
2141   const FileDescriptor* foo_file_;
2142 
2143   const Descriptor* foo_;
2144   const Descriptor* bar_;
2145   const EnumDescriptor* baz_;
2146   const Descriptor* moo_;
2147 };
2148 
TEST_F(ExtensionDescriptorTest,ExtensionRanges)2149 TEST_F(ExtensionDescriptorTest, ExtensionRanges) {
2150   EXPECT_EQ(0, bar_->extension_range_count());
2151   ASSERT_EQ(2, foo_->extension_range_count());
2152 
2153   EXPECT_EQ(10, foo_->extension_range(0)->start_number());
2154   EXPECT_EQ(30, foo_->extension_range(1)->start_number());
2155 
2156   EXPECT_EQ(20, foo_->extension_range(0)->end_number());
2157   EXPECT_EQ(40, foo_->extension_range(1)->end_number());
2158 }
2159 
TEST_F(ExtensionDescriptorTest,Extensions)2160 TEST_F(ExtensionDescriptorTest, Extensions) {
2161   EXPECT_EQ(0, foo_->extension_count());
2162   ASSERT_EQ(2, foo_file_->extension_count());
2163   ASSERT_EQ(2, bar_->extension_count());
2164 
2165   EXPECT_TRUE(foo_file_->extension(0)->is_extension());
2166   EXPECT_TRUE(foo_file_->extension(1)->is_extension());
2167   EXPECT_TRUE(bar_->extension(0)->is_extension());
2168   EXPECT_TRUE(bar_->extension(1)->is_extension());
2169 
2170   EXPECT_EQ("foo_int32", foo_file_->extension(0)->name());
2171   EXPECT_EQ("foo_enum", foo_file_->extension(1)->name());
2172   EXPECT_EQ("foo_message", bar_->extension(0)->name());
2173   EXPECT_EQ("foo_group", bar_->extension(1)->name());
2174 
2175   EXPECT_EQ(10, foo_file_->extension(0)->number());
2176   EXPECT_EQ(19, foo_file_->extension(1)->number());
2177   EXPECT_EQ(30, bar_->extension(0)->number());
2178   EXPECT_EQ(39, bar_->extension(1)->number());
2179 
2180   EXPECT_EQ(FieldDescriptor::TYPE_INT32, foo_file_->extension(0)->type());
2181   EXPECT_EQ(FieldDescriptor::TYPE_ENUM, foo_file_->extension(1)->type());
2182   EXPECT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_->extension(0)->type());
2183   EXPECT_EQ(FieldDescriptor::TYPE_GROUP, bar_->extension(1)->type());
2184 
2185   EXPECT_EQ(baz_, foo_file_->extension(1)->enum_type());
2186   EXPECT_EQ(moo_, bar_->extension(0)->message_type());
2187   EXPECT_EQ(moo_, bar_->extension(1)->message_type());
2188 
2189   EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, foo_file_->extension(0)->label());
2190   EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, foo_file_->extension(1)->label());
2191   EXPECT_EQ(FieldDescriptor::LABEL_OPTIONAL, bar_->extension(0)->label());
2192   EXPECT_EQ(FieldDescriptor::LABEL_REPEATED, bar_->extension(1)->label());
2193 
2194   EXPECT_EQ(foo_, foo_file_->extension(0)->containing_type());
2195   EXPECT_EQ(foo_, foo_file_->extension(1)->containing_type());
2196   EXPECT_EQ(foo_, bar_->extension(0)->containing_type());
2197   EXPECT_EQ(foo_, bar_->extension(1)->containing_type());
2198 
2199   EXPECT_TRUE(foo_file_->extension(0)->extension_scope() == nullptr);
2200   EXPECT_TRUE(foo_file_->extension(1)->extension_scope() == nullptr);
2201   EXPECT_EQ(bar_, bar_->extension(0)->extension_scope());
2202   EXPECT_EQ(bar_, bar_->extension(1)->extension_scope());
2203 }
2204 
TEST_F(ExtensionDescriptorTest,IsExtensionNumber)2205 TEST_F(ExtensionDescriptorTest, IsExtensionNumber) {
2206   EXPECT_FALSE(foo_->IsExtensionNumber(9));
2207   EXPECT_TRUE(foo_->IsExtensionNumber(10));
2208   EXPECT_TRUE(foo_->IsExtensionNumber(19));
2209   EXPECT_FALSE(foo_->IsExtensionNumber(20));
2210   EXPECT_FALSE(foo_->IsExtensionNumber(29));
2211   EXPECT_TRUE(foo_->IsExtensionNumber(30));
2212   EXPECT_TRUE(foo_->IsExtensionNumber(39));
2213   EXPECT_FALSE(foo_->IsExtensionNumber(40));
2214 }
2215 
TEST_F(ExtensionDescriptorTest,FindExtensionByName)2216 TEST_F(ExtensionDescriptorTest, FindExtensionByName) {
2217   // Note that FileDescriptor::FindExtensionByName() is tested by
2218   // FileDescriptorTest.
2219   ASSERT_EQ(2, bar_->extension_count());
2220 
2221   EXPECT_EQ(bar_->extension(0), bar_->FindExtensionByName("foo_message"));
2222   EXPECT_EQ(bar_->extension(1), bar_->FindExtensionByName("foo_group"));
2223 
2224   EXPECT_TRUE(bar_->FindExtensionByName("no_such_extension") == nullptr);
2225   EXPECT_TRUE(foo_->FindExtensionByName("foo_int32") == nullptr);
2226   EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == nullptr);
2227 }
2228 
TEST_F(ExtensionDescriptorTest,FieldVsExtension)2229 TEST_F(ExtensionDescriptorTest, FieldVsExtension) {
2230   EXPECT_EQ(foo_->FindFieldByName("foo_message"), nullptr);
2231   EXPECT_EQ(bar_->FindFieldByName("foo_message"), nullptr);
2232   EXPECT_NE(bar_->FindFieldByName("non_ext_int32"), nullptr);
2233   EXPECT_EQ(foo_->FindExtensionByName("foo_message"), nullptr);
2234   EXPECT_NE(bar_->FindExtensionByName("foo_message"), nullptr);
2235   EXPECT_EQ(bar_->FindExtensionByName("non_ext_int32"), nullptr);
2236 }
2237 
TEST_F(ExtensionDescriptorTest,FindExtensionByPrintableName)2238 TEST_F(ExtensionDescriptorTest, FindExtensionByPrintableName) {
2239   EXPECT_TRUE(pool_.FindExtensionByPrintableName(foo_, "no_such_extension") ==
2240               nullptr);
2241   EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "no_such_extension") ==
2242               nullptr);
2243 
2244   ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "Bar.foo_message") ==
2245                nullptr);
2246   ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "Bar.foo_group") ==
2247                nullptr);
2248   EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_message") ==
2249               nullptr);
2250   EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_group") == nullptr);
2251   EXPECT_EQ(bar_->FindExtensionByName("foo_message"),
2252             pool_.FindExtensionByPrintableName(foo_, "Bar.foo_message"));
2253   EXPECT_EQ(bar_->FindExtensionByName("foo_group"),
2254             pool_.FindExtensionByPrintableName(foo_, "Bar.foo_group"));
2255 
2256   ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "foo_int32") ==
2257                nullptr);
2258   ASSERT_FALSE(pool_.FindExtensionByPrintableName(foo_, "foo_enum") == nullptr);
2259   EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_int32") == nullptr);
2260   EXPECT_TRUE(pool_.FindExtensionByPrintableName(bar_, "foo_enum") == nullptr);
2261   EXPECT_EQ(foo_file_->FindExtensionByName("foo_int32"),
2262             pool_.FindExtensionByPrintableName(foo_, "foo_int32"));
2263   EXPECT_EQ(foo_file_->FindExtensionByName("foo_enum"),
2264             pool_.FindExtensionByPrintableName(foo_, "foo_enum"));
2265 }
2266 
TEST_F(ExtensionDescriptorTest,FindAllExtensions)2267 TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
2268   std::vector<const FieldDescriptor*> extensions;
2269   pool_.FindAllExtensions(foo_, &extensions);
2270   ASSERT_EQ(4, extensions.size());
2271   EXPECT_EQ(10, extensions[0]->number());
2272   EXPECT_EQ(19, extensions[1]->number());
2273   EXPECT_EQ(30, extensions[2]->number());
2274   EXPECT_EQ(39, extensions[3]->number());
2275 }
2276 
2277 
TEST_F(ExtensionDescriptorTest,DuplicateFieldNumber)2278 TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) {
2279   DescriptorPool pool;
2280   FileDescriptorProto file_proto;
2281   // Add "google/protobuf/descriptor.proto".
2282   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
2283   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
2284   // Add "foo.proto":
2285   //   import "google/protobuf/descriptor.proto";
2286   //   extend google.protobuf.FieldOptions {
2287   //     optional int32 option1 = 1000;
2288   //   }
2289   file_proto.Clear();
2290   file_proto.set_name("foo.proto");
2291   file_proto.add_dependency("google/protobuf/descriptor.proto");
2292   AddExtension(&file_proto, "google.protobuf.FieldOptions", "option1", 1000,
2293                FieldDescriptorProto::LABEL_OPTIONAL,
2294                FieldDescriptorProto::TYPE_INT32);
2295   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
2296   // Add "bar.proto":
2297   //   import "google/protobuf/descriptor.proto";
2298   //   extend google.protobuf.FieldOptions {
2299   //     optional int32 option2 = 1000;
2300   //   }
2301   file_proto.Clear();
2302   file_proto.set_name("bar.proto");
2303   file_proto.add_dependency("google/protobuf/descriptor.proto");
2304   AddExtension(&file_proto, "google.protobuf.FieldOptions", "option2", 1000,
2305                FieldDescriptorProto::LABEL_OPTIONAL,
2306                FieldDescriptorProto::TYPE_INT32);
2307   // Currently we only generate a warning for conflicting extension numbers.
2308   // TODO: Change it to an error.
2309   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
2310 }
2311 
2312 // ===================================================================
2313 
2314 // Ensure that overlapping extension ranges are not allowed.
TEST(OverlappingExtensionRangeTest,ExtensionRangeInternal)2315 TEST(OverlappingExtensionRangeTest, ExtensionRangeInternal) {
2316   // Build descriptors for the following definitions:
2317   //
2318   //   message Foo {
2319   //     extensions 10 to 19;
2320   //     extensions 15;
2321   //   }
2322   FileDescriptorProto foo_file;
2323   foo_file.set_name("foo.proto");
2324 
2325   DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2326   AddExtensionRange(foo, 10, 20);
2327   AddExtensionRange(foo, 15, 16);
2328 
2329   DescriptorPool pool;
2330   MockErrorCollector error_collector;
2331   // The extensions ranges are invalid, so the proto shouldn't build.
2332   ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
2333               nullptr);
2334   ASSERT_EQ(
2335       "foo.proto: Foo: NUMBER: Extension range 15 to 15 overlaps with "
2336       "already-defined range 10 to 19.\n",
2337       error_collector.text_);
2338 }
2339 
TEST(OverlappingExtensionRangeTest,ExtensionRangeAfter)2340 TEST(OverlappingExtensionRangeTest, ExtensionRangeAfter) {
2341   // Build descriptors for the following definitions:
2342   //
2343   //   message Foo {
2344   //     extensions 10 to 19;
2345   //     extensions 15 to 24;
2346   //   }
2347   FileDescriptorProto foo_file;
2348   foo_file.set_name("foo.proto");
2349 
2350   DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2351   AddExtensionRange(foo, 10, 20);
2352   AddExtensionRange(foo, 15, 25);
2353 
2354   DescriptorPool pool;
2355   MockErrorCollector error_collector;
2356   // The extensions ranges are invalid, so the proto shouldn't build.
2357   ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
2358               nullptr);
2359   ASSERT_EQ(
2360       "foo.proto: Foo: NUMBER: Extension range 15 to 24 overlaps with "
2361       "already-defined range 10 to 19.\n",
2362       error_collector.text_);
2363 }
2364 
TEST(OverlappingExtensionRangeTest,ExtensionRangeBefore)2365 TEST(OverlappingExtensionRangeTest, ExtensionRangeBefore) {
2366   // Build descriptors for the following definitions:
2367   //
2368   //   message Foo {
2369   //     extensions 10 to 19;
2370   //     extensions 5 to 14;
2371   //   }
2372   FileDescriptorProto foo_file;
2373   foo_file.set_name("foo.proto");
2374 
2375   DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2376   AddExtensionRange(foo, 10, 20);
2377   AddExtensionRange(foo, 5, 15);
2378 
2379   DescriptorPool pool;
2380   MockErrorCollector error_collector;
2381   // The extensions ranges are invalid, so the proto shouldn't build.
2382   ASSERT_TRUE(pool.BuildFileCollectingErrors(foo_file, &error_collector) ==
2383               nullptr);
2384   ASSERT_EQ(
2385       "foo.proto: Foo: NUMBER: Extension range 5 to 14 overlaps with "
2386       "already-defined range 10 to 19.\n",
2387       error_collector.text_);
2388 }
2389 
2390 // ===================================================================
2391 
2392 // Test reserved fields.
2393 class ReservedDescriptorTest : public testing::Test {
2394  protected:
SetUp()2395   void SetUp() override {
2396     // Build descriptors for the following definitions:
2397     //
2398     //   message Foo {
2399     //     reserved 2, 9 to 11, 15;
2400     //     reserved "foo", "bar";
2401     //   }
2402 
2403     FileDescriptorProto foo_file;
2404     foo_file.set_name("foo.proto");
2405 
2406     DescriptorProto* foo = AddMessage(&foo_file, "Foo");
2407     AddReservedRange(foo, 2, 3);
2408     AddReservedRange(foo, 9, 12);
2409     AddReservedRange(foo, 15, 16);
2410 
2411     foo->add_reserved_name("foo");
2412     foo->add_reserved_name("bar");
2413 
2414     // Build the descriptors and get the pointers.
2415     foo_file_ = pool_.BuildFile(foo_file);
2416     ASSERT_TRUE(foo_file_ != nullptr);
2417 
2418     ASSERT_EQ(1, foo_file_->message_type_count());
2419     foo_ = foo_file_->message_type(0);
2420   }
2421 
2422   DescriptorPool pool_;
2423   const FileDescriptor* foo_file_;
2424   const Descriptor* foo_;
2425 };
2426 
TEST_F(ReservedDescriptorTest,ReservedRanges)2427 TEST_F(ReservedDescriptorTest, ReservedRanges) {
2428   ASSERT_EQ(3, foo_->reserved_range_count());
2429 
2430   EXPECT_EQ(2, foo_->reserved_range(0)->start);
2431   EXPECT_EQ(3, foo_->reserved_range(0)->end);
2432 
2433   EXPECT_EQ(9, foo_->reserved_range(1)->start);
2434   EXPECT_EQ(12, foo_->reserved_range(1)->end);
2435 
2436   EXPECT_EQ(15, foo_->reserved_range(2)->start);
2437   EXPECT_EQ(16, foo_->reserved_range(2)->end);
2438 }
2439 
TEST_F(ReservedDescriptorTest,IsReservedNumber)2440 TEST_F(ReservedDescriptorTest, IsReservedNumber) {
2441   EXPECT_FALSE(foo_->IsReservedNumber(1));
2442   EXPECT_TRUE(foo_->IsReservedNumber(2));
2443   EXPECT_FALSE(foo_->IsReservedNumber(3));
2444   EXPECT_FALSE(foo_->IsReservedNumber(8));
2445   EXPECT_TRUE(foo_->IsReservedNumber(9));
2446   EXPECT_TRUE(foo_->IsReservedNumber(10));
2447   EXPECT_TRUE(foo_->IsReservedNumber(11));
2448   EXPECT_FALSE(foo_->IsReservedNumber(12));
2449   EXPECT_FALSE(foo_->IsReservedNumber(13));
2450   EXPECT_FALSE(foo_->IsReservedNumber(14));
2451   EXPECT_TRUE(foo_->IsReservedNumber(15));
2452   EXPECT_FALSE(foo_->IsReservedNumber(16));
2453 }
2454 
TEST_F(ReservedDescriptorTest,ReservedNames)2455 TEST_F(ReservedDescriptorTest, ReservedNames) {
2456   ASSERT_EQ(2, foo_->reserved_name_count());
2457 
2458   EXPECT_EQ("foo", foo_->reserved_name(0));
2459   EXPECT_EQ("bar", foo_->reserved_name(1));
2460 }
2461 
TEST_F(ReservedDescriptorTest,IsReservedName)2462 TEST_F(ReservedDescriptorTest, IsReservedName) {
2463   EXPECT_TRUE(foo_->IsReservedName("foo"));
2464   EXPECT_TRUE(foo_->IsReservedName("bar"));
2465   EXPECT_FALSE(foo_->IsReservedName("baz"));
2466 }
2467 
2468 // ===================================================================
2469 
2470 // Test reserved enum fields.
2471 class ReservedEnumDescriptorTest : public testing::Test {
2472  protected:
SetUp()2473   void SetUp() override {
2474     // Build descriptors for the following definitions:
2475     //
2476     //   enum Foo {
2477     //     BAR = 1;
2478     //     reserved 2, 9 to 11, 15;
2479     //     reserved "foo", "bar";
2480     //   }
2481 
2482     FileDescriptorProto foo_file;
2483     foo_file.set_name("foo.proto");
2484 
2485     EnumDescriptorProto* foo = AddEnum(&foo_file, "Foo");
2486     EnumDescriptorProto* edge1 = AddEnum(&foo_file, "Edge1");
2487     EnumDescriptorProto* edge2 = AddEnum(&foo_file, "Edge2");
2488 
2489     AddEnumValue(foo, "BAR", 4);
2490     AddReservedRange(foo, -5, -3);
2491     AddReservedRange(foo, -2, 1);
2492     AddReservedRange(foo, 2, 3);
2493     AddReservedRange(foo, 9, 12);
2494     AddReservedRange(foo, 15, 16);
2495 
2496     foo->add_reserved_name("foo");
2497     foo->add_reserved_name("bar");
2498 
2499     // Some additional edge cases that cover most or all of the range of enum
2500     // values
2501 
2502     // Note: We use INT_MAX as the maximum reserved range upper bound,
2503     // inclusive.
2504     AddEnumValue(edge1, "EDGE1", 1);
2505     AddReservedRange(edge1, 10, INT_MAX);
2506     AddEnumValue(edge2, "EDGE2", 15);
2507     AddReservedRange(edge2, INT_MIN, 10);
2508 
2509     // Build the descriptors and get the pointers.
2510     foo_file_ = pool_.BuildFile(foo_file);
2511     ASSERT_TRUE(foo_file_ != nullptr);
2512 
2513     ASSERT_EQ(3, foo_file_->enum_type_count());
2514     foo_ = foo_file_->enum_type(0);
2515     edge1_ = foo_file_->enum_type(1);
2516     edge2_ = foo_file_->enum_type(2);
2517   }
2518 
2519   DescriptorPool pool_;
2520   const FileDescriptor* foo_file_;
2521   const EnumDescriptor* foo_;
2522   const EnumDescriptor* edge1_;
2523   const EnumDescriptor* edge2_;
2524 };
2525 
TEST_F(ReservedEnumDescriptorTest,ReservedRanges)2526 TEST_F(ReservedEnumDescriptorTest, ReservedRanges) {
2527   ASSERT_EQ(5, foo_->reserved_range_count());
2528 
2529   EXPECT_EQ(-5, foo_->reserved_range(0)->start);
2530   EXPECT_EQ(-3, foo_->reserved_range(0)->end);
2531 
2532   EXPECT_EQ(-2, foo_->reserved_range(1)->start);
2533   EXPECT_EQ(1, foo_->reserved_range(1)->end);
2534 
2535   EXPECT_EQ(2, foo_->reserved_range(2)->start);
2536   EXPECT_EQ(3, foo_->reserved_range(2)->end);
2537 
2538   EXPECT_EQ(9, foo_->reserved_range(3)->start);
2539   EXPECT_EQ(12, foo_->reserved_range(3)->end);
2540 
2541   EXPECT_EQ(15, foo_->reserved_range(4)->start);
2542   EXPECT_EQ(16, foo_->reserved_range(4)->end);
2543 
2544   ASSERT_EQ(1, edge1_->reserved_range_count());
2545   EXPECT_EQ(10, edge1_->reserved_range(0)->start);
2546   EXPECT_EQ(INT_MAX, edge1_->reserved_range(0)->end);
2547 
2548   ASSERT_EQ(1, edge2_->reserved_range_count());
2549   EXPECT_EQ(INT_MIN, edge2_->reserved_range(0)->start);
2550   EXPECT_EQ(10, edge2_->reserved_range(0)->end);
2551 }
2552 
TEST_F(ReservedEnumDescriptorTest,IsReservedNumber)2553 TEST_F(ReservedEnumDescriptorTest, IsReservedNumber) {
2554   EXPECT_TRUE(foo_->IsReservedNumber(-5));
2555   EXPECT_TRUE(foo_->IsReservedNumber(-4));
2556   EXPECT_TRUE(foo_->IsReservedNumber(-3));
2557   EXPECT_TRUE(foo_->IsReservedNumber(-2));
2558   EXPECT_TRUE(foo_->IsReservedNumber(-1));
2559   EXPECT_TRUE(foo_->IsReservedNumber(0));
2560   EXPECT_TRUE(foo_->IsReservedNumber(1));
2561   EXPECT_TRUE(foo_->IsReservedNumber(2));
2562   EXPECT_TRUE(foo_->IsReservedNumber(3));
2563   EXPECT_FALSE(foo_->IsReservedNumber(8));
2564   EXPECT_TRUE(foo_->IsReservedNumber(9));
2565   EXPECT_TRUE(foo_->IsReservedNumber(10));
2566   EXPECT_TRUE(foo_->IsReservedNumber(11));
2567   EXPECT_TRUE(foo_->IsReservedNumber(12));
2568   EXPECT_FALSE(foo_->IsReservedNumber(13));
2569   EXPECT_FALSE(foo_->IsReservedNumber(13));
2570   EXPECT_FALSE(foo_->IsReservedNumber(14));
2571   EXPECT_TRUE(foo_->IsReservedNumber(15));
2572   EXPECT_TRUE(foo_->IsReservedNumber(16));
2573   EXPECT_FALSE(foo_->IsReservedNumber(17));
2574 
2575   EXPECT_FALSE(edge1_->IsReservedNumber(9));
2576   EXPECT_TRUE(edge1_->IsReservedNumber(10));
2577   EXPECT_TRUE(edge1_->IsReservedNumber(INT_MAX - 1));
2578   EXPECT_TRUE(edge1_->IsReservedNumber(INT_MAX));
2579 
2580   EXPECT_TRUE(edge2_->IsReservedNumber(INT_MIN));
2581   EXPECT_TRUE(edge2_->IsReservedNumber(9));
2582   EXPECT_TRUE(edge2_->IsReservedNumber(10));
2583   EXPECT_FALSE(edge2_->IsReservedNumber(11));
2584 }
2585 
TEST_F(ReservedEnumDescriptorTest,ReservedNames)2586 TEST_F(ReservedEnumDescriptorTest, ReservedNames) {
2587   ASSERT_EQ(2, foo_->reserved_name_count());
2588 
2589   EXPECT_EQ("foo", foo_->reserved_name(0));
2590   EXPECT_EQ("bar", foo_->reserved_name(1));
2591 }
2592 
TEST_F(ReservedEnumDescriptorTest,IsReservedName)2593 TEST_F(ReservedEnumDescriptorTest, IsReservedName) {
2594   EXPECT_TRUE(foo_->IsReservedName("foo"));
2595   EXPECT_TRUE(foo_->IsReservedName("bar"));
2596   EXPECT_FALSE(foo_->IsReservedName("baz"));
2597 }
2598 
2599 // ===================================================================
2600 
2601 class MiscTest : public testing::Test {
2602  protected:
2603   // Function which makes a field descriptor of the given type.
GetFieldDescriptorOfType(FieldDescriptor::Type type)2604   const FieldDescriptor* GetFieldDescriptorOfType(FieldDescriptor::Type type) {
2605     FileDescriptorProto file_proto;
2606     file_proto.set_name("foo.proto");
2607     AddEmptyEnum(&file_proto, "DummyEnum");
2608 
2609     DescriptorProto* message = AddMessage(&file_proto, "TestMessage");
2610     FieldDescriptorProto* field = AddField(
2611         message, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
2612         static_cast<FieldDescriptorProto::Type>(static_cast<int>(type)));
2613 
2614     if (type == FieldDescriptor::TYPE_MESSAGE ||
2615         type == FieldDescriptor::TYPE_GROUP) {
2616       field->set_type_name("TestMessage");
2617     } else if (type == FieldDescriptor::TYPE_ENUM) {
2618       field->set_type_name("DummyEnum");
2619     }
2620 
2621     // Build the descriptors and get the pointers.
2622     pool_ = std::make_unique<DescriptorPool>();
2623     const FileDescriptor* file = pool_->BuildFile(file_proto);
2624 
2625     if (file != nullptr && file->message_type_count() == 1 &&
2626         file->message_type(0)->field_count() == 1) {
2627       return file->message_type(0)->field(0);
2628     } else {
2629       return nullptr;
2630     }
2631   }
2632 
GetTypeNameForFieldType(FieldDescriptor::Type type)2633   const char* GetTypeNameForFieldType(FieldDescriptor::Type type) {
2634     const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2635     return field != nullptr ? field->type_name() : "";
2636   }
2637 
GetCppTypeForFieldType(FieldDescriptor::Type type)2638   FieldDescriptor::CppType GetCppTypeForFieldType(FieldDescriptor::Type type) {
2639     const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2640     return field != nullptr ? field->cpp_type()
2641                             : static_cast<FieldDescriptor::CppType>(0);
2642   }
2643 
GetCppTypeNameForFieldType(FieldDescriptor::Type type)2644   const char* GetCppTypeNameForFieldType(FieldDescriptor::Type type) {
2645     const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2646     return field != nullptr ? field->cpp_type_name() : "";
2647   }
2648 
GetMessageDescriptorForFieldType(FieldDescriptor::Type type)2649   const Descriptor* GetMessageDescriptorForFieldType(
2650       FieldDescriptor::Type type) {
2651     const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2652     return field != nullptr ? field->message_type() : nullptr;
2653   }
2654 
GetEnumDescriptorForFieldType(FieldDescriptor::Type type)2655   const EnumDescriptor* GetEnumDescriptorForFieldType(
2656       FieldDescriptor::Type type) {
2657     const FieldDescriptor* field = GetFieldDescriptorOfType(type);
2658     return field != nullptr ? field->enum_type() : nullptr;
2659   }
2660 
2661   std::unique_ptr<DescriptorPool> pool_;
2662 };
2663 
TEST_F(MiscTest,TypeNames)2664 TEST_F(MiscTest, TypeNames) {
2665   // Test that correct type names are returned.
2666 
2667   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2668 
2669   EXPECT_STREQ("double", GetTypeNameForFieldType(FD::TYPE_DOUBLE));
2670   EXPECT_STREQ("float", GetTypeNameForFieldType(FD::TYPE_FLOAT));
2671   EXPECT_STREQ("int64", GetTypeNameForFieldType(FD::TYPE_INT64));
2672   EXPECT_STREQ("uint64", GetTypeNameForFieldType(FD::TYPE_UINT64));
2673   EXPECT_STREQ("int32", GetTypeNameForFieldType(FD::TYPE_INT32));
2674   EXPECT_STREQ("fixed64", GetTypeNameForFieldType(FD::TYPE_FIXED64));
2675   EXPECT_STREQ("fixed32", GetTypeNameForFieldType(FD::TYPE_FIXED32));
2676   EXPECT_STREQ("bool", GetTypeNameForFieldType(FD::TYPE_BOOL));
2677   EXPECT_STREQ("string", GetTypeNameForFieldType(FD::TYPE_STRING));
2678   EXPECT_STREQ("group", GetTypeNameForFieldType(FD::TYPE_GROUP));
2679   EXPECT_STREQ("message", GetTypeNameForFieldType(FD::TYPE_MESSAGE));
2680   EXPECT_STREQ("bytes", GetTypeNameForFieldType(FD::TYPE_BYTES));
2681   EXPECT_STREQ("uint32", GetTypeNameForFieldType(FD::TYPE_UINT32));
2682   EXPECT_STREQ("enum", GetTypeNameForFieldType(FD::TYPE_ENUM));
2683   EXPECT_STREQ("sfixed32", GetTypeNameForFieldType(FD::TYPE_SFIXED32));
2684   EXPECT_STREQ("sfixed64", GetTypeNameForFieldType(FD::TYPE_SFIXED64));
2685   EXPECT_STREQ("sint32", GetTypeNameForFieldType(FD::TYPE_SINT32));
2686   EXPECT_STREQ("sint64", GetTypeNameForFieldType(FD::TYPE_SINT64));
2687 }
2688 
TEST_F(MiscTest,StaticTypeNames)2689 TEST_F(MiscTest, StaticTypeNames) {
2690   // Test that correct type names are returned.
2691 
2692   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2693 
2694   EXPECT_STREQ("double", FD::TypeName(FD::TYPE_DOUBLE));
2695   EXPECT_STREQ("float", FD::TypeName(FD::TYPE_FLOAT));
2696   EXPECT_STREQ("int64", FD::TypeName(FD::TYPE_INT64));
2697   EXPECT_STREQ("uint64", FD::TypeName(FD::TYPE_UINT64));
2698   EXPECT_STREQ("int32", FD::TypeName(FD::TYPE_INT32));
2699   EXPECT_STREQ("fixed64", FD::TypeName(FD::TYPE_FIXED64));
2700   EXPECT_STREQ("fixed32", FD::TypeName(FD::TYPE_FIXED32));
2701   EXPECT_STREQ("bool", FD::TypeName(FD::TYPE_BOOL));
2702   EXPECT_STREQ("string", FD::TypeName(FD::TYPE_STRING));
2703   EXPECT_STREQ("group", FD::TypeName(FD::TYPE_GROUP));
2704   EXPECT_STREQ("message", FD::TypeName(FD::TYPE_MESSAGE));
2705   EXPECT_STREQ("bytes", FD::TypeName(FD::TYPE_BYTES));
2706   EXPECT_STREQ("uint32", FD::TypeName(FD::TYPE_UINT32));
2707   EXPECT_STREQ("enum", FD::TypeName(FD::TYPE_ENUM));
2708   EXPECT_STREQ("sfixed32", FD::TypeName(FD::TYPE_SFIXED32));
2709   EXPECT_STREQ("sfixed64", FD::TypeName(FD::TYPE_SFIXED64));
2710   EXPECT_STREQ("sint32", FD::TypeName(FD::TYPE_SINT32));
2711   EXPECT_STREQ("sint64", FD::TypeName(FD::TYPE_SINT64));
2712 }
2713 
TEST_F(MiscTest,CppTypes)2714 TEST_F(MiscTest, CppTypes) {
2715   // Test that CPP types are assigned correctly.
2716 
2717   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2718 
2719   EXPECT_EQ(FD::CPPTYPE_DOUBLE, GetCppTypeForFieldType(FD::TYPE_DOUBLE));
2720   EXPECT_EQ(FD::CPPTYPE_FLOAT, GetCppTypeForFieldType(FD::TYPE_FLOAT));
2721   EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_INT64));
2722   EXPECT_EQ(FD::CPPTYPE_UINT64, GetCppTypeForFieldType(FD::TYPE_UINT64));
2723   EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_INT32));
2724   EXPECT_EQ(FD::CPPTYPE_UINT64, GetCppTypeForFieldType(FD::TYPE_FIXED64));
2725   EXPECT_EQ(FD::CPPTYPE_UINT32, GetCppTypeForFieldType(FD::TYPE_FIXED32));
2726   EXPECT_EQ(FD::CPPTYPE_BOOL, GetCppTypeForFieldType(FD::TYPE_BOOL));
2727   EXPECT_EQ(FD::CPPTYPE_STRING, GetCppTypeForFieldType(FD::TYPE_STRING));
2728   EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_GROUP));
2729   EXPECT_EQ(FD::CPPTYPE_MESSAGE, GetCppTypeForFieldType(FD::TYPE_MESSAGE));
2730   EXPECT_EQ(FD::CPPTYPE_STRING, GetCppTypeForFieldType(FD::TYPE_BYTES));
2731   EXPECT_EQ(FD::CPPTYPE_UINT32, GetCppTypeForFieldType(FD::TYPE_UINT32));
2732   EXPECT_EQ(FD::CPPTYPE_ENUM, GetCppTypeForFieldType(FD::TYPE_ENUM));
2733   EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_SFIXED32));
2734   EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_SFIXED64));
2735   EXPECT_EQ(FD::CPPTYPE_INT32, GetCppTypeForFieldType(FD::TYPE_SINT32));
2736   EXPECT_EQ(FD::CPPTYPE_INT64, GetCppTypeForFieldType(FD::TYPE_SINT64));
2737 }
2738 
TEST_F(MiscTest,CppTypeNames)2739 TEST_F(MiscTest, CppTypeNames) {
2740   // Test that correct CPP type names are returned.
2741 
2742   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2743 
2744   EXPECT_STREQ("double", GetCppTypeNameForFieldType(FD::TYPE_DOUBLE));
2745   EXPECT_STREQ("float", GetCppTypeNameForFieldType(FD::TYPE_FLOAT));
2746   EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_INT64));
2747   EXPECT_STREQ("uint64", GetCppTypeNameForFieldType(FD::TYPE_UINT64));
2748   EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_INT32));
2749   EXPECT_STREQ("uint64", GetCppTypeNameForFieldType(FD::TYPE_FIXED64));
2750   EXPECT_STREQ("uint32", GetCppTypeNameForFieldType(FD::TYPE_FIXED32));
2751   EXPECT_STREQ("bool", GetCppTypeNameForFieldType(FD::TYPE_BOOL));
2752   EXPECT_STREQ("string", GetCppTypeNameForFieldType(FD::TYPE_STRING));
2753   EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_GROUP));
2754   EXPECT_STREQ("message", GetCppTypeNameForFieldType(FD::TYPE_MESSAGE));
2755   EXPECT_STREQ("string", GetCppTypeNameForFieldType(FD::TYPE_BYTES));
2756   EXPECT_STREQ("uint32", GetCppTypeNameForFieldType(FD::TYPE_UINT32));
2757   EXPECT_STREQ("enum", GetCppTypeNameForFieldType(FD::TYPE_ENUM));
2758   EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_SFIXED32));
2759   EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_SFIXED64));
2760   EXPECT_STREQ("int32", GetCppTypeNameForFieldType(FD::TYPE_SINT32));
2761   EXPECT_STREQ("int64", GetCppTypeNameForFieldType(FD::TYPE_SINT64));
2762 }
2763 
TEST_F(MiscTest,StaticCppTypeNames)2764 TEST_F(MiscTest, StaticCppTypeNames) {
2765   // Test that correct CPP type names are returned.
2766 
2767   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2768 
2769   EXPECT_STREQ("int32", FD::CppTypeName(FD::CPPTYPE_INT32));
2770   EXPECT_STREQ("int64", FD::CppTypeName(FD::CPPTYPE_INT64));
2771   EXPECT_STREQ("uint32", FD::CppTypeName(FD::CPPTYPE_UINT32));
2772   EXPECT_STREQ("uint64", FD::CppTypeName(FD::CPPTYPE_UINT64));
2773   EXPECT_STREQ("double", FD::CppTypeName(FD::CPPTYPE_DOUBLE));
2774   EXPECT_STREQ("float", FD::CppTypeName(FD::CPPTYPE_FLOAT));
2775   EXPECT_STREQ("bool", FD::CppTypeName(FD::CPPTYPE_BOOL));
2776   EXPECT_STREQ("enum", FD::CppTypeName(FD::CPPTYPE_ENUM));
2777   EXPECT_STREQ("string", FD::CppTypeName(FD::CPPTYPE_STRING));
2778   EXPECT_STREQ("message", FD::CppTypeName(FD::CPPTYPE_MESSAGE));
2779 }
2780 
TEST_F(MiscTest,MessageType)2781 TEST_F(MiscTest, MessageType) {
2782   // Test that message_type() is nullptr for non-aggregate fields
2783 
2784   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2785 
2786   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_DOUBLE));
2787   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FLOAT));
2788   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_INT64));
2789   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_UINT64));
2790   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_INT32));
2791   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FIXED64));
2792   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_FIXED32));
2793   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_BOOL));
2794   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_STRING));
2795   EXPECT_TRUE(nullptr != GetMessageDescriptorForFieldType(FD::TYPE_GROUP));
2796   EXPECT_TRUE(nullptr != GetMessageDescriptorForFieldType(FD::TYPE_MESSAGE));
2797   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_BYTES));
2798   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_UINT32));
2799   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_ENUM));
2800   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED32));
2801   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SFIXED64));
2802   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SINT32));
2803   EXPECT_TRUE(nullptr == GetMessageDescriptorForFieldType(FD::TYPE_SINT64));
2804 }
2805 
TEST_F(MiscTest,EnumType)2806 TEST_F(MiscTest, EnumType) {
2807   // Test that enum_type() is nullptr for non-enum fields
2808 
2809   typedef FieldDescriptor FD;  // avoid ugly line wrapping
2810 
2811   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_DOUBLE));
2812   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FLOAT));
2813   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_INT64));
2814   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_UINT64));
2815   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_INT32));
2816   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FIXED64));
2817   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_FIXED32));
2818   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_BOOL));
2819   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_STRING));
2820   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_GROUP));
2821   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_MESSAGE));
2822   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_BYTES));
2823   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_UINT32));
2824   EXPECT_TRUE(nullptr != GetEnumDescriptorForFieldType(FD::TYPE_ENUM));
2825   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED32));
2826   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SFIXED64));
2827   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SINT32));
2828   EXPECT_TRUE(nullptr == GetEnumDescriptorForFieldType(FD::TYPE_SINT64));
2829 }
2830 
TEST_F(MiscTest,DefaultValues)2831 TEST_F(MiscTest, DefaultValues) {
2832   // Test that setting default values works.
2833   FileDescriptorProto file_proto;
2834   file_proto.set_name("foo.proto");
2835 
2836   EnumDescriptorProto* enum_type_proto = AddEnum(&file_proto, "DummyEnum");
2837   AddEnumValue(enum_type_proto, "A", 1);
2838   AddEnumValue(enum_type_proto, "B", 2);
2839 
2840   DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
2841 
2842   typedef FieldDescriptorProto FD;  // avoid ugly line wrapping
2843   const FD::Label label = FD::LABEL_OPTIONAL;
2844 
2845   // Create fields of every CPP type with default values.
2846   AddField(message_proto, "int32", 1, label, FD::TYPE_INT32)
2847       ->set_default_value("-1");
2848   AddField(message_proto, "int64", 2, label, FD::TYPE_INT64)
2849       ->set_default_value("-1000000000000");
2850   AddField(message_proto, "uint32", 3, label, FD::TYPE_UINT32)
2851       ->set_default_value("42");
2852   AddField(message_proto, "uint64", 4, label, FD::TYPE_UINT64)
2853       ->set_default_value("2000000000000");
2854   AddField(message_proto, "float", 5, label, FD::TYPE_FLOAT)
2855       ->set_default_value("4.5");
2856   AddField(message_proto, "double", 6, label, FD::TYPE_DOUBLE)
2857       ->set_default_value("10e100");
2858   AddField(message_proto, "bool", 7, label, FD::TYPE_BOOL)
2859       ->set_default_value("true");
2860   AddField(message_proto, "string", 8, label, FD::TYPE_STRING)
2861       ->set_default_value("hello");
2862   AddField(message_proto, "data", 9, label, FD::TYPE_BYTES)
2863       ->set_default_value("\\001\\002\\003");
2864   AddField(message_proto, "data2", 10, label, FD::TYPE_BYTES)
2865       ->set_default_value("\\X01\\X2\\X3");
2866   AddField(message_proto, "data3", 11, label, FD::TYPE_BYTES)
2867       ->set_default_value("\\x01\\x2\\x3");
2868 
2869   FieldDescriptorProto* enum_field =
2870       AddField(message_proto, "enum", 12, label, FD::TYPE_ENUM);
2871   enum_field->set_type_name("DummyEnum");
2872   enum_field->set_default_value("B");
2873 
2874   // Strings are allowed to have empty defaults.  (At one point, due to
2875   // a bug, empty defaults for strings were rejected.  Oops.)
2876   AddField(message_proto, "empty_string", 13, label, FD::TYPE_STRING)
2877       ->set_default_value("");
2878 
2879   // Add a second set of fields with implicit default values.
2880   AddField(message_proto, "implicit_int32", 21, label, FD::TYPE_INT32);
2881   AddField(message_proto, "implicit_int64", 22, label, FD::TYPE_INT64);
2882   AddField(message_proto, "implicit_uint32", 23, label, FD::TYPE_UINT32);
2883   AddField(message_proto, "implicit_uint64", 24, label, FD::TYPE_UINT64);
2884   AddField(message_proto, "implicit_float", 25, label, FD::TYPE_FLOAT);
2885   AddField(message_proto, "implicit_double", 26, label, FD::TYPE_DOUBLE);
2886   AddField(message_proto, "implicit_bool", 27, label, FD::TYPE_BOOL);
2887   AddField(message_proto, "implicit_string", 28, label, FD::TYPE_STRING);
2888   AddField(message_proto, "implicit_data", 29, label, FD::TYPE_BYTES);
2889   AddField(message_proto, "implicit_enum", 30, label, FD::TYPE_ENUM)
2890       ->set_type_name("DummyEnum");
2891 
2892   // Build it.
2893   DescriptorPool pool;
2894   const FileDescriptor* file = pool.BuildFile(file_proto);
2895   ASSERT_TRUE(file != nullptr);
2896 
2897   ASSERT_EQ(1, file->enum_type_count());
2898   const EnumDescriptor* enum_type = file->enum_type(0);
2899   ASSERT_EQ(2, enum_type->value_count());
2900   const EnumValueDescriptor* enum_value_a = enum_type->value(0);
2901   const EnumValueDescriptor* enum_value_b = enum_type->value(1);
2902 
2903   ASSERT_EQ(1, file->message_type_count());
2904   const Descriptor* message = file->message_type(0);
2905 
2906   ASSERT_EQ(23, message->field_count());
2907 
2908   // Check the default values.
2909   ASSERT_TRUE(message->field(0)->has_default_value());
2910   ASSERT_TRUE(message->field(1)->has_default_value());
2911   ASSERT_TRUE(message->field(2)->has_default_value());
2912   ASSERT_TRUE(message->field(3)->has_default_value());
2913   ASSERT_TRUE(message->field(4)->has_default_value());
2914   ASSERT_TRUE(message->field(5)->has_default_value());
2915   ASSERT_TRUE(message->field(6)->has_default_value());
2916   ASSERT_TRUE(message->field(7)->has_default_value());
2917   ASSERT_TRUE(message->field(8)->has_default_value());
2918   ASSERT_TRUE(message->field(9)->has_default_value());
2919   ASSERT_TRUE(message->field(10)->has_default_value());
2920   ASSERT_TRUE(message->field(11)->has_default_value());
2921   ASSERT_TRUE(message->field(12)->has_default_value());
2922 
2923   EXPECT_EQ(-1, message->field(0)->default_value_int32());
2924   EXPECT_EQ(int64_t{-1000000000000}, message->field(1)->default_value_int64());
2925   EXPECT_EQ(42, message->field(2)->default_value_uint32());
2926   EXPECT_EQ(uint64_t{2000000000000}, message->field(3)->default_value_uint64());
2927   EXPECT_EQ(4.5, message->field(4)->default_value_float());
2928   EXPECT_EQ(10e100, message->field(5)->default_value_double());
2929   EXPECT_TRUE(message->field(6)->default_value_bool());
2930   EXPECT_EQ("hello", message->field(7)->default_value_string());
2931   EXPECT_EQ("\001\002\003", message->field(8)->default_value_string());
2932   EXPECT_EQ("\001\002\003", message->field(9)->default_value_string());
2933   EXPECT_EQ("\001\002\003", message->field(10)->default_value_string());
2934   EXPECT_EQ(enum_value_b, message->field(11)->default_value_enum());
2935   EXPECT_EQ("", message->field(12)->default_value_string());
2936 
2937   ASSERT_FALSE(message->field(13)->has_default_value());
2938   ASSERT_FALSE(message->field(14)->has_default_value());
2939   ASSERT_FALSE(message->field(15)->has_default_value());
2940   ASSERT_FALSE(message->field(16)->has_default_value());
2941   ASSERT_FALSE(message->field(17)->has_default_value());
2942   ASSERT_FALSE(message->field(18)->has_default_value());
2943   ASSERT_FALSE(message->field(19)->has_default_value());
2944   ASSERT_FALSE(message->field(20)->has_default_value());
2945   ASSERT_FALSE(message->field(21)->has_default_value());
2946   ASSERT_FALSE(message->field(22)->has_default_value());
2947 
2948   EXPECT_EQ(0, message->field(13)->default_value_int32());
2949   EXPECT_EQ(0, message->field(14)->default_value_int64());
2950   EXPECT_EQ(0, message->field(15)->default_value_uint32());
2951   EXPECT_EQ(0, message->field(16)->default_value_uint64());
2952   EXPECT_EQ(0.0f, message->field(17)->default_value_float());
2953   EXPECT_EQ(0.0, message->field(18)->default_value_double());
2954   EXPECT_FALSE(message->field(19)->default_value_bool());
2955   EXPECT_EQ("", message->field(20)->default_value_string());
2956   EXPECT_EQ("", message->field(21)->default_value_string());
2957   EXPECT_EQ(enum_value_a, message->field(22)->default_value_enum());
2958 }
2959 
TEST_F(MiscTest,FieldOptions)2960 TEST_F(MiscTest, FieldOptions) {
2961   // Try setting field options.
2962 
2963   FileDescriptorProto file_proto;
2964   file_proto.set_name("foo.proto");
2965 
2966   DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
2967   AddField(message_proto, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
2968            FieldDescriptorProto::TYPE_INT32);
2969   FieldDescriptorProto* bar_proto =
2970       AddField(message_proto, "bar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
2971                FieldDescriptorProto::TYPE_BYTES);
2972 
2973   FieldOptions* options = bar_proto->mutable_options();
2974   options->set_ctype(FieldOptions::CORD);
2975 
2976   // Build the descriptors and get the pointers.
2977   DescriptorPool pool;
2978   const FileDescriptor* file = pool.BuildFile(file_proto);
2979   ASSERT_TRUE(file != nullptr);
2980 
2981   ASSERT_EQ(1, file->message_type_count());
2982   const Descriptor* message = file->message_type(0);
2983 
2984   ASSERT_EQ(2, message->field_count());
2985   const FieldDescriptor* foo = message->field(0);
2986   const FieldDescriptor* bar = message->field(1);
2987 
2988   // "foo" had no options set, so it should return the default options.
2989   EXPECT_EQ(&FieldOptions::default_instance(), &foo->options());
2990 
2991   // "bar" had options set.
2992   EXPECT_NE(&FieldOptions::default_instance(), options);
2993   EXPECT_TRUE(bar->options().has_ctype());
2994   EXPECT_EQ(FieldOptions::CORD, bar->options().ctype());
2995 }
2996 
2997 // ===================================================================
2998 enum DescriptorPoolMode { NO_DATABASE, FALLBACK_DATABASE };
2999 
3000 class AllowUnknownDependenciesTest
3001     : public testing::TestWithParam<
3002           std::tuple<DescriptorPoolMode, const char*>> {
3003  protected:
mode()3004   DescriptorPoolMode mode() { return std::get<0>(GetParam()); }
syntax()3005   const char* syntax() { return std::get<1>(GetParam()); }
3006 
SetUp()3007   void SetUp() override {
3008     FileDescriptorProto foo_proto, bar_proto;
3009 
3010     switch (mode()) {
3011       case NO_DATABASE:
3012         pool_ = std::make_unique<DescriptorPool>();
3013         break;
3014       case FALLBACK_DATABASE:
3015         pool_ = std::make_unique<DescriptorPool>(&db_);
3016         break;
3017     }
3018 
3019     pool_->AllowUnknownDependencies();
3020 
3021     ASSERT_TRUE(TextFormat::ParseFromString(
3022         "name: 'foo.proto'"
3023         "dependency: 'bar.proto'"
3024         "dependency: 'baz.proto'"
3025         "message_type {"
3026         "  name: 'Foo'"
3027         "  field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }"
3028         "  field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }"
3029         "  field { name:'moo' number:3 label:LABEL_OPTIONAL"
3030         "    type_name: '.corge.Moo'"
3031         "    type: TYPE_ENUM"
3032         "    options {"
3033         "      uninterpreted_option {"
3034         "        name {"
3035         "          name_part: 'grault'"
3036         "          is_extension: true"
3037         "        }"
3038         "        positive_int_value: 1234"
3039         "      }"
3040         "    }"
3041         "  }"
3042         "}",
3043         &foo_proto));
3044     foo_proto.set_syntax(syntax());
3045 
3046     ASSERT_TRUE(
3047         TextFormat::ParseFromString("name: 'bar.proto'"
3048                                     "message_type { name: 'Bar' }",
3049                                     &bar_proto));
3050     bar_proto.set_syntax(syntax());
3051 
3052     // Collect pointers to stuff.
3053     bar_file_ = BuildFile(bar_proto);
3054     ASSERT_TRUE(bar_file_ != nullptr);
3055 
3056     ASSERT_EQ(1, bar_file_->message_type_count());
3057     bar_type_ = bar_file_->message_type(0);
3058 
3059     foo_file_ = BuildFile(foo_proto);
3060     ASSERT_TRUE(foo_file_ != nullptr);
3061 
3062     ASSERT_EQ(1, foo_file_->message_type_count());
3063     foo_type_ = foo_file_->message_type(0);
3064 
3065     ASSERT_EQ(3, foo_type_->field_count());
3066     bar_field_ = foo_type_->field(0);
3067     baz_field_ = foo_type_->field(1);
3068     moo_field_ = foo_type_->field(2);
3069   }
3070 
BuildFile(const FileDescriptorProto & proto)3071   const FileDescriptor* BuildFile(const FileDescriptorProto& proto) {
3072     switch (mode()) {
3073       case NO_DATABASE:
3074         return pool_->BuildFile(proto);
3075         break;
3076       case FALLBACK_DATABASE: {
3077         EXPECT_TRUE(db_.Add(proto));
3078         return pool_->FindFileByName(proto.name());
3079       }
3080     }
3081     ABSL_LOG(FATAL) << "Can't get here.";
3082     return nullptr;
3083   }
3084 
3085   const FileDescriptor* bar_file_;
3086   const Descriptor* bar_type_;
3087   const FileDescriptor* foo_file_;
3088   const Descriptor* foo_type_;
3089   const FieldDescriptor* bar_field_;
3090   const FieldDescriptor* baz_field_;
3091   const FieldDescriptor* moo_field_;
3092 
3093   SimpleDescriptorDatabase db_;  // used if in FALLBACK_DATABASE mode.
3094   std::unique_ptr<DescriptorPool> pool_;
3095 };
3096 
TEST_P(AllowUnknownDependenciesTest,PlaceholderFile)3097 TEST_P(AllowUnknownDependenciesTest, PlaceholderFile) {
3098   ASSERT_EQ(2, foo_file_->dependency_count());
3099   EXPECT_EQ(bar_file_, foo_file_->dependency(0));
3100   EXPECT_FALSE(bar_file_->is_placeholder());
3101 
3102   const FileDescriptor* baz_file = foo_file_->dependency(1);
3103   EXPECT_EQ("baz.proto", baz_file->name());
3104   EXPECT_EQ(0, baz_file->message_type_count());
3105   EXPECT_TRUE(baz_file->is_placeholder());
3106 
3107   // Placeholder files should not be findable.
3108   EXPECT_EQ(bar_file_, pool_->FindFileByName(bar_file_->name()));
3109   EXPECT_TRUE(pool_->FindFileByName(baz_file->name()) == nullptr);
3110 
3111   // Copy*To should not crash for placeholder files.
3112   FileDescriptorProto baz_file_proto;
3113   baz_file->CopyTo(&baz_file_proto);
3114   baz_file->CopySourceCodeInfoTo(&baz_file_proto);
3115   EXPECT_FALSE(baz_file_proto.has_source_code_info());
3116 }
3117 
TEST_P(AllowUnknownDependenciesTest,PlaceholderTypes)3118 TEST_P(AllowUnknownDependenciesTest, PlaceholderTypes) {
3119   ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type());
3120   EXPECT_EQ(bar_type_, bar_field_->message_type());
3121   EXPECT_FALSE(bar_type_->is_placeholder());
3122 
3123   ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type());
3124   const Descriptor* baz_type = baz_field_->message_type();
3125   EXPECT_EQ("Baz", baz_type->name());
3126   EXPECT_EQ("Baz", baz_type->full_name());
3127   EXPECT_EQ(0, baz_type->extension_range_count());
3128   EXPECT_TRUE(baz_type->is_placeholder());
3129 
3130   ASSERT_EQ(FieldDescriptor::TYPE_ENUM, moo_field_->type());
3131   const EnumDescriptor* moo_type = moo_field_->enum_type();
3132   EXPECT_EQ("Moo", moo_type->name());
3133   EXPECT_EQ("corge.Moo", moo_type->full_name());
3134   EXPECT_TRUE(moo_type->is_placeholder());
3135   // Placeholder enum values should not be findable.
3136   EXPECT_EQ(moo_type->FindValueByNumber(0), nullptr);
3137 
3138   // Placeholder types should not be findable.
3139   EXPECT_EQ(bar_type_, pool_->FindMessageTypeByName(bar_type_->full_name()));
3140   EXPECT_TRUE(pool_->FindMessageTypeByName(baz_type->full_name()) == nullptr);
3141   EXPECT_TRUE(pool_->FindEnumTypeByName(moo_type->full_name()) == nullptr);
3142 }
3143 
TEST_P(AllowUnknownDependenciesTest,CopyTo)3144 TEST_P(AllowUnknownDependenciesTest, CopyTo) {
3145   // FieldDescriptor::CopyTo() should write non-fully-qualified type names
3146   // for placeholder types which were not originally fully-qualified.
3147   FieldDescriptorProto proto;
3148 
3149   // Bar is not a placeholder, so it is fully-qualified.
3150   bar_field_->CopyTo(&proto);
3151   EXPECT_EQ(".Bar", proto.type_name());
3152   EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type());
3153 
3154   // Baz is an unqualified placeholder.
3155   proto.Clear();
3156   baz_field_->CopyTo(&proto);
3157   EXPECT_EQ("Baz", proto.type_name());
3158   EXPECT_FALSE(proto.has_type());
3159 
3160   // Moo is a fully-qualified placeholder.
3161   proto.Clear();
3162   moo_field_->CopyTo(&proto);
3163   EXPECT_EQ(".corge.Moo", proto.type_name());
3164   EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type());
3165 }
3166 
TEST_P(AllowUnknownDependenciesTest,CustomOptions)3167 TEST_P(AllowUnknownDependenciesTest, CustomOptions) {
3168   // Moo should still have the uninterpreted option attached.
3169   ASSERT_EQ(1, moo_field_->options().uninterpreted_option_size());
3170   const UninterpretedOption& option =
3171       moo_field_->options().uninterpreted_option(0);
3172   ASSERT_EQ(1, option.name_size());
3173   EXPECT_EQ("grault", option.name(0).name_part());
3174 }
3175 
TEST_P(AllowUnknownDependenciesTest,UnknownExtendee)3176 TEST_P(AllowUnknownDependenciesTest, UnknownExtendee) {
3177   // Test that we can extend an unknown type.  This is slightly tricky because
3178   // it means that the placeholder type must have an extension range.
3179 
3180   FileDescriptorProto extension_proto;
3181 
3182   ASSERT_TRUE(TextFormat::ParseFromString(
3183       "name: 'extension.proto'"
3184       "extension { extendee: 'UnknownType' name:'some_extension' number:123"
3185       "            label:LABEL_OPTIONAL type:TYPE_INT32 }",
3186       &extension_proto));
3187   const FileDescriptor* file = BuildFile(extension_proto);
3188 
3189   ASSERT_TRUE(file != nullptr);
3190 
3191   ASSERT_EQ(1, file->extension_count());
3192   const Descriptor* extendee = file->extension(0)->containing_type();
3193   EXPECT_EQ("UnknownType", extendee->name());
3194   EXPECT_TRUE(extendee->is_placeholder());
3195   ASSERT_EQ(1, extendee->extension_range_count());
3196   EXPECT_EQ(1, extendee->extension_range(0)->start_number());
3197   EXPECT_EQ(FieldDescriptor::kMaxNumber + 1,
3198             extendee->extension_range(0)->end_number());
3199 }
3200 
3201 
TEST_P(AllowUnknownDependenciesTest,CustomOption)3202 TEST_P(AllowUnknownDependenciesTest, CustomOption) {
3203   // Test that we can use a custom option without having parsed
3204   // descriptor.proto.
3205 
3206   FileDescriptorProto option_proto;
3207 
3208   ASSERT_TRUE(TextFormat::ParseFromString(
3209       "name: \"unknown_custom_options.proto\" "
3210       "dependency: \"google/protobuf/descriptor.proto\" "
3211       "extension { "
3212       "  extendee: \"google.protobuf.FileOptions\" "
3213       "  name: \"some_option\" "
3214       "  number: 123456 "
3215       "  label: LABEL_OPTIONAL "
3216       "  type: TYPE_INT32 "
3217       "} "
3218       "options { "
3219       "  uninterpreted_option { "
3220       "    name { "
3221       "      name_part: \"some_option\" "
3222       "      is_extension: true "
3223       "    } "
3224       "    positive_int_value: 1234 "
3225       "  } "
3226       "  uninterpreted_option { "
3227       "    name { "
3228       "      name_part: \"unknown_option\" "
3229       "      is_extension: true "
3230       "    } "
3231       "    positive_int_value: 1234 "
3232       "  } "
3233       "  uninterpreted_option { "
3234       "    name { "
3235       "      name_part: \"optimize_for\" "
3236       "      is_extension: false "
3237       "    } "
3238       "    identifier_value: \"SPEED\" "
3239       "  } "
3240       "}",
3241       &option_proto));
3242 
3243   const FileDescriptor* file = BuildFile(option_proto);
3244   ASSERT_TRUE(file != nullptr);
3245 
3246   // Verify that no extension options were set, but they were left as
3247   // uninterpreted_options.
3248   std::vector<const FieldDescriptor*> fields;
3249   file->options().GetReflection()->ListFields(file->options(), &fields);
3250   ASSERT_EQ(2, fields.size());
3251   EXPECT_TRUE(file->options().has_optimize_for());
3252   EXPECT_EQ(2, file->options().uninterpreted_option_size());
3253 }
3254 
TEST_P(AllowUnknownDependenciesTest,UndeclaredDependencyTriggersBuildOfDependency)3255 TEST_P(AllowUnknownDependenciesTest,
3256        UndeclaredDependencyTriggersBuildOfDependency) {
3257   // Crazy case: suppose foo.proto refers to a symbol without declaring the
3258   // dependency that finds it. In the event that the pool is backed by a
3259   // DescriptorDatabase, the pool will attempt to find the symbol in the
3260   // database. If successful, it will build the undeclared dependency to verify
3261   // that the file does indeed contain the symbol. If that file fails to build,
3262   // then its descriptors must be rolled back. However, we still want foo.proto
3263   // to build successfully, since we are allowing unknown dependencies.
3264 
3265   FileDescriptorProto undeclared_dep_proto;
3266   // We make this file fail to build by giving it two fields with tag 1.
3267   ASSERT_TRUE(TextFormat::ParseFromString(
3268       "name: \"invalid_file_as_undeclared_dep.proto\" "
3269       "package: \"undeclared\" "
3270       "message_type: {  "
3271       "  name: \"Mooo\"  "
3272       "  field { "
3273       "    name:'moo' number:1 label:LABEL_OPTIONAL type: TYPE_INT32 "
3274       "  }"
3275       "  field { "
3276       "    name:'mooo' number:1 label:LABEL_OPTIONAL type: TYPE_INT64 "
3277       "  }"
3278       "}",
3279       &undeclared_dep_proto));
3280   // We can't use the BuildFile() helper because we don't actually want to build
3281   // it into the descriptor pool in the fallback database case: it just needs to
3282   // be sitting in the database so that it gets built during the building of
3283   // test.proto below.
3284   switch (mode()) {
3285     case NO_DATABASE: {
3286       ASSERT_TRUE(pool_->BuildFile(undeclared_dep_proto) == nullptr);
3287       break;
3288     }
3289     case FALLBACK_DATABASE: {
3290       ASSERT_TRUE(db_.Add(undeclared_dep_proto));
3291     }
3292   }
3293 
3294   FileDescriptorProto test_proto;
3295   ASSERT_TRUE(TextFormat::ParseFromString(
3296       "name: \"test.proto\" "
3297       "message_type: { "
3298       "  name: \"Corge\" "
3299       "  field { "
3300       "    name:'mooo' number:1 label: LABEL_OPTIONAL "
3301       "    type_name:'undeclared.Mooo' type: TYPE_MESSAGE "
3302       "  }"
3303       "}",
3304       &test_proto));
3305 
3306   const FileDescriptor* file = BuildFile(test_proto);
3307   ASSERT_TRUE(file != nullptr);
3308   ABSL_LOG(INFO) << file->DebugString();
3309 
3310   EXPECT_EQ(0, file->dependency_count());
3311   ASSERT_EQ(1, file->message_type_count());
3312   const Descriptor* corge_desc = file->message_type(0);
3313   ASSERT_EQ("Corge", corge_desc->name());
3314   ASSERT_EQ(1, corge_desc->field_count());
3315   EXPECT_FALSE(corge_desc->is_placeholder());
3316 
3317   const FieldDescriptor* mooo_field = corge_desc->field(0);
3318   ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, mooo_field->type());
3319   ASSERT_EQ("Mooo", mooo_field->message_type()->name());
3320   ASSERT_EQ("undeclared.Mooo", mooo_field->message_type()->full_name());
3321   EXPECT_TRUE(mooo_field->message_type()->is_placeholder());
3322   // The place holder type should not be findable.
3323   ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Mooo") == nullptr);
3324 }
3325 
3326 INSTANTIATE_TEST_SUITE_P(DatabaseSource, AllowUnknownDependenciesTest,
3327                          testing::Combine(testing::Values(NO_DATABASE,
3328                                                           FALLBACK_DATABASE),
3329                                           testing::Values("proto2", "proto3")));
3330 
3331 // ===================================================================
3332 
TEST(CustomOptions,OptionLocations)3333 TEST(CustomOptions, OptionLocations) {
3334   const Descriptor* message =
3335       protobuf_unittest::TestMessageWithCustomOptions::descriptor();
3336   const FileDescriptor* file = message->file();
3337   const FieldDescriptor* field = message->FindFieldByName("field1");
3338   const OneofDescriptor* oneof = message->FindOneofByName("AnOneof");
3339   const FieldDescriptor* map_field = message->FindFieldByName("map_field");
3340   const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
3341   // TODO: Support EnumValue options, once the compiler does.
3342   const ServiceDescriptor* service =
3343       file->FindServiceByName("TestServiceWithCustomOptions");
3344   const MethodDescriptor* method = service->FindMethodByName("Foo");
3345 
3346   EXPECT_EQ(int64_t{9876543210},
3347             file->options().GetExtension(protobuf_unittest::file_opt1));
3348   EXPECT_EQ(-56,
3349             message->options().GetExtension(protobuf_unittest::message_opt1));
3350   EXPECT_EQ(int64_t{8765432109},
3351             field->options().GetExtension(protobuf_unittest::field_opt1));
3352   EXPECT_EQ(42,  // Check that we get the default for an option we don't set.
3353             field->options().GetExtension(protobuf_unittest::field_opt2));
3354   EXPECT_EQ(-99, oneof->options().GetExtension(protobuf_unittest::oneof_opt1));
3355   EXPECT_EQ(int64_t{12345},
3356             map_field->options().GetExtension(protobuf_unittest::field_opt1));
3357   EXPECT_EQ(-789, enm->options().GetExtension(protobuf_unittest::enum_opt1));
3358   EXPECT_EQ(123, enm->value(1)->options().GetExtension(
3359                      protobuf_unittest::enum_value_opt1));
3360   EXPECT_EQ(int64_t{-9876543210},
3361             service->options().GetExtension(protobuf_unittest::service_opt1));
3362   EXPECT_EQ(protobuf_unittest::METHODOPT1_VAL2,
3363             method->options().GetExtension(protobuf_unittest::method_opt1));
3364 
3365   // See that the regular options went through unscathed.
3366   EXPECT_TRUE(message->options().has_message_set_wire_format());
3367   EXPECT_EQ(FieldOptions::CORD, field->options().ctype());
3368 }
3369 
TEST(CustomOptions,OptionTypes)3370 TEST(CustomOptions, OptionTypes) {
3371   const MessageOptions* options = nullptr;
3372 
3373   constexpr int32_t kint32min = std::numeric_limits<int32_t>::min();
3374   constexpr int32_t kint32max = std::numeric_limits<int32_t>::max();
3375   constexpr uint32_t kuint32max = std::numeric_limits<uint32_t>::max();
3376   constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
3377   constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
3378   constexpr uint64_t kuint64max = std::numeric_limits<uint64_t>::max();
3379 
3380   options =
3381       &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options();
3382   EXPECT_EQ(false, options->GetExtension(protobuf_unittest::bool_opt));
3383   EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt));
3384   EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt));
3385   EXPECT_EQ(0, options->GetExtension(protobuf_unittest::uint32_opt));
3386   EXPECT_EQ(0, options->GetExtension(protobuf_unittest::uint64_opt));
3387   EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sint32_opt));
3388   EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sint64_opt));
3389   EXPECT_EQ(0, options->GetExtension(protobuf_unittest::fixed32_opt));
3390   EXPECT_EQ(0, options->GetExtension(protobuf_unittest::fixed64_opt));
3391   EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::sfixed32_opt));
3392   EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::sfixed64_opt));
3393 
3394   options =
3395       &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options();
3396   EXPECT_EQ(true, options->GetExtension(protobuf_unittest::bool_opt));
3397   EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::int32_opt));
3398   EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::int64_opt));
3399   EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt));
3400   EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::uint64_opt));
3401   EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::sint32_opt));
3402   EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::sint64_opt));
3403   EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::fixed32_opt));
3404   EXPECT_EQ(kuint64max, options->GetExtension(protobuf_unittest::fixed64_opt));
3405   EXPECT_EQ(kint32max, options->GetExtension(protobuf_unittest::sfixed32_opt));
3406   EXPECT_EQ(kint64max, options->GetExtension(protobuf_unittest::sfixed64_opt));
3407 
3408   options = &protobuf_unittest::CustomOptionOtherValues::descriptor()->options();
3409   EXPECT_EQ(-100, options->GetExtension(protobuf_unittest::int32_opt));
3410   EXPECT_FLOAT_EQ(12.3456789,
3411                   options->GetExtension(protobuf_unittest::float_opt));
3412   EXPECT_DOUBLE_EQ(1.234567890123456789,
3413                    options->GetExtension(protobuf_unittest::double_opt));
3414   EXPECT_EQ("Hello, \"World\"",
3415             options->GetExtension(protobuf_unittest::string_opt));
3416 
3417   EXPECT_EQ(std::string("Hello\0World", 11),
3418             options->GetExtension(protobuf_unittest::bytes_opt));
3419 
3420   EXPECT_EQ(protobuf_unittest::DummyMessageContainingEnum::TEST_OPTION_ENUM_TYPE2,
3421             options->GetExtension(protobuf_unittest::enum_opt));
3422 
3423   options =
3424       &protobuf_unittest::SettingRealsFromPositiveInts::descriptor()->options();
3425   EXPECT_FLOAT_EQ(12, options->GetExtension(protobuf_unittest::float_opt));
3426   EXPECT_DOUBLE_EQ(154, options->GetExtension(protobuf_unittest::double_opt));
3427 
3428   options =
3429       &protobuf_unittest::SettingRealsFromNegativeInts::descriptor()->options();
3430   EXPECT_FLOAT_EQ(-12, options->GetExtension(protobuf_unittest::float_opt));
3431   EXPECT_DOUBLE_EQ(-154, options->GetExtension(protobuf_unittest::double_opt));
3432 }
3433 
TEST(CustomOptions,ComplexExtensionOptions)3434 TEST(CustomOptions, ComplexExtensionOptions) {
3435   const MessageOptions* options =
3436       &protobuf_unittest::VariousComplexOptions::descriptor()->options();
3437   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1).foo(), 42);
3438   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1)
3439                 .GetExtension(protobuf_unittest::mooo),
3440             324);
3441   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt1)
3442                 .GetExtension(protobuf_unittest::corge)
3443                 .moo(),
3444             876);
3445   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).baz(), 987);
3446   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3447                 .GetExtension(protobuf_unittest::grault),
3448             654);
3449   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).bar().foo(),
3450             743);
3451   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3452                 .bar()
3453                 .GetExtension(protobuf_unittest::mooo),
3454             1999);
3455   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3456                 .bar()
3457                 .GetExtension(protobuf_unittest::corge)
3458                 .moo(),
3459             2008);
3460   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3461                 .GetExtension(protobuf_unittest::garply)
3462                 .foo(),
3463             741);
3464   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3465                 .GetExtension(protobuf_unittest::garply)
3466                 .GetExtension(protobuf_unittest::mooo),
3467             1998);
3468   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2)
3469                 .GetExtension(protobuf_unittest::garply)
3470                 .GetExtension(protobuf_unittest::corge)
3471                 .moo(),
3472             2121);
3473   EXPECT_EQ(options
3474                 ->GetExtension(protobuf_unittest::ComplexOptionType2::
3475                                    ComplexOptionType4::complex_opt4)
3476                 .waldo(),
3477             1971);
3478   EXPECT_EQ(options->GetExtension(protobuf_unittest::complex_opt2).fred().waldo(),
3479             321);
3480   EXPECT_EQ(9, options->GetExtension(protobuf_unittest::complex_opt3).moo());
3481   EXPECT_EQ(22, options->GetExtension(protobuf_unittest::complex_opt3)
3482                     .complexoptiontype5()
3483                     .plugh());
3484   EXPECT_EQ(24, options->GetExtension(protobuf_unittest::complexopt6).xyzzy());
3485 }
3486 
TEST(CustomOptions,OptionsFromOtherFile)3487 TEST(CustomOptions, OptionsFromOtherFile) {
3488   // Test that to use a custom option, we only need to import the file
3489   // defining the option; we do not also have to import descriptor.proto.
3490   DescriptorPool pool;
3491   {
3492     FileDescriptorProto file_proto;
3493     FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3494     ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3495   }
3496   {
3497     // We have to import the Any dependency.
3498     FileDescriptorProto any_proto;
3499     google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3500     ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3501   }
3502   FileDescriptorProto file_proto;
3503   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3504       &file_proto);
3505   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3506 
3507   ASSERT_TRUE(TextFormat::ParseFromString(
3508       "name: \"custom_options_import.proto\" "
3509       "package: \"protobuf_unittest\" "
3510       "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3511       "options { "
3512       "  uninterpreted_option { "
3513       "    name { "
3514       "      name_part: \"file_opt1\" "
3515       "      is_extension: true "
3516       "    } "
3517       "    positive_int_value: 1234 "
3518       "  } "
3519       // Test a non-extension option too.  (At one point this failed due to a
3520       // bug.)
3521       "  uninterpreted_option { "
3522       "    name { "
3523       "      name_part: \"java_package\" "
3524       "      is_extension: false "
3525       "    } "
3526       "    string_value: \"foo\" "
3527       "  } "
3528       // Test that enum-typed options still work too.  (At one point this also
3529       // failed due to a bug.)
3530       "  uninterpreted_option { "
3531       "    name { "
3532       "      name_part: \"optimize_for\" "
3533       "      is_extension: false "
3534       "    } "
3535       "    identifier_value: \"SPEED\" "
3536       "  } "
3537       "}",
3538       &file_proto));
3539 
3540   const FileDescriptor* file = pool.BuildFile(file_proto);
3541   ASSERT_TRUE(file != nullptr);
3542   EXPECT_EQ(1234, file->options().GetExtension(protobuf_unittest::file_opt1));
3543   EXPECT_TRUE(file->options().has_java_package());
3544   EXPECT_EQ("foo", file->options().java_package());
3545   EXPECT_TRUE(file->options().has_optimize_for());
3546   EXPECT_EQ(FileOptions::SPEED, file->options().optimize_for());
3547 }
3548 
TEST(CustomOptions,MessageOptionThreeFieldsSet)3549 TEST(CustomOptions, MessageOptionThreeFieldsSet) {
3550   // This tests a bug which previously existed in custom options parsing.  The
3551   // bug occurred when you defined a custom option with message type and then
3552   // set three fields of that option on a single definition (see the example
3553   // below).  The bug is a bit hard to explain, so check the change history if
3554   // you want to know more.
3555   DescriptorPool pool;
3556 
3557   {
3558     FileDescriptorProto file_proto;
3559     FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3560     ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3561   }
3562   {
3563     FileDescriptorProto any_proto;
3564     google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3565     ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3566   }
3567   FileDescriptorProto file_proto;
3568   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3569       &file_proto);
3570   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3571 
3572   // The following represents the definition:
3573   //
3574   //   import "google/protobuf/unittest_custom_options.proto"
3575   //   package protobuf_unittest;
3576   //   message Foo {
3577   //     option (complex_opt1).foo  = 1234;
3578   //     option (complex_opt1).foo2 = 1234;
3579   //     option (complex_opt1).foo3 = 1234;
3580   //   }
3581   ASSERT_TRUE(TextFormat::ParseFromString(
3582       "name: \"custom_options_import.proto\" "
3583       "package: \"protobuf_unittest\" "
3584       "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3585       "message_type { "
3586       "  name: \"Foo\" "
3587       "  options { "
3588       "    uninterpreted_option { "
3589       "      name { "
3590       "        name_part: \"complex_opt1\" "
3591       "        is_extension: true "
3592       "      } "
3593       "      name { "
3594       "        name_part: \"foo\" "
3595       "        is_extension: false "
3596       "      } "
3597       "      positive_int_value: 1234 "
3598       "    } "
3599       "    uninterpreted_option { "
3600       "      name { "
3601       "        name_part: \"complex_opt1\" "
3602       "        is_extension: true "
3603       "      } "
3604       "      name { "
3605       "        name_part: \"foo2\" "
3606       "        is_extension: false "
3607       "      } "
3608       "      positive_int_value: 1234 "
3609       "    } "
3610       "    uninterpreted_option { "
3611       "      name { "
3612       "        name_part: \"complex_opt1\" "
3613       "        is_extension: true "
3614       "      } "
3615       "      name { "
3616       "        name_part: \"foo3\" "
3617       "        is_extension: false "
3618       "      } "
3619       "      positive_int_value: 1234 "
3620       "    } "
3621       "  } "
3622       "}",
3623       &file_proto));
3624 
3625   const FileDescriptor* file = pool.BuildFile(file_proto);
3626   ASSERT_TRUE(file != nullptr);
3627   ASSERT_EQ(1, file->message_type_count());
3628 
3629   const MessageOptions& options = file->message_type(0)->options();
3630   EXPECT_EQ(1234, options.GetExtension(protobuf_unittest::complex_opt1).foo());
3631 }
3632 
TEST(CustomOptions,MessageOptionRepeatedLeafFieldSet)3633 TEST(CustomOptions, MessageOptionRepeatedLeafFieldSet) {
3634   // This test verifies that repeated fields in custom options can be
3635   // given multiple values by repeating the option with a different value.
3636   // This test checks repeated leaf values. Each repeated custom value
3637   // appears in a different uninterpreted_option, which will be concatenated
3638   // when they are merged into the final option value.
3639   DescriptorPool pool;
3640 
3641   {
3642     FileDescriptorProto file_proto;
3643     FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3644     ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3645   }
3646   {
3647     FileDescriptorProto any_proto;
3648     google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3649     ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3650   }
3651   FileDescriptorProto file_proto;
3652   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3653       &file_proto);
3654   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3655 
3656   // The following represents the definition:
3657   //
3658   //   import "google/protobuf/unittest_custom_options.proto"
3659   //   package protobuf_unittest;
3660   //   message Foo {
3661   //     option (complex_opt1).foo4 = 12;
3662   //     option (complex_opt1).foo4 = 34;
3663   //     option (complex_opt1).foo4 = 56;
3664   //   }
3665   ASSERT_TRUE(TextFormat::ParseFromString(
3666       "name: \"custom_options_import.proto\" "
3667       "package: \"protobuf_unittest\" "
3668       "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3669       "message_type { "
3670       "  name: \"Foo\" "
3671       "  options { "
3672       "    uninterpreted_option { "
3673       "      name { "
3674       "        name_part: \"complex_opt1\" "
3675       "        is_extension: true "
3676       "      } "
3677       "      name { "
3678       "        name_part: \"foo4\" "
3679       "        is_extension: false "
3680       "      } "
3681       "      positive_int_value: 12 "
3682       "    } "
3683       "    uninterpreted_option { "
3684       "      name { "
3685       "        name_part: \"complex_opt1\" "
3686       "        is_extension: true "
3687       "      } "
3688       "      name { "
3689       "        name_part: \"foo4\" "
3690       "        is_extension: false "
3691       "      } "
3692       "      positive_int_value: 34 "
3693       "    } "
3694       "    uninterpreted_option { "
3695       "      name { "
3696       "        name_part: \"complex_opt1\" "
3697       "        is_extension: true "
3698       "      } "
3699       "      name { "
3700       "        name_part: \"foo4\" "
3701       "        is_extension: false "
3702       "      } "
3703       "      positive_int_value: 56 "
3704       "    } "
3705       "  } "
3706       "}",
3707       &file_proto));
3708 
3709   const FileDescriptor* file = pool.BuildFile(file_proto);
3710   ASSERT_TRUE(file != nullptr);
3711   ASSERT_EQ(1, file->message_type_count());
3712 
3713   const MessageOptions& options = file->message_type(0)->options();
3714   EXPECT_EQ(3, options.GetExtension(protobuf_unittest::complex_opt1).foo4_size());
3715   EXPECT_EQ(12, options.GetExtension(protobuf_unittest::complex_opt1).foo4(0));
3716   EXPECT_EQ(34, options.GetExtension(protobuf_unittest::complex_opt1).foo4(1));
3717   EXPECT_EQ(56, options.GetExtension(protobuf_unittest::complex_opt1).foo4(2));
3718 }
3719 
TEST(CustomOptions,MessageOptionRepeatedMsgFieldSet)3720 TEST(CustomOptions, MessageOptionRepeatedMsgFieldSet) {
3721   // This test verifies that repeated fields in custom options can be
3722   // given multiple values by repeating the option with a different value.
3723   // This test checks repeated message values. Each repeated custom value
3724   // appears in a different uninterpreted_option, which will be concatenated
3725   // when they are merged into the final option value.
3726   DescriptorPool pool;
3727 
3728   {
3729     FileDescriptorProto file_proto;
3730     FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3731     ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3732   }
3733   {
3734     FileDescriptorProto any_proto;
3735     google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3736     ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3737   }
3738   FileDescriptorProto file_proto;
3739   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3740       &file_proto);
3741   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3742 
3743   // The following represents the definition:
3744   //
3745   //   import "google/protobuf/unittest_custom_options.proto"
3746   //   package protobuf_unittest;
3747   //   message Foo {
3748   //     option (complex_opt2).barney = {waldo: 1};
3749   //     option (complex_opt2).barney = {waldo: 10};
3750   //     option (complex_opt2).barney = {waldo: 100};
3751   //   }
3752   ASSERT_TRUE(TextFormat::ParseFromString(
3753       "name: \"custom_options_import.proto\" "
3754       "package: \"protobuf_unittest\" "
3755       "dependency: \"google/protobuf/unittest_custom_options.proto\" "
3756       "message_type { "
3757       "  name: \"Foo\" "
3758       "  options { "
3759       "    uninterpreted_option { "
3760       "      name { "
3761       "        name_part: \"complex_opt2\" "
3762       "        is_extension: true "
3763       "      } "
3764       "      name { "
3765       "        name_part: \"barney\" "
3766       "        is_extension: false "
3767       "      } "
3768       "      aggregate_value: \"waldo: 1\" "
3769       "    } "
3770       "    uninterpreted_option { "
3771       "      name { "
3772       "        name_part: \"complex_opt2\" "
3773       "        is_extension: true "
3774       "      } "
3775       "      name { "
3776       "        name_part: \"barney\" "
3777       "        is_extension: false "
3778       "      } "
3779       "      aggregate_value: \"waldo: 10\" "
3780       "    } "
3781       "    uninterpreted_option { "
3782       "      name { "
3783       "        name_part: \"complex_opt2\" "
3784       "        is_extension: true "
3785       "      } "
3786       "      name { "
3787       "        name_part: \"barney\" "
3788       "        is_extension: false "
3789       "      } "
3790       "      aggregate_value: \"waldo: 100\" "
3791       "    } "
3792       "  } "
3793       "}",
3794       &file_proto));
3795 
3796   const FileDescriptor* file = pool.BuildFile(file_proto);
3797   ASSERT_TRUE(file != nullptr);
3798   ASSERT_EQ(1, file->message_type_count());
3799 
3800   const MessageOptions& options = file->message_type(0)->options();
3801   EXPECT_EQ(3,
3802             options.GetExtension(protobuf_unittest::complex_opt2).barney_size());
3803   EXPECT_EQ(
3804       1, options.GetExtension(protobuf_unittest::complex_opt2).barney(0).waldo());
3805   EXPECT_EQ(
3806       10,
3807       options.GetExtension(protobuf_unittest::complex_opt2).barney(1).waldo());
3808   EXPECT_EQ(
3809       100,
3810       options.GetExtension(protobuf_unittest::complex_opt2).barney(2).waldo());
3811 }
3812 
3813 // Check that aggregate options were parsed and saved correctly in
3814 // the appropriate descriptors.
TEST(CustomOptions,AggregateOptions)3815 TEST(CustomOptions, AggregateOptions) {
3816   const Descriptor* msg = protobuf_unittest::AggregateMessage::descriptor();
3817   const FileDescriptor* file = msg->file();
3818   const FieldDescriptor* field = msg->FindFieldByName("fieldname");
3819   const EnumDescriptor* enumd = file->FindEnumTypeByName("AggregateEnum");
3820   const EnumValueDescriptor* enumv = enumd->FindValueByName("VALUE");
3821   const ServiceDescriptor* service =
3822       file->FindServiceByName("AggregateService");
3823   const MethodDescriptor* method = service->FindMethodByName("Method");
3824 
3825   // Tests for the different types of data embedded in fileopt
3826   const protobuf_unittest::Aggregate& file_options =
3827       file->options().GetExtension(protobuf_unittest::fileopt);
3828   EXPECT_EQ(100, file_options.i());
3829   EXPECT_EQ("FileAnnotation", file_options.s());
3830   EXPECT_EQ("NestedFileAnnotation", file_options.sub().s());
3831   EXPECT_EQ("FileExtensionAnnotation",
3832             file_options.file().GetExtension(protobuf_unittest::fileopt).s());
3833   EXPECT_EQ("EmbeddedMessageSetElement",
3834             file_options.mset()
3835                 .GetExtension(protobuf_unittest::AggregateMessageSetElement ::
3836                                   message_set_extension)
3837                 .s());
3838 
3839   protobuf_unittest::AggregateMessageSetElement any_payload;
3840   ASSERT_TRUE(file_options.any().UnpackTo(&any_payload));
3841   EXPECT_EQ("EmbeddedMessageSetElement", any_payload.s());
3842 
3843   // Simple tests for all the other types of annotations
3844   EXPECT_EQ("MessageAnnotation",
3845             msg->options().GetExtension(protobuf_unittest::msgopt).s());
3846   EXPECT_EQ("FieldAnnotation",
3847             field->options().GetExtension(protobuf_unittest::fieldopt).s());
3848   EXPECT_EQ("EnumAnnotation",
3849             enumd->options().GetExtension(protobuf_unittest::enumopt).s());
3850   EXPECT_EQ("EnumValueAnnotation",
3851             enumv->options().GetExtension(protobuf_unittest::enumvalopt).s());
3852   EXPECT_EQ("ServiceAnnotation",
3853             service->options().GetExtension(protobuf_unittest::serviceopt).s());
3854   EXPECT_EQ("MethodAnnotation",
3855             method->options().GetExtension(protobuf_unittest::methodopt).s());
3856 }
3857 
TEST(CustomOptions,UnusedImportError)3858 TEST(CustomOptions, UnusedImportError) {
3859   DescriptorPool pool;
3860 
3861   {
3862     FileDescriptorProto file_proto;
3863     FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
3864     ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3865   }
3866   {
3867     FileDescriptorProto any_proto;
3868     google::protobuf::Any::descriptor()->file()->CopyTo(&any_proto);
3869     ASSERT_TRUE(pool.BuildFile(any_proto) != nullptr);
3870   }
3871   FileDescriptorProto file_proto;
3872   protobuf_unittest::TestMessageWithCustomOptions::descriptor()->file()->CopyTo(
3873       &file_proto);
3874   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3875 
3876   pool.AddDirectInputFile("custom_options_import.proto", true);
3877   ASSERT_TRUE(TextFormat::ParseFromString(
3878       "name: \"custom_options_import.proto\" "
3879       "package: \"protobuf_unittest\" "
3880       "dependency: \"google/protobuf/unittest_custom_options.proto\" ",
3881       &file_proto));
3882 
3883   MockErrorCollector error_collector;
3884   EXPECT_FALSE(pool.BuildFileCollectingErrors(file_proto, &error_collector));
3885   EXPECT_EQ(
3886       "custom_options_import.proto: "
3887       "google/protobuf/unittest_custom_options.proto: IMPORT: Import "
3888       "google/protobuf/unittest_custom_options.proto is unused.\n",
3889       error_collector.text_);
3890 }
3891 
3892 // Verifies that proto files can correctly be parsed, even if the
3893 // custom options defined in the file are incompatible with those
3894 // compiled in the binary. See http://b/19276250.
TEST(CustomOptions,OptionsWithIncompatibleDescriptors)3895 TEST(CustomOptions, OptionsWithIncompatibleDescriptors) {
3896   DescriptorPool pool;
3897 
3898   FileDescriptorProto file_proto;
3899   MessageOptions::descriptor()->file()->CopyTo(&file_proto);
3900   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3901 
3902   // Create a new file descriptor proto containing a subset of the
3903   // messages defined in google/protobuf/unittest_custom_options.proto.
3904   file_proto.Clear();
3905   file_proto.set_name("unittest_custom_options.proto");
3906   file_proto.set_package("protobuf_unittest");
3907   file_proto.add_dependency("google/protobuf/descriptor.proto");
3908 
3909   // Add the "required_enum_opt" extension.
3910   FieldDescriptorProto* extension = file_proto.add_extension();
3911   protobuf_unittest::OldOptionType::descriptor()
3912       ->file()
3913       ->FindExtensionByName("required_enum_opt")
3914       ->CopyTo(extension);
3915 
3916   // Add a test message that uses the "required_enum_opt" option.
3917   DescriptorProto* test_message_type = file_proto.add_message_type();
3918   protobuf_unittest::TestMessageWithRequiredEnumOption::descriptor()->CopyTo(
3919       test_message_type);
3920 
3921   // Instruct the extension to use NewOptionType instead of
3922   // OldOptionType, and add the descriptor of NewOptionType.
3923   extension->set_type_name(".protobuf_unittest.NewOptionType");
3924   DescriptorProto* new_option_type = file_proto.add_message_type();
3925   protobuf_unittest::NewOptionType::descriptor()->CopyTo(new_option_type);
3926 
3927   // Replace the value of the "required_enum_opt" option used in the
3928   // test message with an enum value that only exists in NewOptionType.
3929   ASSERT_TRUE(
3930       TextFormat::ParseFromString("uninterpreted_option { "
3931                                   "  name { "
3932                                   "    name_part: 'required_enum_opt' "
3933                                   "    is_extension: true "
3934                                   "  } "
3935                                   "  aggregate_value: 'value: NEW_VALUE'"
3936                                   "}",
3937                                   test_message_type->mutable_options()));
3938 
3939   // Adding the file descriptor to the pool should fail.
3940   EXPECT_TRUE(pool.BuildFile(file_proto) == nullptr);
3941 }
3942 
3943 // Test that FileDescriptor::DebugString() formats custom options correctly.
TEST(CustomOptions,DebugString)3944 TEST(CustomOptions, DebugString) {
3945   DescriptorPool pool;
3946 
3947   FileDescriptorProto file_proto;
3948   MessageOptions::descriptor()->file()->CopyTo(&file_proto);
3949   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
3950 
3951   // Add "foo.proto":
3952   //   import "google/protobuf/descriptor.proto";
3953   //   package "protobuf_unittest";
3954   //   option (protobuf_unittest.cc_option1) = 1;
3955   //   option (protobuf_unittest.cc_option2) = 2;
3956   //   extend google.protobuf.FieldOptions {
3957   //     optional int32 cc_option1 = 7736974;
3958   //     optional int32 cc_option2 = 7736975;
3959   //   }
3960   ASSERT_TRUE(TextFormat::ParseFromString(
3961       "name: \"foo.proto\" "
3962       "package: \"protobuf_unittest\" "
3963       "dependency: \"google/protobuf/descriptor.proto\" "
3964       "options { "
3965       "  uninterpreted_option { "
3966       "    name { "
3967       "      name_part: \"protobuf_unittest.cc_option1\" "
3968       "      is_extension: true "
3969       "    } "
3970       "    positive_int_value: 1 "
3971       "  } "
3972       "  uninterpreted_option { "
3973       "    name { "
3974       "      name_part: \"protobuf_unittest.cc_option2\" "
3975       "      is_extension: true "
3976       "    } "
3977       "    positive_int_value: 2 "
3978       "  } "
3979       "} "
3980       "extension { "
3981       "  name: \"cc_option1\" "
3982       "  extendee: \".google.protobuf.FileOptions\" "
3983       // This field number is intentionally chosen to be the same as
3984       // (.fileopt1) defined in unittest_custom_options.proto (linked
3985       // in this test binary). This is to test whether we are messing
3986       // generated pool with custom descriptor pools when dealing with
3987       // custom options.
3988       "  number: 7736974 "
3989       "  label: LABEL_OPTIONAL "
3990       "  type: TYPE_INT32 "
3991       "}"
3992       "extension { "
3993       "  name: \"cc_option2\" "
3994       "  extendee: \".google.protobuf.FileOptions\" "
3995       "  number: 7736975 "
3996       "  label: LABEL_OPTIONAL "
3997       "  type: TYPE_INT32 "
3998       "}",
3999       &file_proto));
4000   const FileDescriptor* descriptor = pool.BuildFile(file_proto);
4001   ASSERT_TRUE(descriptor != nullptr);
4002 
4003   EXPECT_EQ(2, descriptor->extension_count());
4004 
4005   ASSERT_EQ(
4006       "syntax = \"proto2\";\n"
4007       "\n"
4008       "import \"google/protobuf/descriptor.proto\";\n"
4009       "package protobuf_unittest;\n"
4010       "\n"
4011       "option (.protobuf_unittest.cc_option1) = 1;\n"
4012       "option (.protobuf_unittest.cc_option2) = 2;\n"
4013       "\n"
4014       "extend .google.protobuf.FileOptions {\n"
4015       "  optional int32 cc_option1 = 7736974;\n"
4016       "  optional int32 cc_option2 = 7736975;\n"
4017       "}\n"
4018       "\n",
4019       descriptor->DebugString());
4020 }
4021 
4022 // ===================================================================
4023 
4024 
4025 class ValidationErrorTest : public testing::Test {
4026  protected:
SetUp()4027   void SetUp() override {
4028     // Enable extension declaration enforcement since most test cases want to
4029     // exercise the full validation.
4030     pool_.EnforceExtensionDeclarations(true);
4031   }
4032   // Parse file_text as a FileDescriptorProto in text format and add it
4033   // to the DescriptorPool.  Expect no errors.
BuildFile(absl::string_view file_text)4034   const FileDescriptor* BuildFile(absl::string_view file_text) {
4035     FileDescriptorProto file_proto;
4036     EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
4037     return ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
4038   }
4039 
ParseFile(absl::string_view file_name,absl::string_view file_text)4040   FileDescriptorProto ParseFile(absl::string_view file_name,
4041                                 absl::string_view file_text) {
4042     io::ArrayInputStream input_stream(file_text.data(), file_text.size());
4043     SimpleErrorCollector error_collector;
4044     io::Tokenizer tokenizer(&input_stream, &error_collector);
4045     compiler::Parser parser;
4046     parser.RecordErrorsTo(&error_collector);
4047     FileDescriptorProto proto;
4048     ABSL_CHECK(parser.Parse(&tokenizer, &proto))
4049         << error_collector.last_error() << "\n"
4050         << file_text;
4051     ABSL_CHECK_EQ("", error_collector.last_error());
4052     proto.set_name(file_name);
4053     return proto;
4054   }
4055 
ParseAndBuildFile(absl::string_view file_name,absl::string_view file_text)4056   const FileDescriptor* ParseAndBuildFile(absl::string_view file_name,
4057                                           absl::string_view file_text) {
4058     return pool_.BuildFile(ParseFile(file_name, file_text));
4059   }
4060 
4061 
4062   // Add file_proto to the DescriptorPool. Expect errors to be produced which
4063   // match the given error text.
BuildFileWithErrors(const FileDescriptorProto & file_proto,const std::string & expected_errors)4064   void BuildFileWithErrors(const FileDescriptorProto& file_proto,
4065                            const std::string& expected_errors) {
4066     MockErrorCollector error_collector;
4067     EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
4068                 nullptr);
4069     EXPECT_EQ(expected_errors, error_collector.text_);
4070   }
4071 
4072   // Parse file_text as a FileDescriptorProto in text format and add it
4073   // to the DescriptorPool.  Expect errors to be produced which match the
4074   // given error text.
BuildFileWithErrors(const std::string & file_text,const std::string & expected_errors)4075   void BuildFileWithErrors(const std::string& file_text,
4076                            const std::string& expected_errors) {
4077     FileDescriptorProto file_proto;
4078     ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
4079     BuildFileWithErrors(file_proto, expected_errors);
4080   }
4081 
4082   // Parse a proto file and build it.  Expect errors to be produced which match
4083   // the given error text.
ParseAndBuildFileWithErrors(absl::string_view file_name,absl::string_view file_text,absl::string_view expected_errors)4084   void ParseAndBuildFileWithErrors(absl::string_view file_name,
4085                                    absl::string_view file_text,
4086                                    absl::string_view expected_errors) {
4087     MockErrorCollector error_collector;
4088     EXPECT_TRUE(pool_.BuildFileCollectingErrors(ParseFile(file_name, file_text),
4089                                                 &error_collector) == nullptr);
4090     EXPECT_EQ(expected_errors, error_collector.text_);
4091   }
4092 
4093   // Parse file_text as a FileDescriptorProto in text format and add it
4094   // to the DescriptorPool.  Expect errors to be produced which match the
4095   // given warning text.
BuildFileWithWarnings(const std::string & file_text,const std::string & expected_warnings)4096   void BuildFileWithWarnings(const std::string& file_text,
4097                              const std::string& expected_warnings) {
4098     FileDescriptorProto file_proto;
4099     ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
4100 
4101     MockErrorCollector error_collector;
4102     EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector));
4103     EXPECT_EQ(expected_warnings, error_collector.warning_text_);
4104   }
4105 
4106   // Builds some already-parsed file in our test pool.
BuildFileInTestPool(const FileDescriptor * file)4107   void BuildFileInTestPool(const FileDescriptor* file) {
4108     FileDescriptorProto file_proto;
4109     file->CopyTo(&file_proto);
4110     ASSERT_TRUE(pool_.BuildFile(file_proto) != nullptr);
4111   }
4112 
4113   // Build descriptor.proto in our test pool. This allows us to extend it in
4114   // the test pool, so we can test custom options.
BuildDescriptorMessagesInTestPool()4115   void BuildDescriptorMessagesInTestPool() {
4116     BuildFileInTestPool(DescriptorProto::descriptor()->file());
4117   }
4118 
BuildDescriptorMessagesInTestPoolWithErrors(absl::string_view expected_errors)4119   void BuildDescriptorMessagesInTestPoolWithErrors(
4120       absl::string_view expected_errors) {
4121     FileDescriptorProto file_proto;
4122     DescriptorProto::descriptor()->file()->CopyTo(&file_proto);
4123     MockErrorCollector error_collector;
4124     EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
4125                 nullptr);
4126     EXPECT_EQ(error_collector.text_, expected_errors);
4127   }
4128 
4129   DescriptorPool pool_;
4130 };
4131 
TEST_F(ValidationErrorTest,AlreadyDefined)4132 TEST_F(ValidationErrorTest, AlreadyDefined) {
4133   BuildFileWithErrors(
4134       "name: \"foo.proto\" "
4135       "message_type { name: \"Foo\" }"
4136       "message_type { name: \"Foo\" }",
4137 
4138       "foo.proto: Foo: NAME: \"Foo\" is already defined.\n");
4139 }
4140 
TEST_F(ValidationErrorTest,AlreadyDefinedInPackage)4141 TEST_F(ValidationErrorTest, AlreadyDefinedInPackage) {
4142   BuildFileWithErrors(
4143       "name: \"foo.proto\" "
4144       "package: \"foo.bar\" "
4145       "message_type { name: \"Foo\" }"
4146       "message_type { name: \"Foo\" }",
4147 
4148       "foo.proto: foo.bar.Foo: NAME: \"Foo\" is already defined in "
4149       "\"foo.bar\".\n");
4150 }
4151 
TEST_F(ValidationErrorTest,AlreadyDefinedInOtherFile)4152 TEST_F(ValidationErrorTest, AlreadyDefinedInOtherFile) {
4153   BuildFile(
4154       "name: \"foo.proto\" "
4155       "message_type { name: \"Foo\" }");
4156 
4157   BuildFileWithErrors(
4158       "name: \"bar.proto\" "
4159       "message_type { name: \"Foo\" }",
4160 
4161       "bar.proto: Foo: NAME: \"Foo\" is already defined in file "
4162       "\"foo.proto\".\n");
4163 }
4164 
TEST_F(ValidationErrorTest,PackageAlreadyDefined)4165 TEST_F(ValidationErrorTest, PackageAlreadyDefined) {
4166   BuildFile(
4167       "name: \"foo.proto\" "
4168       "message_type { name: \"foo\" }");
4169   BuildFileWithErrors(
4170       "name: \"bar.proto\" "
4171       "package: \"foo.bar\"",
4172 
4173       "bar.proto: foo: NAME: \"foo\" is already defined (as something other "
4174       "than a package) in file \"foo.proto\".\n");
4175 }
4176 
TEST_F(ValidationErrorTest,EnumValueAlreadyDefinedInParent)4177 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) {
4178   BuildFileWithErrors(
4179       "name: \"foo.proto\" "
4180       "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
4181       "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
4182 
4183       "foo.proto: FOO: NAME: \"FOO\" is already defined.\n"
4184       "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, "
4185       "meaning that enum values are siblings of their type, not children of "
4186       "it.  Therefore, \"FOO\" must be unique within the global scope, not "
4187       "just within \"Bar\".\n");
4188 }
4189 
TEST_F(ValidationErrorTest,EnumValueAlreadyDefinedInParentNonGlobal)4190 TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) {
4191   BuildFileWithErrors(
4192       "name: \"foo.proto\" "
4193       "package: \"pkg\" "
4194       "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
4195       "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
4196 
4197       "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n"
4198       "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, "
4199       "meaning that enum values are siblings of their type, not children of "
4200       "it.  Therefore, \"FOO\" must be unique within \"pkg\", not just within "
4201       "\"Bar\".\n");
4202 }
4203 
TEST_F(ValidationErrorTest,MissingName)4204 TEST_F(ValidationErrorTest, MissingName) {
4205   BuildFileWithErrors(
4206       "name: \"foo.proto\" "
4207       "message_type { }",
4208 
4209       "foo.proto: : NAME: Missing name.\n");
4210 }
4211 
TEST_F(ValidationErrorTest,InvalidName)4212 TEST_F(ValidationErrorTest, InvalidName) {
4213   BuildFileWithErrors(
4214       "name: \"foo.proto\" "
4215       "message_type { name: \"$\" }",
4216 
4217       "foo.proto: $: NAME: \"$\" is not a valid identifier.\n");
4218 }
4219 
TEST_F(ValidationErrorTest,InvalidPackageName)4220 TEST_F(ValidationErrorTest, InvalidPackageName) {
4221   BuildFileWithErrors(
4222       "name: \"foo.proto\" "
4223       "package: \"foo.$\"",
4224 
4225       "foo.proto: foo.$: NAME: \"$\" is not a valid identifier.\n");
4226 }
4227 
4228 // 'str' is a static C-style string that may contain '\0'
4229 #define STATIC_STR(str) std::string((str), sizeof(str) - 1)
4230 
TEST_F(ValidationErrorTest,NullCharSymbolName)4231 TEST_F(ValidationErrorTest, NullCharSymbolName) {
4232   BuildFileWithErrors(
4233       "name: \"bar.proto\" "
4234       "package: \"foo\""
4235       "message_type { "
4236       "  name: '\\000\\001\\013.Bar' "
4237       "  field { name: \"foo\" number:  9 label:LABEL_OPTIONAL type:TYPE_INT32 "
4238       "} "
4239       "}",
4240       STATIC_STR("bar.proto: foo.\0\x1\v.Bar: NAME: \"\0\x1\v.Bar\" is not a "
4241                  "valid identifier.\nbar.proto: foo.\0\x1\v.Bar.foo: NAME: "
4242                  "\"foo.\0\x1\v.Bar.foo\" contains null character.\nbar.proto: "
4243                  "foo.\0\x1\v.Bar: NAME: \"foo.\0\x1\v.Bar\" contains null "
4244                  "character.\n"));
4245 }
4246 
TEST_F(ValidationErrorTest,NullCharFileName)4247 TEST_F(ValidationErrorTest, NullCharFileName) {
4248   BuildFileWithErrors(
4249       "name: \"bar\\000\\001\\013.proto\" "
4250       "package: \"outer.foo\"",
4251       STATIC_STR("bar\0\x1\v.proto: bar\0\x1\v.proto: NAME: "
4252                  "\"bar\0\x1\v.proto\" contains null character.\n"));
4253 }
4254 
TEST_F(ValidationErrorTest,NullCharPackageName)4255 TEST_F(ValidationErrorTest, NullCharPackageName) {
4256   BuildFileWithErrors(
4257       "name: \"bar.proto\" "
4258       "package: \"\\000\\001\\013.\"",
4259       STATIC_STR("bar.proto: \0\x1\v.: NAME: \"\0\x1\v.\" contains null "
4260                  "character.\n"));
4261 }
4262 
TEST_F(ValidationErrorTest,MissingFileName)4263 TEST_F(ValidationErrorTest, MissingFileName) {
4264   BuildFileWithErrors("",
4265 
4266                       ": : OTHER: Missing field: FileDescriptorProto.name.\n");
4267 }
4268 
TEST_F(ValidationErrorTest,DupeDependency)4269 TEST_F(ValidationErrorTest, DupeDependency) {
4270   BuildFile("name: \"foo.proto\"");
4271   BuildFileWithErrors(
4272       "name: \"bar.proto\" "
4273       "dependency: \"foo.proto\" "
4274       "dependency: \"foo.proto\" ",
4275 
4276       "bar.proto: foo.proto: IMPORT: Import \"foo.proto\" was listed twice.\n");
4277 }
4278 
TEST_F(ValidationErrorTest,UnknownDependency)4279 TEST_F(ValidationErrorTest, UnknownDependency) {
4280   BuildFileWithErrors(
4281       "name: \"bar.proto\" "
4282       "dependency: \"foo.proto\" ",
4283 
4284       "bar.proto: foo.proto: IMPORT: Import \"foo.proto\" has not been "
4285       "loaded.\n");
4286 }
4287 
TEST_F(ValidationErrorTest,InvalidPublicDependencyIndex)4288 TEST_F(ValidationErrorTest, InvalidPublicDependencyIndex) {
4289   BuildFile("name: \"foo.proto\"");
4290   BuildFileWithErrors(
4291       "name: \"bar.proto\" "
4292       "dependency: \"foo.proto\" "
4293       "public_dependency: 1",
4294       "bar.proto: bar.proto: OTHER: Invalid public dependency index.\n");
4295 }
4296 
TEST_F(ValidationErrorTest,ForeignUnimportedPackageNoCrash)4297 TEST_F(ValidationErrorTest, ForeignUnimportedPackageNoCrash) {
4298   // Used to crash:  If we depend on a non-existent file and then refer to a
4299   // package defined in a file that we didn't import, and that package is
4300   // nested within a parent package which this file is also in, and we don't
4301   // include that parent package in the name (i.e. we do a relative lookup)...
4302   // Yes, really.
4303   BuildFile(
4304       "name: 'foo.proto' "
4305       "package: 'outer.foo' ");
4306   BuildFileWithErrors(
4307       "name: 'bar.proto' "
4308       "dependency: 'baz.proto' "
4309       "package: 'outer.bar' "
4310       "message_type { "
4311       "  name: 'Bar' "
4312       "  field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'foo.Foo' }"
4313       "}",
4314 
4315       "bar.proto: baz.proto: IMPORT: Import \"baz.proto\" has not been "
4316       "loaded.\n"
4317       "bar.proto: outer.bar.Bar.bar: TYPE: \"outer.foo\" seems to be defined "
4318       "in "
4319       "\"foo.proto\", which is not imported by \"bar.proto\".  To use it here, "
4320       "please add the necessary import.\n");
4321 }
4322 
TEST_F(ValidationErrorTest,DupeFile)4323 TEST_F(ValidationErrorTest, DupeFile) {
4324   BuildFile(
4325       "name: \"foo.proto\" "
4326       "message_type { name: \"Foo\" }");
4327   // Note:  We should *not* get redundant errors about "Foo" already being
4328   //   defined.
4329   BuildFileWithErrors(
4330       "name: \"foo.proto\" "
4331       "message_type { name: \"Foo\" } "
4332       // Add another type so that the files aren't identical (in which case
4333       // there would be no error).
4334       "enum_type { name: \"Bar\" }",
4335 
4336       "foo.proto: foo.proto: OTHER: A file with this name is already in the "
4337       "pool.\n");
4338 }
4339 
TEST_F(ValidationErrorTest,FieldInExtensionRange)4340 TEST_F(ValidationErrorTest, FieldInExtensionRange) {
4341   BuildFileWithErrors(
4342       "name: \"foo.proto\" "
4343       "message_type {"
4344       "  name: \"Foo\""
4345       "  field { name: \"foo\" number:  9 label:LABEL_OPTIONAL type:TYPE_INT32 "
4346       "}"
4347       "  field { name: \"bar\" number: 10 label:LABEL_OPTIONAL type:TYPE_INT32 "
4348       "}"
4349       "  field { name: \"baz\" number: 19 label:LABEL_OPTIONAL type:TYPE_INT32 "
4350       "}"
4351       "  field { name: \"moo\" number: 20 label:LABEL_OPTIONAL type:TYPE_INT32 "
4352       "}"
4353       "  extension_range { start: 10 end: 20 }"
4354       "}",
4355 
4356       "foo.proto: Foo.bar: NUMBER: Extension range 10 to 19 includes field "
4357       "\"bar\" (10).\n"
4358       "foo.proto: Foo.baz: NUMBER: Extension range 10 to 19 includes field "
4359       "\"baz\" (19).\n"
4360       "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1, 2\n");
4361 }
4362 
TEST_F(ValidationErrorTest,OverlappingExtensionRanges)4363 TEST_F(ValidationErrorTest, OverlappingExtensionRanges) {
4364   BuildFileWithErrors(
4365       "name: \"foo.proto\" "
4366       "message_type {"
4367       "  name: \"Foo\""
4368       "  extension_range { start: 10 end: 20 }"
4369       "  extension_range { start: 20 end: 30 }"
4370       "  extension_range { start: 19 end: 21 }"
4371       "}",
4372 
4373       "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
4374       "already-defined range 10 to 19.\n"
4375       "foo.proto: Foo: NUMBER: Extension range 19 to 20 overlaps with "
4376       "already-defined range 20 to 29.\n");
4377 }
4378 
TEST_F(ValidationErrorTest,ReservedFieldError)4379 TEST_F(ValidationErrorTest, ReservedFieldError) {
4380   BuildFileWithErrors(
4381       "name: \"foo.proto\" "
4382       "message_type {"
4383       "  name: \"Foo\""
4384       "  field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 "
4385       "}"
4386       "  reserved_range { start: 10 end: 20 }"
4387       "}",
4388 
4389       "foo.proto: Foo.foo: NUMBER: Field \"foo\" uses reserved number 15.\n"
4390       "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1\n");
4391 }
4392 
TEST_F(ValidationErrorTest,ReservedExtensionRangeError)4393 TEST_F(ValidationErrorTest, ReservedExtensionRangeError) {
4394   BuildFileWithErrors(
4395       "name: \"foo.proto\" "
4396       "message_type {"
4397       "  name: \"Foo\""
4398       "  extension_range { start: 10 end: 20 }"
4399       "  reserved_range { start: 5 end: 15 }"
4400       "}",
4401 
4402       "foo.proto: Foo: NUMBER: Extension range 10 to 19"
4403       " overlaps with reserved range 5 to 14.\n");
4404 }
4405 
TEST_F(ValidationErrorTest,ReservedExtensionRangeAdjacent)4406 TEST_F(ValidationErrorTest, ReservedExtensionRangeAdjacent) {
4407   BuildFile(
4408       "name: \"foo.proto\" "
4409       "message_type {"
4410       "  name: \"Foo\""
4411       "  extension_range { start: 10 end: 20 }"
4412       "  reserved_range { start: 5 end: 10 }"
4413       "}");
4414 }
4415 
TEST_F(ValidationErrorTest,ReservedRangeOverlap)4416 TEST_F(ValidationErrorTest, ReservedRangeOverlap) {
4417   BuildFileWithErrors(
4418       "name: \"foo.proto\" "
4419       "message_type {"
4420       "  name: \"Foo\""
4421       "  reserved_range { start: 10 end: 20 }"
4422       "  reserved_range { start: 5 end: 15 }"
4423       "}",
4424 
4425       "foo.proto: Foo: NUMBER: Reserved range 5 to 14"
4426       " overlaps with already-defined range 10 to 19.\n");
4427 }
4428 
TEST_F(ValidationErrorTest,ReservedNameError)4429 TEST_F(ValidationErrorTest, ReservedNameError) {
4430   BuildFileWithErrors(
4431       "name: \"foo.proto\" "
4432       "message_type {"
4433       "  name: \"Foo\""
4434       "  field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 "
4435       "}"
4436       "  field { name: \"bar\" number: 16 label:LABEL_OPTIONAL type:TYPE_INT32 "
4437       "}"
4438       "  field { name: \"baz\" number: 17 label:LABEL_OPTIONAL type:TYPE_INT32 "
4439       "}"
4440       "  reserved_name: \"foo\""
4441       "  reserved_name: \"bar\""
4442       "}",
4443 
4444       "foo.proto: Foo.foo: NAME: Field name \"foo\" is reserved.\n"
4445       "foo.proto: Foo.bar: NAME: Field name \"bar\" is reserved.\n");
4446 }
4447 
TEST_F(ValidationErrorTest,ReservedNameRedundant)4448 TEST_F(ValidationErrorTest, ReservedNameRedundant) {
4449   BuildFileWithErrors(
4450       "name: \"foo.proto\" "
4451       "message_type {"
4452       "  name: \"Foo\""
4453       "  reserved_name: \"foo\""
4454       "  reserved_name: \"foo\""
4455       "}",
4456 
4457       "foo.proto: foo: NAME: Field name \"foo\" is reserved multiple times.\n");
4458 }
4459 
TEST_F(ValidationErrorTest,ReservedFieldsDebugString)4460 TEST_F(ValidationErrorTest, ReservedFieldsDebugString) {
4461   const FileDescriptor* file = BuildFile(
4462       "name: \"foo.proto\" "
4463       "message_type {"
4464       "  name: \"Foo\""
4465       "  reserved_name: \"foo\""
4466       "  reserved_name: \"bar\""
4467       "  reserved_range { start: 5 end: 6 }"
4468       "  reserved_range { start: 10 end: 20 }"
4469       "}");
4470 
4471   ASSERT_EQ(
4472       "syntax = \"proto2\";\n\n"
4473       "message Foo {\n"
4474       "  reserved 5, 10 to 19;\n"
4475       "  reserved \"foo\", \"bar\";\n"
4476       "}\n\n",
4477       file->DebugString());
4478 }
4479 
TEST_F(ValidationErrorTest,ReservedFieldsDebugString2023)4480 TEST_F(ValidationErrorTest, ReservedFieldsDebugString2023) {
4481   const FileDescriptor* file = BuildFile(R"pb(
4482     syntax: "editions"
4483     edition: EDITION_2023
4484     name: "foo.proto"
4485     message_type {
4486       name: "Foo"
4487       reserved_name: "foo"
4488       reserved_name: "bar"
4489       reserved_range { start: 5 end: 6 }
4490       reserved_range { start: 10 end: 20 }
4491     })pb");
4492 
4493   ASSERT_EQ(
4494       "edition = \"2023\";\n\n"
4495       "message Foo {\n"
4496       "  reserved 5, 10 to 19;\n"
4497       "  reserved foo, bar;\n"
4498       "}\n\n",
4499       file->DebugString());
4500 }
4501 
TEST_F(ValidationErrorTest,DebugStringReservedRangeMax)4502 TEST_F(ValidationErrorTest, DebugStringReservedRangeMax) {
4503   const FileDescriptor* file = BuildFile(absl::Substitute(
4504       "name: \"foo.proto\" "
4505       "enum_type { "
4506       "  name: \"Bar\""
4507       "  value { name:\"BAR\" number:1 }"
4508       "  reserved_range { start: 5 end: $0 }"
4509       "}"
4510       "message_type {"
4511       "  name: \"Foo\""
4512       "  reserved_range { start: 5 end: $1 }"
4513       "}",
4514       std::numeric_limits<int>::max(), FieldDescriptor::kMaxNumber + 1));
4515 
4516   ASSERT_EQ(
4517       "syntax = \"proto2\";\n\n"
4518       "enum Bar {\n"
4519       "  BAR = 1;\n"
4520       "  reserved 5 to max;\n"
4521       "}\n\n"
4522       "message Foo {\n"
4523       "  reserved 5 to max;\n"
4524       "}\n\n",
4525       file->DebugString());
4526 }
4527 
TEST_F(ValidationErrorTest,EnumReservedFieldError)4528 TEST_F(ValidationErrorTest, EnumReservedFieldError) {
4529   BuildFileWithErrors(
4530       "name: \"foo.proto\" "
4531       "enum_type {"
4532       "  name: \"Foo\""
4533       "  value { name:\"BAR\" number:15 }"
4534       "  reserved_range { start: 10 end: 20 }"
4535       "}",
4536 
4537       "foo.proto: BAR: NUMBER: Enum value \"BAR\" uses reserved number 15.\n");
4538 }
4539 
TEST_F(ValidationErrorTest,EnumNegativeReservedFieldError)4540 TEST_F(ValidationErrorTest, EnumNegativeReservedFieldError) {
4541   BuildFileWithErrors(
4542       "name: \"foo.proto\" "
4543       "enum_type {"
4544       "  name: \"Foo\""
4545       "  value { name:\"BAR\" number:-15 }"
4546       "  reserved_range { start: -20 end: -10 }"
4547       "}",
4548 
4549       "foo.proto: BAR: NUMBER: Enum value \"BAR\" uses reserved number -15.\n");
4550 }
4551 
TEST_F(ValidationErrorTest,EnumReservedRangeOverlap)4552 TEST_F(ValidationErrorTest, EnumReservedRangeOverlap) {
4553   BuildFileWithErrors(
4554       "name: \"foo.proto\" "
4555       "enum_type {"
4556       "  name: \"Foo\""
4557       "  value { name:\"BAR\" number:0 }"
4558       "  reserved_range { start: 10 end: 20 }"
4559       "  reserved_range { start: 5 end: 15 }"
4560       "}",
4561 
4562       "foo.proto: Foo: NUMBER: Reserved range 5 to 15"
4563       " overlaps with already-defined range 10 to 20.\n");
4564 }
4565 
TEST_F(ValidationErrorTest,EnumReservedRangeOverlapByOne)4566 TEST_F(ValidationErrorTest, EnumReservedRangeOverlapByOne) {
4567   BuildFileWithErrors(
4568       "name: \"foo.proto\" "
4569       "enum_type {"
4570       "  name: \"Foo\""
4571       "  value { name:\"BAR\" number:0 }"
4572       "  reserved_range { start: 10 end: 20 }"
4573       "  reserved_range { start: 5 end: 10 }"
4574       "}",
4575 
4576       "foo.proto: Foo: NUMBER: Reserved range 5 to 10"
4577       " overlaps with already-defined range 10 to 20.\n");
4578 }
4579 
TEST_F(ValidationErrorTest,EnumNegativeReservedRangeOverlap)4580 TEST_F(ValidationErrorTest, EnumNegativeReservedRangeOverlap) {
4581   BuildFileWithErrors(
4582       "name: \"foo.proto\" "
4583       "enum_type {"
4584       "  name: \"Foo\""
4585       "  value { name:\"BAR\" number:0 }"
4586       "  reserved_range { start: -20 end: -10 }"
4587       "  reserved_range { start: -15 end: -5 }"
4588       "}",
4589 
4590       "foo.proto: Foo: NUMBER: Reserved range -15 to -5"
4591       " overlaps with already-defined range -20 to -10.\n");
4592 }
4593 
TEST_F(ValidationErrorTest,EnumMixedReservedRangeOverlap)4594 TEST_F(ValidationErrorTest, EnumMixedReservedRangeOverlap) {
4595   BuildFileWithErrors(
4596       "name: \"foo.proto\" "
4597       "enum_type {"
4598       "  name: \"Foo\""
4599       "  value { name:\"BAR\" number:20 }"
4600       "  reserved_range { start: -20 end: 10 }"
4601       "  reserved_range { start: -15 end: 5 }"
4602       "}",
4603 
4604       "foo.proto: Foo: NUMBER: Reserved range -15 to 5"
4605       " overlaps with already-defined range -20 to 10.\n");
4606 }
4607 
TEST_F(ValidationErrorTest,EnumMixedReservedRangeOverlap2)4608 TEST_F(ValidationErrorTest, EnumMixedReservedRangeOverlap2) {
4609   BuildFileWithErrors(
4610       "name: \"foo.proto\" "
4611       "enum_type {"
4612       "  name: \"Foo\""
4613       "  value { name:\"BAR\" number:20 }"
4614       "  reserved_range { start: -20 end: 10 }"
4615       "  reserved_range { start: 10 end: 10 }"
4616       "}",
4617 
4618       "foo.proto: Foo: NUMBER: Reserved range 10 to 10"
4619       " overlaps with already-defined range -20 to 10.\n");
4620 }
4621 
TEST_F(ValidationErrorTest,EnumReservedRangeStartGreaterThanEnd)4622 TEST_F(ValidationErrorTest, EnumReservedRangeStartGreaterThanEnd) {
4623   BuildFileWithErrors(
4624       "name: \"foo.proto\" "
4625       "enum_type {"
4626       "  name: \"Foo\""
4627       "  value { name:\"BAR\" number:20 }"
4628       "  reserved_range { start: 11 end: 10 }"
4629       "}",
4630 
4631       "foo.proto: Foo: NUMBER: Reserved range end number must be greater"
4632       " than start number.\n");
4633 }
4634 
TEST_F(ValidationErrorTest,EnumReservedNameError)4635 TEST_F(ValidationErrorTest, EnumReservedNameError) {
4636   BuildFileWithErrors(
4637       "name: \"foo.proto\" "
4638       "enum_type {"
4639       "  name: \"Foo\""
4640       "  value { name:\"FOO\" number:15 }"
4641       "  value { name:\"BAR\" number:15 }"
4642       "  reserved_name: \"FOO\""
4643       "  reserved_name: \"BAR\""
4644       "}",
4645 
4646       "foo.proto: FOO: NAME: Enum value \"FOO\" is reserved.\n"
4647       "foo.proto: BAR: NAME: Enum value \"BAR\" is reserved.\n");
4648 }
4649 
TEST_F(ValidationErrorTest,EnumReservedNameRedundant)4650 TEST_F(ValidationErrorTest, EnumReservedNameRedundant) {
4651   BuildFileWithErrors(
4652       "name: \"foo.proto\" "
4653       "enum_type {"
4654       "  name: \"Foo\""
4655       "  value { name:\"FOO\" number:15 }"
4656       "  reserved_name: \"foo\""
4657       "  reserved_name: \"foo\""
4658       "}",
4659 
4660       "foo.proto: foo: NAME: Enum value \"foo\" is reserved multiple times.\n");
4661 }
4662 
TEST_F(ValidationErrorTest,EnumReservedFieldsDebugString)4663 TEST_F(ValidationErrorTest, EnumReservedFieldsDebugString) {
4664   const FileDescriptor* file = BuildFile(
4665       "name: \"foo.proto\" "
4666       "enum_type {"
4667       "  name: \"Foo\""
4668       "  value { name:\"FOO\" number:3 }"
4669       "  reserved_name: \"foo\""
4670       "  reserved_name: \"bar\""
4671       "  reserved_range { start: -6 end: -6 }"
4672       "  reserved_range { start: -5 end: -4 }"
4673       "  reserved_range { start: -1 end: 1 }"
4674       "  reserved_range { start: 5 end: 5 }"
4675       "  reserved_range { start: 10 end: 19 }"
4676       "}");
4677 
4678   ASSERT_EQ(
4679       "syntax = \"proto2\";\n\n"
4680       "enum Foo {\n"
4681       "  FOO = 3;\n"
4682       "  reserved -6, -5 to -4, -1 to 1, 5, 10 to 19;\n"
4683       "  reserved \"foo\", \"bar\";\n"
4684       "}\n\n",
4685       file->DebugString());
4686 }
4687 
TEST_F(ValidationErrorTest,EnumReservedFieldsDebugString2023)4688 TEST_F(ValidationErrorTest, EnumReservedFieldsDebugString2023) {
4689   const FileDescriptor* file = BuildFile(R"pb(
4690     syntax: "editions"
4691     edition: EDITION_2023
4692     name: "foo.proto"
4693     enum_type {
4694       name: "Foo"
4695       value { name: "FOO" number: 3 }
4696       options { features { enum_type: CLOSED } }
4697       reserved_name: "foo"
4698       reserved_name: "bar"
4699       reserved_range { start: -6 end: -6 }
4700       reserved_range { start: -5 end: -4 }
4701       reserved_range { start: -1 end: 1 }
4702       reserved_range { start: 5 end: 5 }
4703       reserved_range { start: 10 end: 19 }
4704     })pb");
4705 
4706   ASSERT_EQ(
4707       "edition = \"2023\";\n\n"
4708       "enum Foo {\n"
4709       "  option features = {\n"
4710       "    enum_type: CLOSED\n"
4711       "  };\n"
4712       "  FOO = 3;\n"
4713       "  reserved -6, -5 to -4, -1 to 1, 5, 10 to 19;\n"
4714       "  reserved foo, bar;\n"
4715       "}\n\n",
4716       file->DebugString());
4717 }
4718 
TEST_F(ValidationErrorTest,InvalidDefaults)4719 TEST_F(ValidationErrorTest, InvalidDefaults) {
4720   BuildFileWithErrors(
4721       "name: \"foo.proto\" "
4722       "message_type {"
4723       "  name: \"Foo\""
4724 
4725       // Invalid number.
4726       "  field { name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32"
4727       "          default_value: \"abc\" }"
4728 
4729       // Empty default value.
4730       "  field { name: \"bar\" number: 2 label: LABEL_OPTIONAL type: TYPE_INT32"
4731       "          default_value: \"\" }"
4732 
4733       // Invalid boolean.
4734       "  field { name: \"baz\" number: 3 label: LABEL_OPTIONAL type: TYPE_BOOL"
4735       "          default_value: \"abc\" }"
4736 
4737       // Messages can't have defaults.
4738       "  field { name: \"moo\" number: 4 label: LABEL_OPTIONAL type: "
4739       "TYPE_MESSAGE"
4740       "          default_value: \"abc\" type_name: \"Foo\" }"
4741 
4742       // Same thing, but we don't know that this field has message type until
4743       // we look up the type name.
4744       "  field { name: \"mooo\" number: 5 label: LABEL_OPTIONAL"
4745       "          default_value: \"abc\" type_name: \"Foo\" }"
4746 
4747       // Repeateds can't have defaults.
4748       "  field { name: \"corge\" number: 6 label: LABEL_REPEATED type: "
4749       "TYPE_INT32"
4750       "          default_value: \"1\" }"
4751 
4752       // Invalid CEscaped bytes default.
4753       "  field { name: \"bytes_default\" number: 7 label: LABEL_OPTIONAL "
4754       "          type: TYPE_BYTES"
4755       "          default_value: \"\\\\\" }"
4756 
4757       "}",
4758 
4759       "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value "
4760       "\"abc\".\n"
4761       "foo.proto: Foo.bar: DEFAULT_VALUE: Couldn't parse default value \"\".\n"
4762       "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or "
4763       "false.\n"
4764       "foo.proto: Foo.moo: DEFAULT_VALUE: Messages can't have default values.\n"
4765       "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default "
4766       "values.\n"
4767       "foo.proto: Foo.bytes_default: DEFAULT_VALUE: Invalid escaping in "
4768       "default value.\n"
4769       // This ends up being reported later because the error is detected at
4770       // cross-linking time.
4771       "foo.proto: Foo.mooo: DEFAULT_VALUE: Messages can't have default "
4772       "values.\n");
4773 }
4774 
TEST_F(ValidationErrorTest,NegativeFieldNumber)4775 TEST_F(ValidationErrorTest, NegativeFieldNumber) {
4776   BuildFileWithErrors(
4777       "name: \"foo.proto\" "
4778       "message_type {"
4779       "  name: \"Foo\""
4780       "  field { name: \"foo\" number: -1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4781       "}"
4782       "}",
4783 
4784       "foo.proto: Foo.foo: NUMBER: Field numbers must be positive integers.\n"
4785       "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1\n");
4786 }
4787 
TEST_F(ValidationErrorTest,HugeFieldNumber)4788 TEST_F(ValidationErrorTest, HugeFieldNumber) {
4789   BuildFileWithErrors(
4790       "name: \"foo.proto\" "
4791       "message_type {"
4792       "  name: \"Foo\""
4793       "  field { name: \"foo\" number: 0x70000000 "
4794       "          label:LABEL_OPTIONAL type:TYPE_INT32 }"
4795       "}",
4796 
4797       "foo.proto: Foo.foo: NUMBER: Field numbers cannot be greater than "
4798       "536870911.\n"
4799       "foo.proto: Foo: NUMBER: Suggested field numbers for Foo: 1\n");
4800 }
4801 
TEST_F(ValidationErrorTest,ExtensionMissingExtendee)4802 TEST_F(ValidationErrorTest, ExtensionMissingExtendee) {
4803   BuildFileWithErrors(
4804       "name: \"foo.proto\" "
4805       "message_type {"
4806       "  name: \"Foo\""
4807       "  extension { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
4808       "              type_name: \"Foo\" }"
4809       "}",
4810 
4811       "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee not set for "
4812       "extension field.\n");
4813 }
4814 
TEST_F(ValidationErrorTest,NonExtensionWithExtendee)4815 TEST_F(ValidationErrorTest, NonExtensionWithExtendee) {
4816   BuildFileWithErrors(
4817       "name: \"foo.proto\" "
4818       "message_type {"
4819       "  name: \"Bar\""
4820       "  extension_range { start: 1 end: 2 }"
4821       "}"
4822       "message_type {"
4823       "  name: \"Foo\""
4824       "  field { name: \"foo\" number: 1 label: LABEL_OPTIONAL"
4825       "          type_name: \"Foo\" extendee: \"Bar\" }"
4826       "}",
4827 
4828       "foo.proto: Foo.foo: EXTENDEE: FieldDescriptorProto.extendee set for "
4829       "non-extension field.\n");
4830 }
4831 
TEST_F(ValidationErrorTest,FieldOneofIndexTooLarge)4832 TEST_F(ValidationErrorTest, FieldOneofIndexTooLarge) {
4833   BuildFileWithErrors(
4834       "name: \"foo.proto\" "
4835       "message_type {"
4836       "  name: \"Foo\""
4837       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4838       "          oneof_index: 1 }"
4839       "  field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4840       "          oneof_index: 0 }"
4841       "  oneof_decl { name:\"bar\" }"
4842       "}",
4843 
4844       "foo.proto: Foo.foo: TYPE: FieldDescriptorProto.oneof_index 1 is out of "
4845       "range for type \"Foo\".\n");
4846 }
4847 
TEST_F(ValidationErrorTest,FieldOneofIndexNegative)4848 TEST_F(ValidationErrorTest, FieldOneofIndexNegative) {
4849   BuildFileWithErrors(
4850       "name: \"foo.proto\" "
4851       "message_type {"
4852       "  name: \"Foo\""
4853       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4854       "          oneof_index: -1 }"
4855       "  field { name:\"dummy\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4856       "          oneof_index: 0 }"
4857       "  oneof_decl { name:\"bar\" }"
4858       "}",
4859 
4860       "foo.proto: Foo.foo: TYPE: FieldDescriptorProto.oneof_index -1 is out "
4861       "of "
4862       "range for type \"Foo\".\n");
4863 }
4864 
TEST_F(ValidationErrorTest,OneofFieldsConsecutiveDefinition)4865 TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) {
4866   // Fields belonging to the same oneof must be defined consecutively.
4867   BuildFileWithErrors(
4868       "name: \"foo.proto\" "
4869       "message_type {"
4870       "  name: \"Foo\""
4871       "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4872       "          oneof_index: 0 }"
4873       "  field { name:\"bar\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4874       "  field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
4875       "          oneof_index: 0 }"
4876       "  oneof_decl { name:\"foos\" }"
4877       "}",
4878 
4879       "foo.proto: Foo.bar: TYPE: Fields in the same oneof must be defined "
4880       "consecutively. \"bar\" cannot be defined before the completion of the "
4881       "\"foos\" oneof definition.\n");
4882 
4883   // Prevent interleaved fields, which belong to different oneofs.
4884   BuildFileWithErrors(
4885       "name: \"foo2.proto\" "
4886       "message_type {"
4887       "  name: \"Foo2\""
4888       "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4889       "          oneof_index: 0 }"
4890       "  field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4891       "          oneof_index: 1 }"
4892       "  field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
4893       "          oneof_index: 0 }"
4894       "  field { name:\"bar2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
4895       "          oneof_index: 1 }"
4896       "  oneof_decl { name:\"foos\" }"
4897       "  oneof_decl { name:\"bars\" }"
4898       "}",
4899       "foo2.proto: Foo2.bar1: TYPE: Fields in the same oneof must be defined "
4900       "consecutively. \"bar1\" cannot be defined before the completion of the "
4901       "\"foos\" oneof definition.\n"
4902       "foo2.proto: Foo2.foo2: TYPE: Fields in the same oneof must be defined "
4903       "consecutively. \"foo2\" cannot be defined before the completion of the "
4904       "\"bars\" oneof definition.\n");
4905 
4906   // Another case for normal fields and different oneof fields interleave.
4907   BuildFileWithErrors(
4908       "name: \"foo3.proto\" "
4909       "message_type {"
4910       "  name: \"Foo3\""
4911       "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
4912       "          oneof_index: 0 }"
4913       "  field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
4914       "          oneof_index: 1 }"
4915       "  field { name:\"baz\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4916       "  field { name:\"foo2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
4917       "          oneof_index: 0 }"
4918       "  oneof_decl { name:\"foos\" }"
4919       "  oneof_decl { name:\"bars\" }"
4920       "}",
4921       "foo3.proto: Foo3.baz: TYPE: Fields in the same oneof must be defined "
4922       "consecutively. \"baz\" cannot be defined before the completion of the "
4923       "\"foos\" oneof definition.\n");
4924 }
4925 
TEST_F(ValidationErrorTest,FieldNumberConflict)4926 TEST_F(ValidationErrorTest, FieldNumberConflict) {
4927   BuildFileWithErrors(
4928       "name: \"foo.proto\" "
4929       "message_type {"
4930       "  name: \"Foo\""
4931       "  field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4932       "  field { name: \"bar\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4933       "}",
4934 
4935       "foo.proto: Foo.bar: NUMBER: Field number 1 has already been used in "
4936       "\"Foo\" by field \"foo\".\n");
4937 }
4938 
TEST_F(ValidationErrorTest,BadMessageSetExtensionType)4939 TEST_F(ValidationErrorTest, BadMessageSetExtensionType) {
4940   BuildFileWithErrors(
4941       "name: \"foo.proto\" "
4942       "message_type {"
4943       "  name: \"MessageSet\""
4944       "  options { message_set_wire_format: true }"
4945       "  extension_range { start: 4 end: 5 }"
4946       "}"
4947       "message_type {"
4948       "  name: \"Foo\""
4949       "  extension { name:\"foo\" number:4 label:LABEL_OPTIONAL type:TYPE_INT32"
4950       "              extendee: \"MessageSet\" }"
4951       "}",
4952 
4953       "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
4954       "messages.\n");
4955 }
4956 
TEST_F(ValidationErrorTest,BadMessageSetExtensionLabel)4957 TEST_F(ValidationErrorTest, BadMessageSetExtensionLabel) {
4958   BuildFileWithErrors(
4959       "name: \"foo.proto\" "
4960       "message_type {"
4961       "  name: \"MessageSet\""
4962       "  options { message_set_wire_format: true }"
4963       "  extension_range { start: 4 end: 5 }"
4964       "}"
4965       "message_type {"
4966       "  name: \"Foo\""
4967       "  extension { name:\"foo\" number:4 label:LABEL_REPEATED "
4968       "type:TYPE_MESSAGE"
4969       "              type_name: \"Foo\" extendee: \"MessageSet\" }"
4970       "}",
4971 
4972       "foo.proto: Foo.foo: TYPE: Extensions of MessageSets must be optional "
4973       "messages.\n");
4974 }
4975 
TEST_F(ValidationErrorTest,FieldInMessageSet)4976 TEST_F(ValidationErrorTest, FieldInMessageSet) {
4977   BuildFileWithErrors(
4978       "name: \"foo.proto\" "
4979       "message_type {"
4980       "  name: \"Foo\""
4981       "  options { message_set_wire_format: true }"
4982       "  field { name: \"foo\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
4983       "}",
4984 
4985       "foo.proto: Foo.foo: NAME: MessageSets cannot have fields, only "
4986       "extensions.\n");
4987 }
4988 
TEST_F(ValidationErrorTest,NegativeExtensionRangeNumber)4989 TEST_F(ValidationErrorTest, NegativeExtensionRangeNumber) {
4990   BuildFileWithErrors(
4991       "name: \"foo.proto\" "
4992       "message_type {"
4993       "  name: \"Foo\""
4994       "  extension_range { start: -10 end: -1 }"
4995       "}",
4996 
4997       "foo.proto: Foo: NUMBER: Extension numbers must be positive integers.\n");
4998 }
4999 
TEST_F(ValidationErrorTest,HugeExtensionRangeNumber)5000 TEST_F(ValidationErrorTest, HugeExtensionRangeNumber) {
5001   BuildFileWithErrors(
5002       "name: \"foo.proto\" "
5003       "message_type {"
5004       "  name: \"Foo\""
5005       "  extension_range { start: 1 end: 0x70000000 }"
5006       "}",
5007 
5008       "foo.proto: Foo: NUMBER: Extension numbers cannot be greater than "
5009       "536870911.\n");
5010 }
5011 
TEST_F(ValidationErrorTest,ExtensionRangeEndBeforeStart)5012 TEST_F(ValidationErrorTest, ExtensionRangeEndBeforeStart) {
5013   BuildFileWithErrors(
5014       "name: \"foo.proto\" "
5015       "message_type {"
5016       "  name: \"Foo\""
5017       "  extension_range { start: 10 end: 10 }"
5018       "  extension_range { start: 10 end: 5 }"
5019       "}",
5020 
5021       "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
5022       "start number.\n"
5023       "foo.proto: Foo: NUMBER: Extension range end number must be greater than "
5024       "start number.\n");
5025 }
5026 
TEST_F(ValidationErrorTest,EmptyEnum)5027 TEST_F(ValidationErrorTest, EmptyEnum) {
5028   BuildFileWithErrors(
5029       "name: \"foo.proto\" "
5030       "enum_type { name: \"Foo\" }"
5031       // Also use the empty enum in a message to make sure there are no crashes
5032       // during validation (possible if the code attempts to derive a default
5033       // value for the field).
5034       "message_type {"
5035       "  name: \"Bar\""
5036       "  field { name: \"foo\" number: 1 label:LABEL_OPTIONAL "
5037       "type_name:\"Foo\" }"
5038       "  field { name: \"bar\" number: 2 label:LABEL_OPTIONAL "
5039       "type_name:\"Foo\" "
5040       "          default_value: \"NO_SUCH_VALUE\" }"
5041       "}",
5042 
5043       "foo.proto: Foo: NAME: Enums must contain at least one value.\n"
5044       "foo.proto: Bar.bar: DEFAULT_VALUE: Enum type \"Foo\" has no value named "
5045       "\"NO_SUCH_VALUE\".\n");
5046 }
5047 
TEST_F(ValidationErrorTest,UndefinedExtendee)5048 TEST_F(ValidationErrorTest, UndefinedExtendee) {
5049   BuildFileWithErrors(
5050       "name: \"foo.proto\" "
5051       "message_type {"
5052       "  name: \"Foo\""
5053       "  extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
5054       "              extendee: \"Bar\" }"
5055       "}",
5056 
5057       "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not defined.\n");
5058 }
5059 
TEST_F(ValidationErrorTest,NonMessageExtendee)5060 TEST_F(ValidationErrorTest, NonMessageExtendee) {
5061   BuildFileWithErrors(
5062       "name: \"foo.proto\" "
5063       "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } }"
5064       "message_type {"
5065       "  name: \"Foo\""
5066       "  extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
5067       "              extendee: \"Bar\" }"
5068       "}",
5069 
5070       "foo.proto: Foo.foo: EXTENDEE: \"Bar\" is not a message type.\n");
5071 }
5072 
TEST_F(ValidationErrorTest,NotAnExtensionNumber)5073 TEST_F(ValidationErrorTest, NotAnExtensionNumber) {
5074   BuildFileWithErrors(
5075       "name: \"foo.proto\" "
5076       "message_type {"
5077       "  name: \"Bar\""
5078       "}"
5079       "message_type {"
5080       "  name: \"Foo\""
5081       "  extension { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
5082       "              extendee: \"Bar\" }"
5083       "}",
5084 
5085       "foo.proto: Foo.foo: NUMBER: \"Bar\" does not declare 1 as an extension "
5086       "number.\n");
5087 }
5088 
TEST_F(ValidationErrorTest,RequiredExtension)5089 TEST_F(ValidationErrorTest, RequiredExtension) {
5090   BuildFileWithErrors(
5091       "name: \"foo.proto\" "
5092       "message_type {"
5093       "  name: \"Bar\""
5094       "  extension_range { start: 1000 end: 10000 }"
5095       "}"
5096       "message_type {"
5097       "  name: \"Foo\""
5098       "  extension {"
5099       "    name:\"foo\""
5100       "    number:1000"
5101       "    label:LABEL_REQUIRED"
5102       "    type:TYPE_INT32"
5103       "    extendee: \"Bar\""
5104       "  }"
5105       "}",
5106 
5107       "foo.proto: Foo.foo: TYPE: The extension Foo.foo cannot be required.\n");
5108 }
5109 
TEST_F(ValidationErrorTest,UndefinedFieldType)5110 TEST_F(ValidationErrorTest, UndefinedFieldType) {
5111   BuildFileWithErrors(
5112       "name: \"foo.proto\" "
5113       "message_type {"
5114       "  name: \"Foo\""
5115       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5116       "}",
5117 
5118       "foo.proto: Foo.foo: TYPE: \"Bar\" is not defined.\n");
5119 }
5120 
TEST_F(ValidationErrorTest,UndefinedFieldTypeWithDefault)5121 TEST_F(ValidationErrorTest, UndefinedFieldTypeWithDefault) {
5122   // See b/12533582. Previously this failed because the default value was not
5123   // accepted by the parser, which assumed an enum type, leading to an unclear
5124   // error message. We want this input to yield a validation error instead,
5125   // since the unknown type is the primary problem.
5126   BuildFileWithErrors(
5127       "name: \"foo.proto\" "
5128       "message_type {"
5129       "  name: \"Foo\""
5130       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"int\" "
5131       "          default_value:\"1\" }"
5132       "}",
5133 
5134       "foo.proto: Foo.foo: TYPE: \"int\" is not defined.\n");
5135 }
5136 
TEST_F(ValidationErrorTest,UndefinedNestedFieldType)5137 TEST_F(ValidationErrorTest, UndefinedNestedFieldType) {
5138   BuildFileWithErrors(
5139       "name: \"foo.proto\" "
5140       "message_type {"
5141       "  name: \"Foo\""
5142       "  nested_type { name:\"Baz\" }"
5143       "  field { name:\"foo\" number:1"
5144       "          label:LABEL_OPTIONAL"
5145       "          type_name:\"Foo.Baz.Bar\" }"
5146       "}",
5147 
5148       "foo.proto: Foo.foo: TYPE: \"Foo.Baz.Bar\" is not defined.\n");
5149 }
5150 
TEST_F(ValidationErrorTest,FieldTypeDefinedInUndeclaredDependency)5151 TEST_F(ValidationErrorTest, FieldTypeDefinedInUndeclaredDependency) {
5152   BuildFile(
5153       "name: \"bar.proto\" "
5154       "message_type { name: \"Bar\" } ");
5155 
5156   BuildFileWithErrors(
5157       "name: \"foo.proto\" "
5158       "message_type {"
5159       "  name: \"Foo\""
5160       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5161       "}",
5162       "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
5163       "which is not imported by \"foo.proto\".  To use it here, please add the "
5164       "necessary import.\n");
5165 }
5166 
TEST_F(ValidationErrorTest,FieldTypeDefinedInIndirectDependency)5167 TEST_F(ValidationErrorTest, FieldTypeDefinedInIndirectDependency) {
5168   // Test for hidden dependencies.
5169   //
5170   // // bar.proto
5171   // message Bar{}
5172   //
5173   // // forward.proto
5174   // import "bar.proto"
5175   //
5176   // // foo.proto
5177   // import "forward.proto"
5178   // message Foo {
5179   //   optional Bar foo = 1;  // Error, needs to import bar.proto explicitly.
5180   // }
5181   //
5182   BuildFile(
5183       "name: \"bar.proto\" "
5184       "message_type { name: \"Bar\" }");
5185 
5186   BuildFile(
5187       "name: \"forward.proto\""
5188       "dependency: \"bar.proto\"");
5189 
5190   BuildFileWithErrors(
5191       "name: \"foo.proto\" "
5192       "dependency: \"forward.proto\" "
5193       "message_type {"
5194       "  name: \"Foo\""
5195       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5196       "}",
5197       "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
5198       "which is not imported by \"foo.proto\".  To use it here, please add the "
5199       "necessary import.\n");
5200 }
5201 
TEST_F(ValidationErrorTest,FieldTypeDefinedInPublicDependency)5202 TEST_F(ValidationErrorTest, FieldTypeDefinedInPublicDependency) {
5203   // Test for public dependencies.
5204   //
5205   // // bar.proto
5206   // message Bar{}
5207   //
5208   // // forward.proto
5209   // import public "bar.proto"
5210   //
5211   // // foo.proto
5212   // import "forward.proto"
5213   // message Foo {
5214   //   optional Bar foo = 1;  // Correct. "bar.proto" is public imported into
5215   //                          // forward.proto, so when "foo.proto" imports
5216   //                          // "forward.proto", it imports "bar.proto" too.
5217   // }
5218   //
5219   BuildFile(
5220       "name: \"bar.proto\" "
5221       "message_type { name: \"Bar\" }");
5222 
5223   BuildFile(
5224       "name: \"forward.proto\""
5225       "dependency: \"bar.proto\" "
5226       "public_dependency: 0");
5227 
5228   BuildFile(
5229       "name: \"foo.proto\" "
5230       "dependency: \"forward.proto\" "
5231       "message_type {"
5232       "  name: \"Foo\""
5233       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5234       "}");
5235 }
5236 
TEST_F(ValidationErrorTest,FieldTypeDefinedInTransitivePublicDependency)5237 TEST_F(ValidationErrorTest, FieldTypeDefinedInTransitivePublicDependency) {
5238   // Test for public dependencies.
5239   //
5240   // // bar.proto
5241   // message Bar{}
5242   //
5243   // // forward.proto
5244   // import public "bar.proto"
5245   //
5246   // // forward2.proto
5247   // import public "forward.proto"
5248   //
5249   // // foo.proto
5250   // import "forward2.proto"
5251   // message Foo {
5252   //   optional Bar foo = 1;  // Correct, public imports are transitive.
5253   // }
5254   //
5255   BuildFile(
5256       "name: \"bar.proto\" "
5257       "message_type { name: \"Bar\" }");
5258 
5259   BuildFile(
5260       "name: \"forward.proto\""
5261       "dependency: \"bar.proto\" "
5262       "public_dependency: 0");
5263 
5264   BuildFile(
5265       "name: \"forward2.proto\""
5266       "dependency: \"forward.proto\" "
5267       "public_dependency: 0");
5268 
5269   BuildFile(
5270       "name: \"foo.proto\" "
5271       "dependency: \"forward2.proto\" "
5272       "message_type {"
5273       "  name: \"Foo\""
5274       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5275       "}");
5276 }
5277 
TEST_F(ValidationErrorTest,FieldTypeDefinedInPrivateDependencyOfPublicDependency)5278 TEST_F(ValidationErrorTest,
5279        FieldTypeDefinedInPrivateDependencyOfPublicDependency) {
5280   // Test for public dependencies.
5281   //
5282   // // bar.proto
5283   // message Bar{}
5284   //
5285   // // forward.proto
5286   // import "bar.proto"
5287   //
5288   // // forward2.proto
5289   // import public "forward.proto"
5290   //
5291   // // foo.proto
5292   // import "forward2.proto"
5293   // message Foo {
5294   //   optional Bar foo = 1;  // Error, the "bar.proto" is not public imported
5295   //                          // into "forward.proto", so will not be imported
5296   //                          // into either "forward2.proto" or "foo.proto".
5297   // }
5298   //
5299   BuildFile(
5300       "name: \"bar.proto\" "
5301       "message_type { name: \"Bar\" }");
5302 
5303   BuildFile(
5304       "name: \"forward.proto\""
5305       "dependency: \"bar.proto\"");
5306 
5307   BuildFile(
5308       "name: \"forward2.proto\""
5309       "dependency: \"forward.proto\" "
5310       "public_dependency: 0");
5311 
5312   BuildFileWithErrors(
5313       "name: \"foo.proto\" "
5314       "dependency: \"forward2.proto\" "
5315       "message_type {"
5316       "  name: \"Foo\""
5317       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5318       "}",
5319       "foo.proto: Foo.foo: TYPE: \"Bar\" seems to be defined in \"bar.proto\", "
5320       "which is not imported by \"foo.proto\".  To use it here, please add the "
5321       "necessary import.\n");
5322 }
5323 
5324 
TEST_F(ValidationErrorTest,SearchMostLocalFirst)5325 TEST_F(ValidationErrorTest, SearchMostLocalFirst) {
5326   // The following should produce an error that Bar.Baz is resolved but
5327   // not defined:
5328   //   message Bar { message Baz {} }
5329   //   message Foo {
5330   //     message Bar {
5331   //       // Placing "message Baz{}" here, or removing Foo.Bar altogether,
5332   //       // would fix the error.
5333   //     }
5334   //     optional Bar.Baz baz = 1;
5335   //   }
5336   // An one point the lookup code incorrectly did not produce an error in this
5337   // case, because when looking for Bar.Baz, it would try "Foo.Bar.Baz" first,
5338   // fail, and ten try "Bar.Baz" and succeed, even though "Bar" should actually
5339   // refer to the inner Bar, not the outer one.
5340   BuildFileWithErrors(
5341       "name: \"foo.proto\" "
5342       "message_type {"
5343       "  name: \"Bar\""
5344       "  nested_type { name: \"Baz\" }"
5345       "}"
5346       "message_type {"
5347       "  name: \"Foo\""
5348       "  nested_type { name: \"Bar\" }"
5349       "  field { name:\"baz\" number:1 label:LABEL_OPTIONAL"
5350       "          type_name:\"Bar.Baz\" }"
5351       "}",
5352 
5353       "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is resolved to \"Foo.Bar.Baz\","
5354       " which is not defined. The innermost scope is searched first in name "
5355       "resolution. Consider using a leading '.'(i.e., \".Bar.Baz\") to start "
5356       "from the outermost scope.\n");
5357 }
5358 
TEST_F(ValidationErrorTest,SearchMostLocalFirst2)5359 TEST_F(ValidationErrorTest, SearchMostLocalFirst2) {
5360   // This test would find the most local "Bar" first, and does, but
5361   // proceeds to find the outer one because the inner one's not an
5362   // aggregate.
5363   BuildFile(
5364       "name: \"foo.proto\" "
5365       "message_type {"
5366       "  name: \"Bar\""
5367       "  nested_type { name: \"Baz\" }"
5368       "}"
5369       "message_type {"
5370       "  name: \"Foo\""
5371       "  field { name: \"Bar\" number:1 type:TYPE_BYTES } "
5372       "  field { name:\"baz\" number:2 label:LABEL_OPTIONAL"
5373       "          type_name:\"Bar.Baz\" }"
5374       "}");
5375 }
5376 
TEST_F(ValidationErrorTest,PackageOriginallyDeclaredInTransitiveDependent)5377 TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) {
5378   // Imagine we have the following:
5379   //
5380   // foo.proto:
5381   //   package foo.bar;
5382   // bar.proto:
5383   //   package foo.bar;
5384   //   import "foo.proto";
5385   //   message Bar {}
5386   // baz.proto:
5387   //   package foo;
5388   //   import "bar.proto"
5389   //   message Baz { optional bar.Bar moo = 1; }
5390   //
5391   // When validating baz.proto, we will look up "bar.Bar".  As part of this
5392   // lookup, we first lookup "bar" then try to find "Bar" within it.  "bar"
5393   // should resolve to "foo.bar".  Note, though, that "foo.bar" was originally
5394   // defined in foo.proto, which is not a direct dependency of baz.proto.  The
5395   // implementation of FindSymbol() normally only returns symbols in direct
5396   // dependencies, not indirect ones.  This test insures that this does not
5397   // prevent it from finding "foo.bar".
5398 
5399   BuildFile(
5400       "name: \"foo.proto\" "
5401       "package: \"foo.bar\" ");
5402   BuildFile(
5403       "name: \"bar.proto\" "
5404       "package: \"foo.bar\" "
5405       "dependency: \"foo.proto\" "
5406       "message_type { name: \"Bar\" }");
5407   BuildFile(
5408       "name: \"baz.proto\" "
5409       "package: \"foo\" "
5410       "dependency: \"bar.proto\" "
5411       "message_type { "
5412       "  name: \"Baz\" "
5413       "  field { name:\"moo\" number:1 label:LABEL_OPTIONAL "
5414       "          type_name:\"bar.Bar\" }"
5415       "}");
5416 }
5417 
TEST_F(ValidationErrorTest,FieldTypeNotAType)5418 TEST_F(ValidationErrorTest, FieldTypeNotAType) {
5419   BuildFileWithErrors(
5420       "name: \"foo.proto\" "
5421       "message_type {"
5422       "  name: \"Foo\""
5423       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
5424       "          type_name:\".Foo.bar\" }"
5425       "  field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
5426       "}",
5427 
5428       "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n");
5429 }
5430 
TEST_F(ValidationErrorTest,RelativeFieldTypeNotAType)5431 TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) {
5432   BuildFileWithErrors(
5433       "name: \"foo.proto\" "
5434       "message_type {"
5435       "  nested_type {"
5436       "    name: \"Bar\""
5437       "    field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
5438       "  }"
5439       "  name: \"Foo\""
5440       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL "
5441       "          type_name:\"Bar.Baz\" }"
5442       "}",
5443       "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n");
5444 }
5445 
TEST_F(ValidationErrorTest,FieldTypeMayBeItsName)5446 TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) {
5447   BuildFile(
5448       "name: \"foo.proto\" "
5449       "message_type {"
5450       "  name: \"Bar\""
5451       "}"
5452       "message_type {"
5453       "  name: \"Foo\""
5454       "  field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }"
5455       "}");
5456 }
5457 
TEST_F(ValidationErrorTest,EnumFieldTypeIsMessage)5458 TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) {
5459   BuildFileWithErrors(
5460       "name: \"foo.proto\" "
5461       "message_type { name: \"Bar\" } "
5462       "message_type {"
5463       "  name: \"Foo\""
5464       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM"
5465       "          type_name:\"Bar\" }"
5466       "}",
5467 
5468       "foo.proto: Foo.foo: TYPE: \"Bar\" is not an enum type.\n");
5469 }
5470 
TEST_F(ValidationErrorTest,MessageFieldTypeIsEnum)5471 TEST_F(ValidationErrorTest, MessageFieldTypeIsEnum) {
5472   BuildFileWithErrors(
5473       "name: \"foo.proto\" "
5474       "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5475       "message_type {"
5476       "  name: \"Foo\""
5477       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE"
5478       "          type_name:\"Bar\" }"
5479       "}",
5480 
5481       "foo.proto: Foo.foo: TYPE: \"Bar\" is not a message type.\n");
5482 }
5483 
TEST_F(ValidationErrorTest,BadEnumDefaultValue)5484 TEST_F(ValidationErrorTest, BadEnumDefaultValue) {
5485   BuildFileWithErrors(
5486       "name: \"foo.proto\" "
5487       "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5488       "message_type {"
5489       "  name: \"Foo\""
5490       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
5491       "          default_value:\"NO_SUCH_VALUE\" }"
5492       "}",
5493 
5494       "foo.proto: Foo.foo: DEFAULT_VALUE: Enum type \"Bar\" has no value named "
5495       "\"NO_SUCH_VALUE\".\n");
5496 }
5497 
TEST_F(ValidationErrorTest,EnumDefaultValueIsInteger)5498 TEST_F(ValidationErrorTest, EnumDefaultValueIsInteger) {
5499   BuildFileWithErrors(
5500       "name: \"foo.proto\" "
5501       "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5502       "message_type {"
5503       "  name: \"Foo\""
5504       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\""
5505       "          default_value:\"0\" }"
5506       "}",
5507 
5508       "foo.proto: Foo.foo: DEFAULT_VALUE: Default value for an enum field must "
5509       "be an identifier.\n");
5510 }
5511 
TEST_F(ValidationErrorTest,PrimitiveWithTypeName)5512 TEST_F(ValidationErrorTest, PrimitiveWithTypeName) {
5513   BuildFileWithErrors(
5514       "name: \"foo.proto\" "
5515       "message_type {"
5516       "  name: \"Foo\""
5517       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
5518       "          type_name:\"Foo\" }"
5519       "}",
5520 
5521       "foo.proto: Foo.foo: TYPE: Field with primitive type has type_name.\n");
5522 }
5523 
TEST_F(ValidationErrorTest,NonPrimitiveWithoutTypeName)5524 TEST_F(ValidationErrorTest, NonPrimitiveWithoutTypeName) {
5525   BuildFileWithErrors(
5526       "name: \"foo.proto\" "
5527       "message_type {"
5528       "  name: \"Foo\""
5529       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE }"
5530       "}",
5531 
5532       "foo.proto: Foo.foo: TYPE: Field with message or enum type missing "
5533       "type_name.\n");
5534 }
5535 
TEST_F(ValidationErrorTest,OneofWithNoFields)5536 TEST_F(ValidationErrorTest, OneofWithNoFields) {
5537   BuildFileWithErrors(
5538       "name: \"foo.proto\" "
5539       "message_type {"
5540       "  name: \"Foo\""
5541       "  oneof_decl { name:\"bar\" }"
5542       "}",
5543 
5544       "foo.proto: Foo.bar: NAME: Oneof must have at least one field.\n");
5545 }
5546 
TEST_F(ValidationErrorTest,OneofLabelMismatch)5547 TEST_F(ValidationErrorTest, OneofLabelMismatch) {
5548   BuildFileWithErrors(
5549       "name: \"foo.proto\" "
5550       "message_type {"
5551       "  name: \"Foo\""
5552       "  field { name:\"foo\" number:1 label:LABEL_REPEATED type:TYPE_INT32 "
5553       "          oneof_index:0 }"
5554       "  oneof_decl { name:\"bar\" }"
5555       "}",
5556 
5557       "foo.proto: Foo.foo: NAME: Fields of oneofs must themselves have label "
5558       "LABEL_OPTIONAL.\n");
5559 }
5560 
TEST_F(ValidationErrorTest,InputTypeNotDefined)5561 TEST_F(ValidationErrorTest, InputTypeNotDefined) {
5562   BuildFileWithErrors(
5563       "name: \"foo.proto\" "
5564       "message_type { name: \"Foo\" } "
5565       "service {"
5566       "  name: \"TestService\""
5567       "  method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
5568       "}",
5569 
5570       "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n");
5571 }
5572 
TEST_F(ValidationErrorTest,InputTypeNotAMessage)5573 TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
5574   BuildFileWithErrors(
5575       "name: \"foo.proto\" "
5576       "message_type { name: \"Foo\" } "
5577       "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5578       "service {"
5579       "  name: \"TestService\""
5580       "  method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
5581       "}",
5582 
5583       "foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n");
5584 }
5585 
TEST_F(ValidationErrorTest,OutputTypeNotDefined)5586 TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
5587   BuildFileWithErrors(
5588       "name: \"foo.proto\" "
5589       "message_type { name: \"Foo\" } "
5590       "service {"
5591       "  name: \"TestService\""
5592       "  method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
5593       "}",
5594 
5595       "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n");
5596 }
5597 
TEST_F(ValidationErrorTest,OutputTypeNotAMessage)5598 TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
5599   BuildFileWithErrors(
5600       "name: \"foo.proto\" "
5601       "message_type { name: \"Foo\" } "
5602       "enum_type { name: \"Bar\" value { name:\"DUMMY\" number:0 } } "
5603       "service {"
5604       "  name: \"TestService\""
5605       "  method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
5606       "}",
5607 
5608       "foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message "
5609       "type.\n");
5610 }
5611 
5612 
TEST_F(ValidationErrorTest,IllegalPackedField)5613 TEST_F(ValidationErrorTest, IllegalPackedField) {
5614   BuildFileWithErrors(
5615       "name: \"foo.proto\" "
5616       "message_type {\n"
5617       "  name: \"Foo\""
5618       "  field { name:\"packed_string\" number:1 label:LABEL_REPEATED "
5619       "          type:TYPE_STRING "
5620       "          options { uninterpreted_option {"
5621       "            name { name_part: \"packed\" is_extension: false }"
5622       "            identifier_value: \"true\" }}}\n"
5623       "  field { name:\"packed_message\" number:3 label:LABEL_REPEATED "
5624       "          type_name: \"Foo\""
5625       "          options { uninterpreted_option {"
5626       "            name { name_part: \"packed\" is_extension: false }"
5627       "            identifier_value: \"true\" }}}\n"
5628       "  field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL "
5629       "          type:TYPE_INT32 "
5630       "          options { uninterpreted_option {"
5631       "            name { name_part: \"packed\" is_extension: false }"
5632       "            identifier_value: \"true\" }}}\n"
5633       "}",
5634 
5635       "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be "
5636       "specified for repeated primitive fields.\n"
5637       "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be "
5638       "specified for repeated primitive fields.\n"
5639       "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be "
5640       "specified for repeated primitive fields.\n");
5641 }
5642 
TEST_F(ValidationErrorTest,OptionWrongType)5643 TEST_F(ValidationErrorTest, OptionWrongType) {
5644   BuildFileWithErrors(
5645       "name: \"foo.proto\" "
5646       "message_type { "
5647       "  name: \"TestMessage\" "
5648       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
5649       "          options { uninterpreted_option { name { name_part: \"ctype\" "
5650       "                                                  is_extension: false }"
5651       "                                           positive_int_value: 1 }"
5652       "          }"
5653       "  }"
5654       "}\n",
5655 
5656       "foo.proto: TestMessage.foo: OPTION_VALUE: Value must be identifier for "
5657       "enum-valued option \"google.protobuf.FieldOptions.ctype\".\n");
5658 }
5659 
TEST_F(ValidationErrorTest,OptionExtendsAtomicType)5660 TEST_F(ValidationErrorTest, OptionExtendsAtomicType) {
5661   BuildFileWithErrors(
5662       "name: \"foo.proto\" "
5663       "message_type { "
5664       "  name: \"TestMessage\" "
5665       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_STRING "
5666       "          options { uninterpreted_option { name { name_part: \"ctype\" "
5667       "                                                  is_extension: false }"
5668       "                                           name { name_part: \"foo\" "
5669       "                                                  is_extension: true }"
5670       "                                           positive_int_value: 1 }"
5671       "          }"
5672       "  }"
5673       "}\n",
5674 
5675       "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" is an "
5676       "atomic type, not a message.\n");
5677 }
5678 
TEST_F(ValidationErrorTest,DupOption)5679 TEST_F(ValidationErrorTest, DupOption) {
5680   BuildFileWithErrors(
5681       "name: \"foo.proto\" "
5682       "message_type { "
5683       "  name: \"TestMessage\" "
5684       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_UINT32 "
5685       "          options { uninterpreted_option { name { name_part: \"ctype\" "
5686       "                                                  is_extension: false }"
5687       "                                           identifier_value: \"CORD\" }"
5688       "                    uninterpreted_option { name { name_part: \"ctype\" "
5689       "                                                  is_extension: false }"
5690       "                                           identifier_value: \"CORD\" }"
5691       "          }"
5692       "  }"
5693       "}\n",
5694 
5695       "foo.proto: TestMessage.foo: OPTION_NAME: Option \"ctype\" was "
5696       "already set.\n");
5697 }
5698 
TEST_F(ValidationErrorTest,InvalidOptionName)5699 TEST_F(ValidationErrorTest, InvalidOptionName) {
5700   BuildFileWithErrors(
5701       "name: \"foo.proto\" "
5702       "message_type { "
5703       "  name: \"TestMessage\" "
5704       "  field { name:\"foo\" number:1 label:LABEL_OPTIONAL type:TYPE_BOOL "
5705       "          options { uninterpreted_option { "
5706       "                      name { name_part: \"uninterpreted_option\" "
5707       "                             is_extension: false }"
5708       "                      positive_int_value: 1 "
5709       "                    }"
5710       "          }"
5711       "  }"
5712       "}\n",
5713 
5714       "foo.proto: TestMessage.foo: OPTION_NAME: Option must not use "
5715       "reserved name \"uninterpreted_option\".\n");
5716 }
5717 
TEST_F(ValidationErrorTest,RepeatedMessageOption)5718 TEST_F(ValidationErrorTest, RepeatedMessageOption) {
5719   BuildDescriptorMessagesInTestPool();
5720 
5721   BuildFileWithErrors(
5722       "name: \"foo.proto\" "
5723       "dependency: \"google/protobuf/descriptor.proto\" "
5724       "message_type: { name: \"Bar\" field: { "
5725       "  name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
5726       "} "
5727       "extension { name: \"bar\" number: 7672757 label: LABEL_REPEATED "
5728       "            type: TYPE_MESSAGE type_name: \"Bar\" "
5729       "            extendee: \"google.protobuf.FileOptions\" }"
5730       "options { uninterpreted_option { name { name_part: \"bar\" "
5731       "                                        is_extension: true } "
5732       "                                 name { name_part: \"foo\" "
5733       "                                        is_extension: false } "
5734       "                                 positive_int_value: 1 } }",
5735 
5736       "foo.proto: foo.proto: OPTION_NAME: Option field \"(bar)\" is a "
5737       "repeated message. Repeated message options must be initialized "
5738       "using an aggregate value.\n");
5739 }
5740 
TEST_F(ValidationErrorTest,ResolveUndefinedOption)5741 TEST_F(ValidationErrorTest, ResolveUndefinedOption) {
5742   // The following should produce an error that baz.bar is resolved but not
5743   // defined.
5744   // foo.proto:
5745   //   package baz
5746   //   import google/protobuf/descriptor.proto
5747   //   message Bar { optional int32 foo = 1; }
5748   //   extend FileOptions { optional Bar bar = 7672757; }
5749   //
5750   // moo.proto:
5751   //   package moo.baz
5752   //   option (baz.bar).foo = 1;
5753   //
5754   // Although "baz.bar" is already defined, the lookup code will try
5755   // "moo.baz.bar", since it's the match from the innermost scope, which will
5756   // cause a symbol not defined error.
5757   BuildDescriptorMessagesInTestPool();
5758 
5759   BuildFile(
5760       "name: \"foo.proto\" "
5761       "package: \"baz\" "
5762       "dependency: \"google/protobuf/descriptor.proto\" "
5763       "message_type: { name: \"Bar\" field: { "
5764       "  name: \"foo\" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 } "
5765       "} "
5766       "extension { name: \"bar\" number: 7672757 label: LABEL_OPTIONAL "
5767       "            type: TYPE_MESSAGE type_name: \"Bar\" "
5768       "            extendee: \"google.protobuf.FileOptions\" }");
5769 
5770   BuildFileWithErrors(
5771       "name: \"moo.proto\" "
5772       "package: \"moo.baz\" "
5773       "options { uninterpreted_option { name { name_part: \"baz.bar\" "
5774       "                                        is_extension: true } "
5775       "                                 name { name_part: \"foo\" "
5776       "                                        is_extension: false } "
5777       "                                 positive_int_value: 1 } }",
5778 
5779       "moo.proto: moo.proto: OPTION_NAME: Option \"(baz.bar)\" is resolved to "
5780       "\"(moo.baz.bar)\","
5781       " which is not defined. The innermost scope is searched first in name "
5782       "resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\") to start "
5783       "from the outermost scope.\n");
5784 }
5785 
TEST_F(ValidationErrorTest,UnknownOption)5786 TEST_F(ValidationErrorTest, UnknownOption) {
5787   BuildFileWithErrors(
5788       "name: \"moo.proto\" "
5789       "package: \"moo.baz\" "
5790       "options { uninterpreted_option { name { name_part: \"baaz.bar\" "
5791       "                                        is_extension: true } "
5792       "                                 name { name_part: \"foo\" "
5793       "                                        is_extension: false } "
5794       "                                 positive_int_value: 1 } }",
5795 
5796       "moo.proto: moo.proto: OPTION_NAME: Option \"(baaz.bar)\" unknown. "
5797       "Ensure "
5798       "that your proto definition file imports the proto which defines the "
5799       "option.\n");
5800 }
5801 
TEST_F(ValidationErrorTest,CustomOptionConflictingFieldNumber)5802 TEST_F(ValidationErrorTest, CustomOptionConflictingFieldNumber) {
5803   BuildDescriptorMessagesInTestPool();
5804 
5805   BuildFileWithErrors(
5806       "name: \"foo.proto\" "
5807       "dependency: \"google/protobuf/descriptor.proto\" "
5808       "extension { name: \"foo1\" number: 7672757 label: LABEL_OPTIONAL "
5809       "            type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }"
5810       "extension { name: \"foo2\" number: 7672757 label: LABEL_OPTIONAL "
5811       "            type: TYPE_INT32 extendee: \"google.protobuf.FieldOptions\" }",
5812 
5813       "foo.proto: foo2: NUMBER: Extension number 7672757 has already been used "
5814       "in \"google.protobuf.FieldOptions\" by extension \"foo1\".\n");
5815 }
5816 
TEST_F(ValidationErrorTest,Int32OptionValueOutOfPositiveRange)5817 TEST_F(ValidationErrorTest, Int32OptionValueOutOfPositiveRange) {
5818   BuildDescriptorMessagesInTestPool();
5819 
5820   BuildFileWithErrors(
5821       "name: \"foo.proto\" "
5822       "dependency: \"google/protobuf/descriptor.proto\" "
5823       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5824       "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
5825       "options { uninterpreted_option { name { name_part: \"foo\" "
5826       "                                        is_extension: true } "
5827       "                                 positive_int_value: 0x80000000 } "
5828       "}",
5829 
5830       "foo.proto: foo.proto: OPTION_VALUE: Value out of range, -2147483648 to "
5831       "2147483647, for int32 option \"foo\".\n");
5832 }
5833 
TEST_F(ValidationErrorTest,Int32OptionValueOutOfNegativeRange)5834 TEST_F(ValidationErrorTest, Int32OptionValueOutOfNegativeRange) {
5835   BuildDescriptorMessagesInTestPool();
5836 
5837   BuildFileWithErrors(
5838       "name: \"foo.proto\" "
5839       "dependency: \"google/protobuf/descriptor.proto\" "
5840       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5841       "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
5842       "options { uninterpreted_option { name { name_part: \"foo\" "
5843       "                                        is_extension: true } "
5844       "                                 negative_int_value: -0x80000001 } "
5845       "}",
5846 
5847       "foo.proto: foo.proto: OPTION_VALUE: Value out of range, -2147483648 to "
5848       "2147483647, for int32 option \"foo\".\n");
5849 }
5850 
TEST_F(ValidationErrorTest,Int32OptionValueIsNotPositiveInt)5851 TEST_F(ValidationErrorTest, Int32OptionValueIsNotPositiveInt) {
5852   BuildDescriptorMessagesInTestPool();
5853 
5854   BuildFileWithErrors(
5855       "name: \"foo.proto\" "
5856       "dependency: \"google/protobuf/descriptor.proto\" "
5857       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5858       "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }"
5859       "options { uninterpreted_option { name { name_part: \"foo\" "
5860       "                                        is_extension: true } "
5861       "                                 string_value: \"5\" } }",
5862 
5863       "foo.proto: foo.proto: OPTION_VALUE: Value must be integer, from "
5864       "-2147483648 to 2147483647, for int32 option \"foo\".\n");
5865 }
5866 
TEST_F(ValidationErrorTest,Int64OptionValueOutOfRange)5867 TEST_F(ValidationErrorTest, Int64OptionValueOutOfRange) {
5868   BuildDescriptorMessagesInTestPool();
5869 
5870   BuildFileWithErrors(
5871       "name: \"foo.proto\" "
5872       "dependency: \"google/protobuf/descriptor.proto\" "
5873       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5874       "            type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
5875       "options { uninterpreted_option { name { name_part: \"foo\" "
5876       "                                        is_extension: true } "
5877       "                                 positive_int_value: 0x8000000000000000 "
5878       "} "
5879       "}",
5880 
5881       "foo.proto: foo.proto: OPTION_VALUE: Value out of range, "
5882       "-9223372036854775808 to 9223372036854775807, for int64 option "
5883       "\"foo\".\n");
5884 }
5885 
TEST_F(ValidationErrorTest,Int64OptionValueIsNotPositiveInt)5886 TEST_F(ValidationErrorTest, Int64OptionValueIsNotPositiveInt) {
5887   BuildDescriptorMessagesInTestPool();
5888 
5889   BuildFileWithErrors(
5890       "name: \"foo.proto\" "
5891       "dependency: \"google/protobuf/descriptor.proto\" "
5892       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5893       "            type: TYPE_INT64 extendee: \"google.protobuf.FileOptions\" }"
5894       "options { uninterpreted_option { name { name_part: \"foo\" "
5895       "                                        is_extension: true } "
5896       "                                 identifier_value: \"5\" } }",
5897 
5898       "foo.proto: foo.proto: OPTION_VALUE: Value must be integer, from "
5899       "-9223372036854775808 to 9223372036854775807, for int64 option "
5900       "\"foo\".\n");
5901 }
5902 
TEST_F(ValidationErrorTest,UInt32OptionValueOutOfRange)5903 TEST_F(ValidationErrorTest, UInt32OptionValueOutOfRange) {
5904   BuildDescriptorMessagesInTestPool();
5905 
5906   BuildFileWithErrors(
5907       "name: \"foo.proto\" "
5908       "dependency: \"google/protobuf/descriptor.proto\" "
5909       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5910       "            type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
5911       "options { uninterpreted_option { name { name_part: \"foo\" "
5912       "                                        is_extension: true } "
5913       "                                 positive_int_value: 0x100000000 } }",
5914 
5915       "foo.proto: foo.proto: OPTION_VALUE: Value out of range, 0 to "
5916       "4294967295, for uint32 option \"foo\".\n");
5917 }
5918 
TEST_F(ValidationErrorTest,UInt32OptionValueIsNotPositiveInt)5919 TEST_F(ValidationErrorTest, UInt32OptionValueIsNotPositiveInt) {
5920   BuildDescriptorMessagesInTestPool();
5921 
5922   BuildFileWithErrors(
5923       "name: \"foo.proto\" "
5924       "dependency: \"google/protobuf/descriptor.proto\" "
5925       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5926       "            type: TYPE_UINT32 extendee: \"google.protobuf.FileOptions\" }"
5927       "options { uninterpreted_option { name { name_part: \"foo\" "
5928       "                                        is_extension: true } "
5929       "                                 double_value: -5.6 } }",
5930 
5931       "foo.proto: foo.proto: OPTION_VALUE: Value must be integer, from 0 to "
5932       "4294967295, for uint32 option \"foo\".\n");
5933 }
5934 
TEST_F(ValidationErrorTest,UInt64OptionValueIsNotPositiveInt)5935 TEST_F(ValidationErrorTest, UInt64OptionValueIsNotPositiveInt) {
5936   BuildDescriptorMessagesInTestPool();
5937 
5938   BuildFileWithErrors(
5939       "name: \"foo.proto\" "
5940       "dependency: \"google/protobuf/descriptor.proto\" "
5941       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5942       "            type: TYPE_UINT64 extendee: \"google.protobuf.FileOptions\" }"
5943       "options { uninterpreted_option { name { name_part: \"foo\" "
5944       "                                        is_extension: true } "
5945       "                                 negative_int_value: -5 } }",
5946 
5947       "foo.proto: foo.proto: OPTION_VALUE: Value must be integer, from 0 to "
5948       "18446744073709551615, for uint64 option \"foo\".\n");
5949 }
5950 
TEST_F(ValidationErrorTest,FloatOptionValueIsNotNumber)5951 TEST_F(ValidationErrorTest, FloatOptionValueIsNotNumber) {
5952   BuildDescriptorMessagesInTestPool();
5953 
5954   BuildFileWithErrors(
5955       "name: \"foo.proto\" "
5956       "dependency: \"google/protobuf/descriptor.proto\" "
5957       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5958       "            type: TYPE_FLOAT extendee: \"google.protobuf.FileOptions\" }"
5959       "options { uninterpreted_option { name { name_part: \"foo\" "
5960       "                                        is_extension: true } "
5961       "                                 string_value: \"bar\" } }",
5962 
5963       "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
5964       "for float option \"foo\".\n");
5965 }
5966 
TEST_F(ValidationErrorTest,DoubleOptionValueIsNotNumber)5967 TEST_F(ValidationErrorTest, DoubleOptionValueIsNotNumber) {
5968   BuildDescriptorMessagesInTestPool();
5969 
5970   BuildFileWithErrors(
5971       "name: \"foo.proto\" "
5972       "dependency: \"google/protobuf/descriptor.proto\" "
5973       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5974       "            type: TYPE_DOUBLE extendee: \"google.protobuf.FileOptions\" }"
5975       "options { uninterpreted_option { name { name_part: \"foo\" "
5976       "                                        is_extension: true } "
5977       "                                 string_value: \"bar\" } }",
5978 
5979       "foo.proto: foo.proto: OPTION_VALUE: Value must be number "
5980       "for double option \"foo\".\n");
5981 }
5982 
TEST_F(ValidationErrorTest,BoolOptionValueIsNotTrueOrFalse)5983 TEST_F(ValidationErrorTest, BoolOptionValueIsNotTrueOrFalse) {
5984   BuildDescriptorMessagesInTestPool();
5985 
5986   BuildFileWithErrors(
5987       "name: \"foo.proto\" "
5988       "dependency: \"google/protobuf/descriptor.proto\" "
5989       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
5990       "            type: TYPE_BOOL extendee: \"google.protobuf.FileOptions\" }"
5991       "options { uninterpreted_option { name { name_part: \"foo\" "
5992       "                                        is_extension: true } "
5993       "                                 identifier_value: \"bar\" } }",
5994 
5995       "foo.proto: foo.proto: OPTION_VALUE: Value must be \"true\" or \"false\" "
5996       "for boolean option \"foo\".\n");
5997 }
5998 
TEST_F(ValidationErrorTest,EnumOptionValueIsNotIdentifier)5999 TEST_F(ValidationErrorTest, EnumOptionValueIsNotIdentifier) {
6000   BuildDescriptorMessagesInTestPool();
6001 
6002   BuildFileWithErrors(
6003       "name: \"foo.proto\" "
6004       "dependency: \"google/protobuf/descriptor.proto\" "
6005       "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
6006       "                              value { name: \"BAZ\" number: 2 } }"
6007       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
6008       "            type: TYPE_ENUM type_name: \"FooEnum\" "
6009       "            extendee: \"google.protobuf.FileOptions\" }"
6010       "options { uninterpreted_option { name { name_part: \"foo\" "
6011       "                                        is_extension: true } "
6012       "                                 string_value: \"MOOO\" } }",
6013 
6014       "foo.proto: foo.proto: OPTION_VALUE: Value must be identifier for "
6015       "enum-valued option \"foo\".\n");
6016 }
6017 
TEST_F(ValidationErrorTest,EnumOptionValueIsNotEnumValueName)6018 TEST_F(ValidationErrorTest, EnumOptionValueIsNotEnumValueName) {
6019   BuildDescriptorMessagesInTestPool();
6020 
6021   BuildFileWithErrors(
6022       "name: \"foo.proto\" "
6023       "dependency: \"google/protobuf/descriptor.proto\" "
6024       "enum_type { name: \"FooEnum\" value { name: \"BAR\" number: 1 } "
6025       "                              value { name: \"BAZ\" number: 2 } }"
6026       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
6027       "            type: TYPE_ENUM type_name: \"FooEnum\" "
6028       "            extendee: \"google.protobuf.FileOptions\" }"
6029       "options { uninterpreted_option { name { name_part: \"foo\" "
6030       "                                        is_extension: true } "
6031       "                                 identifier_value: \"MOOO\" } }",
6032 
6033       "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum\" has no value "
6034       "named \"MOOO\" for option \"foo\".\n");
6035 }
6036 
TEST_F(ValidationErrorTest,EnumOptionValueIsSiblingEnumValueName)6037 TEST_F(ValidationErrorTest, EnumOptionValueIsSiblingEnumValueName) {
6038   BuildDescriptorMessagesInTestPool();
6039 
6040   BuildFileWithErrors(
6041       "name: \"foo.proto\" "
6042       "dependency: \"google/protobuf/descriptor.proto\" "
6043       "enum_type { name: \"FooEnum1\" value { name: \"BAR\" number: 1 } "
6044       "                               value { name: \"BAZ\" number: 2 } }"
6045       "enum_type { name: \"FooEnum2\" value { name: \"MOO\" number: 1 } "
6046       "                               value { name: \"MOOO\" number: 2 } }"
6047       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
6048       "            type: TYPE_ENUM type_name: \"FooEnum1\" "
6049       "            extendee: \"google.protobuf.FileOptions\" }"
6050       "options { uninterpreted_option { name { name_part: \"foo\" "
6051       "                                        is_extension: true } "
6052       "                                 identifier_value: \"MOOO\" } }",
6053 
6054       "foo.proto: foo.proto: OPTION_VALUE: Enum type \"FooEnum1\" has no value "
6055       "named \"MOOO\" for option \"foo\". This appears to be a value from a "
6056       "sibling type.\n");
6057 }
6058 
TEST_F(ValidationErrorTest,StringOptionValueIsNotString)6059 TEST_F(ValidationErrorTest, StringOptionValueIsNotString) {
6060   BuildDescriptorMessagesInTestPool();
6061 
6062   BuildFileWithErrors(
6063       "name: \"foo.proto\" "
6064       "dependency: \"google/protobuf/descriptor.proto\" "
6065       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
6066       "            type: TYPE_STRING extendee: \"google.protobuf.FileOptions\" }"
6067       "options { uninterpreted_option { name { name_part: \"foo\" "
6068       "                                        is_extension: true } "
6069       "                                 identifier_value: \"MOOO\" } }",
6070 
6071       "foo.proto: foo.proto: OPTION_VALUE: Value must be quoted string "
6072       "for string option \"foo\".\n");
6073 }
6074 
TEST_F(ValidationErrorTest,JsonNameOptionOnExtensions)6075 TEST_F(ValidationErrorTest, JsonNameOptionOnExtensions) {
6076   BuildFileWithErrors(
6077       "name: \"foo.proto\" "
6078       "package: \"foo\" "
6079       "message_type {"
6080       "  name: \"Foo\""
6081       "  extension_range { start: 10 end: 20 }"
6082       "}"
6083       "extension {"
6084       "  name: \"value\""
6085       "  number: 10"
6086       "  label: LABEL_OPTIONAL"
6087       "  type: TYPE_INT32"
6088       "  extendee: \"foo.Foo\""
6089       "  json_name: \"myName\""
6090       "}",
6091       "foo.proto: foo.value: OPTION_NAME: option json_name is not allowed on "
6092       "extension fields.\n");
6093 }
6094 
TEST_F(ValidationErrorTest,JsonNameEmbeddedNull)6095 TEST_F(ValidationErrorTest, JsonNameEmbeddedNull) {
6096   BuildFileWithErrors(
6097       "name: \"foo.proto\" "
6098       "package: \"foo\" "
6099       "message_type {"
6100       "  name: \"Foo\""
6101       "  field {"
6102       "    name: \"value\""
6103       "    number: 10"
6104       "    label: LABEL_OPTIONAL"
6105       "    type: TYPE_INT32"
6106       "    json_name: \"embedded\\000null\""
6107       "  }"
6108       "}",
6109       "foo.proto: foo.Foo.value: OPTION_NAME: json_name cannot have embedded "
6110       "null characters.\n");
6111 }
6112 
TEST_F(ValidationErrorTest,DuplicateExtensionFieldNumber)6113 TEST_F(ValidationErrorTest, DuplicateExtensionFieldNumber) {
6114   BuildDescriptorMessagesInTestPool();
6115 
6116   BuildFile(
6117       "name: \"foo.proto\" "
6118       "dependency: \"google/protobuf/descriptor.proto\" "
6119       "extension { name: \"option1\" number: 1000 label: LABEL_OPTIONAL "
6120       "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }");
6121 
6122   BuildFileWithWarnings(
6123       "name: \"bar.proto\" "
6124       "dependency: \"google/protobuf/descriptor.proto\" "
6125       "extension { name: \"option2\" number: 1000 label: LABEL_OPTIONAL "
6126       "            type: TYPE_INT32 extendee: \"google.protobuf.FileOptions\" }",
6127       "bar.proto: option2: NUMBER: Extension number 1000 has already been used "
6128       "in \"google.protobuf.FileOptions\" by extension \"option1\" defined in "
6129       "foo.proto.\n");
6130 }
6131 
6132 // Helper function for tests that check for aggregate value parsing
6133 // errors.  The "value" argument is embedded inside the
6134 // "uninterpreted_option" portion of the result.
EmbedAggregateValue(const char * value)6135 static std::string EmbedAggregateValue(const char* value) {
6136   return absl::Substitute(
6137       "name: \"foo.proto\" "
6138       "dependency: \"google/protobuf/descriptor.proto\" "
6139       "message_type { name: \"Foo\" } "
6140       "extension { name: \"foo\" number: 7672757 label: LABEL_OPTIONAL "
6141       "            type: TYPE_MESSAGE type_name: \"Foo\" "
6142       "            extendee: \"google.protobuf.FileOptions\" }"
6143       "options { uninterpreted_option { name { name_part: \"foo\" "
6144       "                                        is_extension: true } "
6145       "                                 $0 } }",
6146       value);
6147 }
6148 
TEST_F(ValidationErrorTest,AggregateValueNotFound)6149 TEST_F(ValidationErrorTest, AggregateValueNotFound) {
6150   BuildDescriptorMessagesInTestPool();
6151 
6152   BuildFileWithErrors(
6153       EmbedAggregateValue("string_value: \"\""),
6154       "foo.proto: foo.proto: OPTION_VALUE: Option \"foo\" is a message. "
6155       "To set the entire message, use syntax like "
6156       "\"foo = { <proto text format> }\". To set fields within it, use "
6157       "syntax like \"foo.foo = value\".\n");
6158 }
6159 
TEST_F(ValidationErrorTest,AggregateValueParseError)6160 TEST_F(ValidationErrorTest, AggregateValueParseError) {
6161   BuildDescriptorMessagesInTestPool();
6162 
6163   BuildFileWithErrors(
6164       EmbedAggregateValue("aggregate_value: \"1+2\""),
6165       "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
6166       "value for \"foo\": Expected identifier, got: 1\n");
6167 }
6168 
TEST_F(ValidationErrorTest,AggregateValueUnknownFields)6169 TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
6170   BuildDescriptorMessagesInTestPool();
6171 
6172   BuildFileWithErrors(
6173       EmbedAggregateValue("aggregate_value: \"x:100\""),
6174       "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
6175       "value for \"foo\": Message type \"Foo\" has no field named \"x\".\n");
6176 }
6177 
TEST_F(ValidationErrorTest,NotLiteImportsLite)6178 TEST_F(ValidationErrorTest, NotLiteImportsLite) {
6179   BuildFile(
6180       "name: \"bar.proto\" "
6181       "options { optimize_for: LITE_RUNTIME } ");
6182 
6183   BuildFileWithErrors(
6184       "name: \"foo.proto\" "
6185       "dependency: \"bar.proto\" ",
6186 
6187       "foo.proto: bar.proto: IMPORT: Files that do not use optimize_for = "
6188       "LITE_RUNTIME cannot import files which do use this option.  This file "
6189       "is not lite, but it imports \"bar.proto\" which is.\n");
6190 }
6191 
TEST_F(ValidationErrorTest,LiteExtendsNotLite)6192 TEST_F(ValidationErrorTest, LiteExtendsNotLite) {
6193   BuildFile(
6194       "name: \"bar.proto\" "
6195       "message_type: {"
6196       "  name: \"Bar\""
6197       "  extension_range { start: 1 end: 1000 }"
6198       "}");
6199 
6200   BuildFileWithErrors(
6201       "name: \"foo.proto\" "
6202       "dependency: \"bar.proto\" "
6203       "options { optimize_for: LITE_RUNTIME } "
6204       "extension { name: \"ext\" number: 123 label: LABEL_OPTIONAL "
6205       "            type: TYPE_INT32 extendee: \"Bar\" }",
6206 
6207       "foo.proto: ext: EXTENDEE: Extensions to non-lite types can only be "
6208       "declared in non-lite files.  Note that you cannot extend a non-lite "
6209       "type to contain a lite type, but the reverse is allowed.\n");
6210 }
6211 
TEST_F(ValidationErrorTest,NoLiteServices)6212 TEST_F(ValidationErrorTest, NoLiteServices) {
6213   BuildFileWithErrors(
6214       "name: \"foo.proto\" "
6215       "options {"
6216       "  optimize_for: LITE_RUNTIME"
6217       "  cc_generic_services: true"
6218       "  java_generic_services: true"
6219       "} "
6220       "service { name: \"Foo\" }",
6221 
6222       "foo.proto: Foo: NAME: Files with optimize_for = LITE_RUNTIME cannot "
6223       "define services unless you set both options cc_generic_services and "
6224       "java_generic_services to false.\n");
6225 
6226   BuildFile(
6227       "name: \"bar.proto\" "
6228       "options {"
6229       "  optimize_for: LITE_RUNTIME"
6230       "  cc_generic_services: false"
6231       "  java_generic_services: false"
6232       "} "
6233       "service { name: \"Bar\" }");
6234 }
6235 
TEST_F(ValidationErrorTest,RollbackAfterError)6236 TEST_F(ValidationErrorTest, RollbackAfterError) {
6237   // Build a file which contains every kind of construct but references an
6238   // undefined type.  All these constructs will be added to the symbol table
6239   // before the undefined type error is noticed.  The DescriptorPool will then
6240   // have to roll everything back.
6241   BuildFileWithErrors(
6242       "name: \"foo.proto\" "
6243       "message_type {"
6244       "  name: \"TestMessage\""
6245       "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
6246       "} "
6247       "enum_type {"
6248       "  name: \"TestEnum\""
6249       "  value { name:\"BAR\" number:1 }"
6250       "} "
6251       "service {"
6252       "  name: \"TestService\""
6253       "  method {"
6254       "    name: \"Baz\""
6255       "    input_type: \"NoSuchType\""  // error
6256       "    output_type: \"TestMessage\""
6257       "  }"
6258       "}",
6259 
6260       "foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not "
6261       "defined.\n");
6262 
6263   // Make sure that if we build the same file again with the error fixed,
6264   // it works.  If the above rollback was incomplete, then some symbols will
6265   // be left defined, and this second attempt will fail since it tries to
6266   // re-define the same symbols.
6267   BuildFile(
6268       "name: \"foo.proto\" "
6269       "message_type {"
6270       "  name: \"TestMessage\""
6271       "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
6272       "} "
6273       "enum_type {"
6274       "  name: \"TestEnum\""
6275       "  value { name:\"BAR\" number:1 }"
6276       "} "
6277       "service {"
6278       "  name: \"TestService\""
6279       "  method { name:\"Baz\""
6280       "           input_type:\"TestMessage\""
6281       "           output_type:\"TestMessage\" }"
6282       "}");
6283 }
6284 
TEST_F(ValidationErrorTest,ErrorsReportedToLogError)6285 TEST_F(ValidationErrorTest, ErrorsReportedToLogError) {
6286   // Test that errors are reported to ABSL_LOG(ERROR) if no error collector is
6287   // provided.
6288 
6289   FileDescriptorProto file_proto;
6290   ASSERT_TRUE(
6291       TextFormat::ParseFromString("name: \"foo.proto\" "
6292                                   "message_type { name: \"Foo\" } "
6293                                   "message_type { name: \"Foo\" } ",
6294                                   &file_proto));
6295   {
6296     absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected);
6297     EXPECT_CALL(log, Log(absl::LogSeverity::kError, testing::_,
6298                          "Invalid proto descriptor for file \"foo.proto\":"));
6299     EXPECT_CALL(log, Log(absl::LogSeverity::kError, testing::_,
6300                          "  Foo: \"Foo\" is already defined."));
6301     log.StartCapturingLogs();
6302     EXPECT_TRUE(pool_.BuildFile(file_proto) == nullptr);
6303   }
6304 }
6305 
TEST_F(ValidationErrorTest,DisallowEnumAlias)6306 TEST_F(ValidationErrorTest, DisallowEnumAlias) {
6307   BuildFileWithErrors(
6308       "name: \"foo.proto\" "
6309       "enum_type {"
6310       "  name: \"Bar\""
6311       "  value { name:\"ENUM_A\" number:0 }"
6312       "  value { name:\"ENUM_B\" number:0 }"
6313       "}",
6314       "foo.proto: Bar: NUMBER: "
6315       "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
6316       "If this is intended, set 'option allow_alias = true;' to the enum "
6317       "definition. The next available enum value is 1.\n");
6318 
6319   BuildFileWithErrors(
6320       R"pb(
6321         name: "foo.proto"
6322         enum_type {
6323           name: "Bar"
6324           value { name: "ENUM_A" number: 10 }
6325           value { name: "ENUM_B" number: 10 }
6326           value { name: "ENUM_C" number: 11 }
6327           value { name: "ENUM_D" number: 20 }
6328         })pb",
6329       "foo.proto: Bar: NUMBER: "
6330       "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
6331       "If this is intended, set 'option allow_alias = true;' to the enum "
6332       "definition. The next available enum value is 12.\n");
6333 
6334   BuildFileWithErrors(
6335       absl::Substitute(R"pb(
6336                          name: "foo.proto"
6337                          enum_type {
6338                            name: "Bar"
6339                            value { name: "ENUM_A" number: $0 }
6340                            value { name: "ENUM_B" number: $0 }
6341                          })pb",
6342                        std::numeric_limits<int32_t>::max()),
6343       "foo.proto: Bar: NUMBER: "
6344       "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
6345       "If this is intended, set 'option allow_alias = true;' to the enum "
6346       "definition.\n");
6347 }
6348 
TEST_F(ValidationErrorTest,AllowEnumAlias)6349 TEST_F(ValidationErrorTest, AllowEnumAlias) {
6350   BuildFile(
6351       "name: \"foo.proto\" "
6352       "enum_type {"
6353       "  name: \"Bar\""
6354       "  value { name:\"ENUM_A\" number:0 }"
6355       "  value { name:\"ENUM_B\" number:0 }"
6356       "  options { allow_alias: true }"
6357       "}");
6358 }
6359 
TEST_F(ValidationErrorTest,UnusedImportWarning)6360 TEST_F(ValidationErrorTest, UnusedImportWarning) {
6361   pool_.AddDirectInputFile("bar.proto");
6362   BuildFile(
6363       "name: \"bar.proto\" "
6364       "message_type { name: \"Bar\" }");
6365 
6366   pool_.AddDirectInputFile("base.proto");
6367   BuildFile(
6368       "name: \"base.proto\" "
6369       "message_type { name: \"Base\" }");
6370 
6371   pool_.AddDirectInputFile("baz.proto");
6372   BuildFile(
6373       "name: \"baz.proto\" "
6374       "message_type { name: \"Baz\" }");
6375 
6376   pool_.AddDirectInputFile("public.proto");
6377   BuildFile(
6378       "name: \"public.proto\" "
6379       "dependency: \"bar.proto\""
6380       "public_dependency: 0");
6381 
6382   // // forward.proto
6383   // import "base.proto"       // No warning: Base message is used.
6384   // import "bar.proto"        // Will log a warning.
6385   // import public "baz.proto" // No warning: Do not track import public.
6386   // import "public.proto"     // No warning: public.proto has import public.
6387   // message Forward {
6388   //   optional Base base = 1;
6389   // }
6390   //
6391   pool_.AddDirectInputFile("forward.proto");
6392   BuildFileWithWarnings(
6393       "name: \"forward.proto\""
6394       "dependency: \"base.proto\""
6395       "dependency: \"bar.proto\""
6396       "dependency: \"baz.proto\""
6397       "dependency: \"public.proto\""
6398       "public_dependency: 2 "
6399       "message_type {"
6400       "  name: \"Forward\""
6401       "  field { name:\"base\" number:1 label:LABEL_OPTIONAL "
6402       "type_name:\"Base\" }"
6403       "}",
6404       "forward.proto: bar.proto: IMPORT: Import bar.proto is unused.\n");
6405 }
6406 
6407 // Verifies that the dependency checker isn't fooled by package symbols,
6408 // which can be defined in multiple files.
TEST_F(ValidationErrorTest,SamePackageUnusedImportError)6409 TEST_F(ValidationErrorTest, SamePackageUnusedImportError) {
6410   BuildFile(R"pb(
6411     name: "unused_dependency.proto"
6412     package: "protobuf_unittest.subpackage"
6413     message_type { name: "Foo" }
6414   )pb");
6415 
6416   BuildFile(R"pb(
6417     name: "used_dependency.proto"
6418     package: "protobuf_unittest.subpackage"
6419     message_type { name: "Bar" }
6420   )pb");
6421 
6422   pool_.AddDirectInputFile("import.proto", true);
6423   BuildFileWithErrors(R"pb(
6424                         name: "import.proto"
6425                         package: "protobuf_unittest"
6426                         dependency: "unused_dependency.proto"
6427                         dependency: "used_dependency.proto"
6428                         message_type {
6429                           name: "Baz"
6430                           field {
6431                             name: "bar"
6432                             number: 1
6433                             label: LABEL_OPTIONAL
6434                             type: TYPE_MESSAGE
6435                             type_name: "subpackage.Bar"
6436                           }
6437                         }
6438                       )pb",
6439                       "import.proto: unused_dependency.proto: "
6440                       "IMPORT: Import unused_dependency.proto is unused.\n");
6441 }
6442 
6443 namespace {
FillValidMapEntry(FileDescriptorProto * file_proto)6444 void FillValidMapEntry(FileDescriptorProto* file_proto) {
6445   ASSERT_TRUE(TextFormat::ParseFromString(
6446       "name: 'foo.proto' "
6447       "message_type { "
6448       "  name: 'Foo' "
6449       "  field { "
6450       "    name: 'foo_map' number: 1 label:LABEL_REPEATED "
6451       "    type_name: 'FooMapEntry' "
6452       "  } "
6453       "  nested_type { "
6454       "    name: 'FooMapEntry' "
6455       "    options {  map_entry: true } "
6456       "    field { "
6457       "      name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
6458       "    } "
6459       "    field { "
6460       "      name: 'value' number: 2 type:TYPE_INT32 label:LABEL_OPTIONAL "
6461       "    } "
6462       "  } "
6463       "} "
6464       "message_type { "
6465       "  name: 'Bar' "
6466       "  extension_range { start: 1 end: 10 }"
6467       "} ",
6468       file_proto));
6469 }
6470 static const char* kMapEntryErrorMessage =
6471     "foo.proto: Foo.foo_map: TYPE: map_entry should not be set explicitly. "
6472     "Use map<KeyType, ValueType> instead.\n";
6473 static const char* kMapEntryKeyTypeErrorMessage =
6474     "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot be float/double, "
6475     "bytes or message types.\n";
6476 
6477 }  // namespace
6478 
TEST_F(ValidationErrorTest,MapEntryBase)6479 TEST_F(ValidationErrorTest, MapEntryBase) {
6480   FileDescriptorProto file_proto;
6481   FillValidMapEntry(&file_proto);
6482   std::string text_proto;
6483   TextFormat::PrintToString(file_proto, &text_proto);
6484   BuildFile(text_proto);
6485 }
6486 
TEST_F(ValidationErrorTest,MapEntryExtensionRange)6487 TEST_F(ValidationErrorTest, MapEntryExtensionRange) {
6488   FileDescriptorProto file_proto;
6489   FillValidMapEntry(&file_proto);
6490   TextFormat::MergeFromString(
6491       "extension_range { "
6492       "  start: 10 end: 20 "
6493       "} ",
6494       file_proto.mutable_message_type(0)->mutable_nested_type(0));
6495   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6496 }
6497 
TEST_F(ValidationErrorTest,MapEntryExtension)6498 TEST_F(ValidationErrorTest, MapEntryExtension) {
6499   FileDescriptorProto file_proto;
6500   FillValidMapEntry(&file_proto);
6501   TextFormat::MergeFromString(
6502       "extension { "
6503       "  name: 'foo_ext' extendee: '.Bar' number: 5"
6504       "} ",
6505       file_proto.mutable_message_type(0)->mutable_nested_type(0));
6506   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6507 }
6508 
TEST_F(ValidationErrorTest,MapEntryNestedType)6509 TEST_F(ValidationErrorTest, MapEntryNestedType) {
6510   FileDescriptorProto file_proto;
6511   FillValidMapEntry(&file_proto);
6512   TextFormat::MergeFromString(
6513       "nested_type { "
6514       "  name: 'Bar' "
6515       "} ",
6516       file_proto.mutable_message_type(0)->mutable_nested_type(0));
6517   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6518 }
6519 
TEST_F(ValidationErrorTest,MapEntryEnumTypes)6520 TEST_F(ValidationErrorTest, MapEntryEnumTypes) {
6521   FileDescriptorProto file_proto;
6522   FillValidMapEntry(&file_proto);
6523   TextFormat::MergeFromString(
6524       "enum_type { "
6525       "  name: 'BarEnum' "
6526       "  value { name: 'BAR_BAR' number:0 } "
6527       "} ",
6528       file_proto.mutable_message_type(0)->mutable_nested_type(0));
6529   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6530 }
6531 
TEST_F(ValidationErrorTest,MapEntryExtraField)6532 TEST_F(ValidationErrorTest, MapEntryExtraField) {
6533   FileDescriptorProto file_proto;
6534   FillValidMapEntry(&file_proto);
6535   TextFormat::MergeFromString(
6536       "field { "
6537       "  name: 'other_field' "
6538       "  label: LABEL_OPTIONAL "
6539       "  type: TYPE_INT32 "
6540       "  number: 3 "
6541       "} ",
6542       file_proto.mutable_message_type(0)->mutable_nested_type(0));
6543   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6544 }
6545 
TEST_F(ValidationErrorTest,MapEntryMessageName)6546 TEST_F(ValidationErrorTest, MapEntryMessageName) {
6547   FileDescriptorProto file_proto;
6548   FillValidMapEntry(&file_proto);
6549   file_proto.mutable_message_type(0)->mutable_nested_type(0)->set_name(
6550       "OtherMapEntry");
6551   file_proto.mutable_message_type(0)->mutable_field(0)->set_type_name(
6552       "OtherMapEntry");
6553   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6554 }
6555 
TEST_F(ValidationErrorTest,MapEntryNoneRepeatedMapEntry)6556 TEST_F(ValidationErrorTest, MapEntryNoneRepeatedMapEntry) {
6557   FileDescriptorProto file_proto;
6558   FillValidMapEntry(&file_proto);
6559   file_proto.mutable_message_type(0)->mutable_field(0)->set_label(
6560       FieldDescriptorProto::LABEL_OPTIONAL);
6561   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6562 }
6563 
TEST_F(ValidationErrorTest,MapEntryDifferentContainingType)6564 TEST_F(ValidationErrorTest, MapEntryDifferentContainingType) {
6565   FileDescriptorProto file_proto;
6566   FillValidMapEntry(&file_proto);
6567   // Move the nested MapEntry message into the top level, which should not pass
6568   // the validation.
6569   file_proto.mutable_message_type()->AddAllocated(
6570       file_proto.mutable_message_type(0)->mutable_nested_type()->ReleaseLast());
6571   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6572 }
6573 
TEST_F(ValidationErrorTest,MapEntryKeyName)6574 TEST_F(ValidationErrorTest, MapEntryKeyName) {
6575   FileDescriptorProto file_proto;
6576   FillValidMapEntry(&file_proto);
6577   FieldDescriptorProto* key =
6578       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6579           0);
6580   key->set_name("Key");
6581   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6582 }
6583 
TEST_F(ValidationErrorTest,MapEntryKeyLabel)6584 TEST_F(ValidationErrorTest, MapEntryKeyLabel) {
6585   FileDescriptorProto file_proto;
6586   FillValidMapEntry(&file_proto);
6587   FieldDescriptorProto* key =
6588       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6589           0);
6590   key->set_label(FieldDescriptorProto::LABEL_REQUIRED);
6591   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6592 }
6593 
TEST_F(ValidationErrorTest,MapEntryKeyNumber)6594 TEST_F(ValidationErrorTest, MapEntryKeyNumber) {
6595   FileDescriptorProto file_proto;
6596   FillValidMapEntry(&file_proto);
6597   FieldDescriptorProto* key =
6598       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6599           0);
6600   key->set_number(3);
6601   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6602 }
6603 
TEST_F(ValidationErrorTest,MapEntryValueName)6604 TEST_F(ValidationErrorTest, MapEntryValueName) {
6605   FileDescriptorProto file_proto;
6606   FillValidMapEntry(&file_proto);
6607   FieldDescriptorProto* value =
6608       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6609           1);
6610   value->set_name("Value");
6611   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6612 }
6613 
TEST_F(ValidationErrorTest,MapEntryValueLabel)6614 TEST_F(ValidationErrorTest, MapEntryValueLabel) {
6615   FileDescriptorProto file_proto;
6616   FillValidMapEntry(&file_proto);
6617   FieldDescriptorProto* value =
6618       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6619           1);
6620   value->set_label(FieldDescriptorProto::LABEL_REQUIRED);
6621   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6622 }
6623 
TEST_F(ValidationErrorTest,MapEntryValueNumber)6624 TEST_F(ValidationErrorTest, MapEntryValueNumber) {
6625   FileDescriptorProto file_proto;
6626   FillValidMapEntry(&file_proto);
6627   FieldDescriptorProto* value =
6628       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6629           1);
6630   value->set_number(3);
6631   BuildFileWithErrors(file_proto, kMapEntryErrorMessage);
6632 }
6633 
TEST_F(ValidationErrorTest,MapEntryKeyTypeFloat)6634 TEST_F(ValidationErrorTest, MapEntryKeyTypeFloat) {
6635   FileDescriptorProto file_proto;
6636   FillValidMapEntry(&file_proto);
6637   FieldDescriptorProto* key =
6638       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6639           0);
6640   key->set_type(FieldDescriptorProto::TYPE_FLOAT);
6641   BuildFileWithErrors(file_proto, kMapEntryKeyTypeErrorMessage);
6642 }
6643 
TEST_F(ValidationErrorTest,MapEntryKeyTypeDouble)6644 TEST_F(ValidationErrorTest, MapEntryKeyTypeDouble) {
6645   FileDescriptorProto file_proto;
6646   FillValidMapEntry(&file_proto);
6647   FieldDescriptorProto* key =
6648       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6649           0);
6650   key->set_type(FieldDescriptorProto::TYPE_DOUBLE);
6651   BuildFileWithErrors(file_proto, kMapEntryKeyTypeErrorMessage);
6652 }
6653 
TEST_F(ValidationErrorTest,MapEntryKeyTypeBytes)6654 TEST_F(ValidationErrorTest, MapEntryKeyTypeBytes) {
6655   FileDescriptorProto file_proto;
6656   FillValidMapEntry(&file_proto);
6657   FieldDescriptorProto* key =
6658       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6659           0);
6660   key->set_type(FieldDescriptorProto::TYPE_BYTES);
6661   BuildFileWithErrors(file_proto, kMapEntryKeyTypeErrorMessage);
6662 }
6663 
TEST_F(ValidationErrorTest,MapEntryKeyTypeEnum)6664 TEST_F(ValidationErrorTest, MapEntryKeyTypeEnum) {
6665   FileDescriptorProto file_proto;
6666   FillValidMapEntry(&file_proto);
6667   FieldDescriptorProto* key =
6668       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6669           0);
6670   key->clear_type();
6671   key->set_type_name("BarEnum");
6672   EnumDescriptorProto* enum_proto = file_proto.add_enum_type();
6673   enum_proto->set_name("BarEnum");
6674   EnumValueDescriptorProto* enum_value_proto = enum_proto->add_value();
6675   enum_value_proto->set_name("BAR_VALUE0");
6676   enum_value_proto->set_number(0);
6677   BuildFileWithErrors(file_proto,
6678                       "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
6679                       "be enum types.\n");
6680   // Enum keys are not allowed in proto3 as well.
6681   // Get rid of extensions for proto3 to make it proto3 compatible.
6682   file_proto.mutable_message_type()->RemoveLast();
6683   file_proto.set_syntax("proto3");
6684   BuildFileWithErrors(file_proto,
6685                       "foo.proto: Foo.foo_map: TYPE: Key in map fields cannot "
6686                       "be enum types.\n");
6687 }
6688 
TEST_F(ValidationErrorTest,MapEntryKeyTypeMessage)6689 TEST_F(ValidationErrorTest, MapEntryKeyTypeMessage) {
6690   FileDescriptorProto file_proto;
6691   FillValidMapEntry(&file_proto);
6692   FieldDescriptorProto* key =
6693       file_proto.mutable_message_type(0)->mutable_nested_type(0)->mutable_field(
6694           0);
6695   key->clear_type();
6696   key->set_type_name(".Bar");
6697   BuildFileWithErrors(file_proto, kMapEntryKeyTypeErrorMessage);
6698 }
6699 
TEST_F(ValidationErrorTest,MapEntryConflictsWithField)6700 TEST_F(ValidationErrorTest, MapEntryConflictsWithField) {
6701   FileDescriptorProto file_proto;
6702   FillValidMapEntry(&file_proto);
6703   TextFormat::MergeFromString(
6704       "field { "
6705       "  name: 'FooMapEntry' "
6706       "  type: TYPE_INT32 "
6707       "  label: LABEL_OPTIONAL "
6708       "  number: 100 "
6709       "}",
6710       file_proto.mutable_message_type(0));
6711   BuildFileWithErrors(
6712       file_proto,
6713       "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6714       "\"Foo\".\n"
6715       "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
6716       "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6717       "with an existing field.\n");
6718 }
6719 
TEST_F(ValidationErrorTest,MapEntryConflictsWithMessage)6720 TEST_F(ValidationErrorTest, MapEntryConflictsWithMessage) {
6721   FileDescriptorProto file_proto;
6722   FillValidMapEntry(&file_proto);
6723   TextFormat::MergeFromString(
6724       "nested_type { "
6725       "  name: 'FooMapEntry' "
6726       "}",
6727       file_proto.mutable_message_type(0));
6728   BuildFileWithErrors(
6729       file_proto,
6730       "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6731       "\"Foo\".\n"
6732       "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6733       "with an existing nested message type.\n");
6734 }
6735 
TEST_F(ValidationErrorTest,MapEntryConflictsWithEnum)6736 TEST_F(ValidationErrorTest, MapEntryConflictsWithEnum) {
6737   FileDescriptorProto file_proto;
6738   FillValidMapEntry(&file_proto);
6739   TextFormat::MergeFromString(
6740       "enum_type { "
6741       "  name: 'FooMapEntry' "
6742       "  value { name: 'ENTRY_FOO' number: 0 }"
6743       "}",
6744       file_proto.mutable_message_type(0));
6745   BuildFileWithErrors(
6746       file_proto,
6747       "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6748       "\"Foo\".\n"
6749       "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6750       "with an existing enum type.\n");
6751 }
6752 
TEST_F(ValidationErrorTest,Proto3EnumValuesConflictWithDifferentCasing)6753 TEST_F(ValidationErrorTest, Proto3EnumValuesConflictWithDifferentCasing) {
6754   BuildFileWithErrors(
6755       "syntax: 'proto3'"
6756       "name: 'foo.proto' "
6757       "enum_type {"
6758       "  name: 'FooEnum' "
6759       "  value { name: 'BAR' number: 0 }"
6760       "  value { name: 'bar' number: 1 }"
6761       "}",
6762       "foo.proto: bar: NAME: Enum name bar has the same name as BAR "
6763       "if you ignore case and strip out the enum name prefix (if any). "
6764       "(If you are using allow_alias, please assign the same number "
6765       "to each enum value name.)\n");
6766 
6767   BuildFileWithErrors(
6768       "syntax: 'proto2'"
6769       "name: 'foo.proto' "
6770       "enum_type {"
6771       "  name: 'FooEnum' "
6772       "  value { name: 'BAR' number: 0 }"
6773       "  value { name: 'bar' number: 1 }"
6774       "}",
6775       "foo.proto: bar: NAME: Enum name bar has the same name as BAR "
6776       "if you ignore case and strip out the enum name prefix (if any). "
6777       "(If you are using allow_alias, please assign the same number "
6778       "to each enum value name.)\n");
6779 
6780   // Not an error because both enums are mapped to the same value.
6781   BuildFile(
6782       "syntax: 'proto3'"
6783       "name: 'foo.proto' "
6784       "enum_type {"
6785       "  name: 'FooEnum' "
6786       "  options { allow_alias: true }"
6787       "  value { name: 'UNKNOWN' number: 0 }"
6788       "  value { name: 'BAR' number: 1 }"
6789       "  value { name: 'bar' number: 1 }"
6790       "}");
6791 }
6792 
TEST_F(ValidationErrorTest,EnumValuesConflictWhenPrefixesStripped)6793 TEST_F(ValidationErrorTest, EnumValuesConflictWhenPrefixesStripped) {
6794   BuildFileWithErrors(
6795       "syntax: 'proto3'"
6796       "name: 'foo.proto' "
6797       "enum_type {"
6798       "  name: 'FooEnum' "
6799       "  value { name: 'FOO_ENUM_BAZ' number: 0 }"
6800       "  value { name: 'BAZ' number: 1 }"
6801       "}",
6802       "foo.proto: BAZ: NAME: Enum name BAZ has the same name as FOO_ENUM_BAZ "
6803       "if you ignore case and strip out the enum name prefix (if any). "
6804       "(If you are using allow_alias, please assign the same number "
6805       "to each enum value name.)\n");
6806 
6807   BuildFileWithErrors(
6808       "syntax: 'proto3'"
6809       "name: 'foo.proto' "
6810       "enum_type {"
6811       "  name: 'FooEnum' "
6812       "  value { name: 'FOOENUM_BAZ' number: 0 }"
6813       "  value { name: 'BAZ' number: 1 }"
6814       "}",
6815       "foo.proto: BAZ: NAME: Enum name BAZ has the same name as FOOENUM_BAZ "
6816       "if you ignore case and strip out the enum name prefix (if any). "
6817       "(If you are using allow_alias, please assign the same number "
6818       "to each enum value name.)\n");
6819 
6820   BuildFileWithErrors(
6821       "syntax: 'proto3'"
6822       "name: 'foo.proto' "
6823       "enum_type {"
6824       "  name: 'FooEnum' "
6825       "  value { name: 'FOO_ENUM_BAR_BAZ' number: 0 }"
6826       "  value { name: 'BAR__BAZ' number: 1 }"
6827       "}",
6828       "foo.proto: BAR__BAZ: NAME: Enum name BAR__BAZ has the same name as "
6829       "FOO_ENUM_BAR_BAZ if you ignore case and strip out the enum name prefix "
6830       "(if any). (If you are using allow_alias, please assign the same number "
6831       "to each enum value name.)\n");
6832 
6833   BuildFileWithErrors(
6834       "syntax: 'proto3'"
6835       "name: 'foo.proto' "
6836       "enum_type {"
6837       "  name: 'FooEnum' "
6838       "  value { name: 'FOO_ENUM__BAR_BAZ' number: 0 }"
6839       "  value { name: 'BAR_BAZ' number: 1 }"
6840       "}",
6841       "foo.proto: BAR_BAZ: NAME: Enum name BAR_BAZ has the same name as "
6842       "FOO_ENUM__BAR_BAZ if you ignore case and strip out the enum name prefix "
6843       "(if any). (If you are using allow_alias, please assign the same number "
6844       "to each enum value name.)\n");
6845 
6846   BuildFileWithErrors(
6847       "syntax: 'proto2'"
6848       "name: 'foo.proto' "
6849       "enum_type {"
6850       "  name: 'FooEnum' "
6851       "  value { name: 'FOO_ENUM__BAR_BAZ' number: 0 }"
6852       "  value { name: 'BAR_BAZ' number: 1 }"
6853       "}",
6854       "foo.proto: BAR_BAZ: NAME: Enum name BAR_BAZ has the same name as "
6855       "FOO_ENUM__BAR_BAZ if you ignore case and strip out the enum name prefix "
6856       "(if any). (If you are using allow_alias, please assign the same number "
6857       "to each enum value name.)\n");
6858 
6859   // This isn't an error because the underscore will cause the PascalCase to
6860   // differ by case (BarBaz vs. Barbaz).
6861   BuildFile(
6862       "syntax: 'proto3'"
6863       "name: 'foo.proto' "
6864       "enum_type {"
6865       "  name: 'FooEnum' "
6866       "  value { name: 'BAR_BAZ' number: 0 }"
6867       "  value { name: 'BARBAZ' number: 1 }"
6868       "}");
6869 }
6870 
TEST_F(ValidationErrorTest,EnumValuesConflictLegacyBehavior)6871 TEST_F(ValidationErrorTest, EnumValuesConflictLegacyBehavior) {
6872   BuildFileWithErrors(
6873       "syntax: 'proto3'"
6874       "name: 'foo.proto' "
6875       "enum_type {"
6876       "  name: 'FooEnum' "
6877       "  options { deprecated_legacy_json_field_conflicts: true }"
6878       "  value { name: 'BAR' number: 0 }"
6879       "  value { name: 'bar' number: 1 }"
6880       "}",
6881       "foo.proto: bar: NAME: Enum name bar has the same name as BAR "
6882       "if you ignore case and strip out the enum name prefix (if any). "
6883       "(If you are using allow_alias, please assign the same number "
6884       "to each enum value name.)\n");
6885 
6886   BuildFileWithErrors(
6887       "syntax: 'proto3'"
6888       "name: 'foo.proto' "
6889       "enum_type {"
6890       "  name: 'FooEnum' "
6891       "  options { deprecated_legacy_json_field_conflicts: true }"
6892       "  value { name: 'FOO_ENUM__BAR_BAZ' number: 0 }"
6893       "  value { name: 'BAR_BAZ' number: 1 }"
6894       "}",
6895       "foo.proto: BAR_BAZ: NAME: Enum name BAR_BAZ has the same name as "
6896       "FOO_ENUM__BAR_BAZ if you ignore case and strip out the enum name "
6897       "prefix "
6898       "(if any). (If you are using allow_alias, please assign the same "
6899       "number to each enum value name.)\n");
6900 
6901   BuildFileWithWarnings(
6902       "syntax: 'proto2'"
6903       "name: 'foo.proto' "
6904       "enum_type {"
6905       "  name: 'FooEnum' "
6906       "  options { deprecated_legacy_json_field_conflicts: true }"
6907       "  value { name: 'BAR' number: 0 }"
6908       "  value { name: 'bar' number: 1 }"
6909       "}",
6910       "foo.proto: bar: NAME: Enum name bar has the same name as BAR "
6911       "if you ignore case and strip out the enum name prefix (if any). "
6912       "(If you are using allow_alias, please assign the same number "
6913       "to each enum value name.)\n");
6914 }
6915 
TEST_F(ValidationErrorTest,MapEntryConflictsWithOneof)6916 TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) {
6917   FileDescriptorProto file_proto;
6918   FillValidMapEntry(&file_proto);
6919   TextFormat::MergeFromString(
6920       "oneof_decl { "
6921       "  name: 'FooMapEntry' "
6922       "}"
6923       "field { "
6924       "  name: 'int_field' "
6925       "  type: TYPE_INT32 "
6926       "  label: LABEL_OPTIONAL "
6927       "  oneof_index: 0 "
6928       "  number: 100 "
6929       "} ",
6930       file_proto.mutable_message_type(0));
6931   BuildFileWithErrors(
6932       file_proto,
6933       "foo.proto: Foo.FooMapEntry: NAME: \"FooMapEntry\" is already defined in "
6934       "\"Foo\".\n"
6935       "foo.proto: Foo.foo_map: TYPE: \"FooMapEntry\" is not defined.\n"
6936       "foo.proto: Foo: NAME: Expanded map entry type FooMapEntry conflicts "
6937       "with an existing oneof type.\n");
6938 }
6939 
TEST_F(ValidationErrorTest,MapEntryUsesNoneZeroEnumDefaultValue)6940 TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) {
6941   BuildFileWithErrors(
6942       "name: \"foo.proto\" "
6943       "enum_type {"
6944       "  name: \"Bar\""
6945       "  value { name:\"ENUM_A\" number:1 }"
6946       "  value { name:\"ENUM_B\" number:2 }"
6947       "}"
6948       "message_type {"
6949       "  name: 'Foo' "
6950       "  field { "
6951       "    name: 'foo_map' number: 1 label:LABEL_REPEATED "
6952       "    type_name: 'FooMapEntry' "
6953       "  } "
6954       "  nested_type { "
6955       "    name: 'FooMapEntry' "
6956       "    options {  map_entry: true } "
6957       "    field { "
6958       "      name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL "
6959       "    } "
6960       "    field { "
6961       "      name: 'value' number: 2 type_name:\"Bar\" label:LABEL_OPTIONAL "
6962       "    } "
6963       "  } "
6964       "}",
6965       "foo.proto: Foo.foo_map: "
6966       "TYPE: Enum value in map must define 0 as the first value.\n");
6967 }
6968 
TEST_F(ValidationErrorTest,Proto3RequiredFields)6969 TEST_F(ValidationErrorTest, Proto3RequiredFields) {
6970   BuildFileWithErrors(
6971       "name: 'foo.proto' "
6972       "syntax: 'proto3' "
6973       "message_type { "
6974       "  name: 'Foo' "
6975       "  field { name:'foo' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
6976       "}",
6977       "foo.proto: Foo.foo: TYPE: Required fields are not allowed in "
6978       "proto3.\n");
6979 
6980   // applied to nested types as well.
6981   BuildFileWithErrors(
6982       "name: 'foo.proto' "
6983       "syntax: 'proto3' "
6984       "message_type { "
6985       "  name: 'Foo' "
6986       "  nested_type { "
6987       "    name : 'Bar' "
6988       "    field { name:'bar' number:1 label:LABEL_REQUIRED type:TYPE_INT32 } "
6989       "  } "
6990       "}",
6991       "foo.proto: Foo.Bar.bar: TYPE: Required fields are not allowed in "
6992       "proto3.\n");
6993 
6994   // optional and repeated fields are OK.
6995   BuildFile(
6996       "name: 'foo.proto' "
6997       "syntax: 'proto3' "
6998       "message_type { "
6999       "  name: 'Foo' "
7000       "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
7001       "  field { name:'bar' number:2 label:LABEL_REPEATED type:TYPE_INT32 } "
7002       "}");
7003 }
7004 
TEST_F(ValidationErrorTest,ValidateProto3DefaultValue)7005 TEST_F(ValidationErrorTest, ValidateProto3DefaultValue) {
7006   BuildFileWithErrors(
7007       "name: 'foo.proto' "
7008       "syntax: 'proto3' "
7009       "message_type { "
7010       "  name: 'Foo' "
7011       "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
7012       "          default_value: '1' }"
7013       "}",
7014       "foo.proto: Foo.foo: DEFAULT_VALUE: Explicit default values are not "
7015       "allowed in proto3.\n");
7016 
7017   BuildFileWithErrors(
7018       "name: 'foo.proto' "
7019       "syntax: 'proto3' "
7020       "message_type { "
7021       "  name: 'Foo' "
7022       "  nested_type { "
7023       "    name : 'Bar' "
7024       "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 "
7025       "            default_value: '1' }"
7026       "  } "
7027       "}",
7028       "foo.proto: Foo.Bar.bar: DEFAULT_VALUE: Explicit default values are not "
7029       "allowed in proto3.\n");
7030 }
7031 
TEST_F(ValidationErrorTest,ValidateProto3ExtensionRange)7032 TEST_F(ValidationErrorTest, ValidateProto3ExtensionRange) {
7033   BuildFileWithErrors(
7034       "name: 'foo.proto' "
7035       "syntax: 'proto3' "
7036       "message_type { "
7037       "  name: 'Foo' "
7038       "  field { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
7039       "  extension_range { start:10 end:100 } "
7040       "}",
7041       "foo.proto: Foo: NUMBER: Extension ranges are not allowed in "
7042       "proto3.\n");
7043 
7044   BuildFileWithErrors(
7045       "name: 'foo.proto' "
7046       "syntax: 'proto3' "
7047       "message_type { "
7048       "  name: 'Foo' "
7049       "  nested_type { "
7050       "    name : 'Bar' "
7051       "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 } "
7052       "    extension_range { start:10 end:100 } "
7053       "  } "
7054       "}",
7055       "foo.proto: Foo.Bar: NUMBER: Extension ranges are not allowed in "
7056       "proto3.\n");
7057 }
7058 
TEST_F(ValidationErrorTest,ValidateProto3MessageSetWireFormat)7059 TEST_F(ValidationErrorTest, ValidateProto3MessageSetWireFormat) {
7060   BuildFileWithErrors(
7061       "name: 'foo.proto' "
7062       "syntax: 'proto3' "
7063       "message_type { "
7064       "  name: 'Foo' "
7065       "  options { message_set_wire_format: true } "
7066       "}",
7067       "foo.proto: Foo: NAME: MessageSet is not supported "
7068       "in proto3.\n");
7069 }
7070 
TEST_F(ValidationErrorTest,ValidateProto3Enum)7071 TEST_F(ValidationErrorTest, ValidateProto3Enum) {
7072   BuildFileWithErrors(
7073       "name: 'foo.proto' "
7074       "syntax: 'proto3' "
7075       "enum_type { "
7076       "  name: 'FooEnum' "
7077       "  value { name: 'FOO_FOO' number:1 } "
7078       "}",
7079       "foo.proto: FooEnum: NUMBER: The first enum value must be "
7080       "zero for open enums.\n");
7081 
7082   BuildFileWithErrors(
7083       "name: 'foo.proto' "
7084       "syntax: 'proto3' "
7085       "message_type { "
7086       "  name: 'Foo' "
7087       "  enum_type { "
7088       "    name: 'FooEnum' "
7089       "    value { name: 'FOO_FOO' number:1 } "
7090       "  } "
7091       "}",
7092       "foo.proto: Foo.FooEnum: NUMBER: The first enum value must be "
7093       "zero for open enums.\n");
7094 
7095   // valid case.
7096   BuildFile(
7097       "name: 'foo.proto' "
7098       "syntax: 'proto3' "
7099       "enum_type { "
7100       "  name: 'FooEnum' "
7101       "  value { name: 'FOO_FOO' number:0 } "
7102       "}");
7103 }
7104 
TEST_F(ValidationErrorTest,ValidateProto3Group)7105 TEST_F(ValidationErrorTest, ValidateProto3Group) {
7106   BuildFileWithErrors(
7107       "name: 'foo.proto' "
7108       "syntax: 'proto3' "
7109       "message_type { "
7110       "  name: 'Foo' "
7111       "  nested_type { "
7112       "    name: 'FooGroup' "
7113       "  } "
7114       "  field { name:'foo_group' number: 1 label:LABEL_OPTIONAL "
7115       "          type: TYPE_GROUP type_name:'FooGroup' } "
7116       "}",
7117       "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 "
7118       "syntax.\n");
7119 }
7120 
7121 
TEST_F(ValidationErrorTest,ValidateProto3EnumFromProto2)7122 TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) {
7123   // Define an enum in a proto2 file.
7124   BuildFile(
7125       "name: 'foo.proto' "
7126       "package: 'foo' "
7127       "syntax: 'proto2' "
7128       "enum_type { "
7129       "  name: 'FooEnum' "
7130       "  value { name: 'DEFAULT_OPTION' number:0 } "
7131       "}");
7132 
7133   // Now try to refer to it. (All tests in the fixture use the same pool, so we
7134   // can refer to the enum above in this definition.)
7135   BuildFileWithErrors(
7136       "name: 'bar.proto' "
7137       "dependency: 'foo.proto' "
7138       "syntax: 'proto3' "
7139       "message_type { "
7140       "  name: 'Foo' "
7141       "    field { name:'bar' number:1 label:LABEL_OPTIONAL type:TYPE_ENUM "
7142       "            type_name: 'foo.FooEnum' }"
7143       "}",
7144       "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not an open "
7145       "enum, but is used in \"Foo\" which is a proto3 message type.\n");
7146 }
7147 
TEST_F(ValidationErrorTest,ValidateProto3ClosedEnum)7148 TEST_F(ValidationErrorTest, ValidateProto3ClosedEnum) {
7149   // Define a closed enum in an editions file.
7150   BuildFile(R"pb(name: 'foo.proto'
7151                  package: 'foo'
7152                  syntax: 'editions'
7153                  edition: EDITION_2023
7154                  enum_type {
7155                    name: 'FooEnum'
7156                    value { name: 'DEFAULT_OPTION' number: 0 }
7157                    options { features { enum_type: CLOSED } }
7158                  })pb");
7159 
7160   BuildFileWithErrors(
7161       R"pb(name: 'bar.proto'
7162            dependency: 'foo.proto'
7163            syntax: 'proto3'
7164            message_type {
7165              name: 'Foo'
7166              field {
7167                name: 'bar'
7168                number: 1
7169                label: LABEL_OPTIONAL
7170                type: TYPE_ENUM
7171                type_name: 'foo.FooEnum'
7172              }
7173            })pb",
7174       "bar.proto: Foo.bar: TYPE: Enum type \"foo.FooEnum\" is not an open "
7175       "enum, but is used in \"Foo\" which is a proto3 message type.\n");
7176 }
7177 
TEST_F(ValidationErrorTest,ValidateProto3OpenEnum)7178 TEST_F(ValidationErrorTest, ValidateProto3OpenEnum) {
7179   // Define an open enum in an editions file.
7180   const FileDescriptor* foo =
7181       BuildFile(R"pb(name: 'foo.proto'
7182                      package: 'foo'
7183                      syntax: 'editions'
7184                      edition: EDITION_2023
7185                      enum_type {
7186                        name: 'FooEnum'
7187                        value { name: 'DEFAULT_OPTION' number: 0 }
7188                      })pb");
7189   const EnumDescriptor* enm = foo->enum_type(0);
7190   ASSERT_NE(enm, nullptr);
7191 
7192   const FileDescriptor* bar = BuildFile(
7193       R"pb(name: 'bar.proto'
7194            dependency: 'foo.proto'
7195            syntax: 'proto3'
7196            message_type {
7197              name: 'Foo'
7198              field {
7199                name: 'bar'
7200                number: 1
7201                label: LABEL_OPTIONAL
7202                type: TYPE_ENUM
7203                type_name: 'foo.FooEnum'
7204              }
7205            })pb");
7206   ASSERT_NE(bar, nullptr);
7207 
7208   EXPECT_EQ(bar->message_type(0)->field(0)->enum_type(), enm);
7209 }
7210 
TEST_F(ValidationErrorTest,ValidateProto3Extension)7211 TEST_F(ValidationErrorTest, ValidateProto3Extension) {
7212   // Valid for options.
7213   DescriptorPool pool;
7214   FileDescriptorProto file_proto;
7215   // Add "google/protobuf/descriptor.proto".
7216   FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto);
7217   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
7218   // Add "foo.proto":
7219   //   import "google/protobuf/descriptor.proto";
7220   //   extend google.protobuf.FileOptions {
7221   //     optional string test_file_opt = 1001;
7222   //   }
7223   //   extend google.protobuf.MessageOptions {
7224   //     optional string test_msg_opt = 1002;
7225   //   }
7226   //   extend google.protobuf.FieldOptions {
7227   //     optional string test_field_opt = 1003;
7228   //   }
7229   //   extend google.protobuf.EnumOptions {
7230   //     repeated int32 test_enum_opt = 1004;
7231   //   }
7232   //   extend google.protobuf.EnumValueOptions {
7233   //     optional int32 test_enumval_opt = 1005;
7234   //   }
7235   //   extend google.protobuf.ServiceOptions {
7236   //     repeated int32 test_svc_opt = 1006;
7237   //   }
7238   //   extend google.protobuf.MethodOptions {
7239   //     optional string test_method_opt = 1007;
7240   //   }
7241   //   extend google.protobuf.OneofOptions {
7242   //     optional string test_oneof_opt = 1008;
7243   //   }
7244   //   extend google.protobuf.ExtensionRangeOptions {
7245   //     optional string test_ext_opt = 1009;
7246   //   }
7247   file_proto.Clear();
7248   file_proto.set_name("foo.proto");
7249   file_proto.set_syntax("proto3");
7250   file_proto.add_dependency("google/protobuf/descriptor.proto");
7251   AddExtension(&file_proto, "google.protobuf.FileOptions", "test_file_opt", 1001,
7252                FieldDescriptorProto::LABEL_OPTIONAL,
7253                FieldDescriptorProto::TYPE_STRING);
7254   AddExtension(&file_proto, "google.protobuf.MessageOptions", "test_msg_opt", 1001,
7255                FieldDescriptorProto::LABEL_OPTIONAL,
7256                FieldDescriptorProto::TYPE_STRING);
7257   AddExtension(&file_proto, "google.protobuf.FieldOptions", "test_field_opt", 1003,
7258                FieldDescriptorProto::LABEL_OPTIONAL,
7259                FieldDescriptorProto::TYPE_STRING);
7260   AddExtension(&file_proto, "google.protobuf.EnumOptions", "test_enum_opt", 1004,
7261                FieldDescriptorProto::LABEL_REPEATED,
7262                FieldDescriptorProto::TYPE_INT32);
7263   AddExtension(&file_proto, "google.protobuf.EnumValueOptions", "test_enumval_opt", 1005,
7264                FieldDescriptorProto::LABEL_OPTIONAL,
7265                FieldDescriptorProto::TYPE_INT32);
7266   AddExtension(&file_proto, "google.protobuf.ServiceOptions", "test_svc_opt", 1006,
7267                FieldDescriptorProto::LABEL_REPEATED,
7268                FieldDescriptorProto::TYPE_INT32);
7269   AddExtension(&file_proto, "google.protobuf.MethodOptions", "test_method_opt", 1007,
7270                FieldDescriptorProto::LABEL_OPTIONAL,
7271                FieldDescriptorProto::TYPE_STRING);
7272   AddExtension(&file_proto, "google.protobuf.OneofOptions", "test_oneof_opt", 1008,
7273                FieldDescriptorProto::LABEL_OPTIONAL,
7274                FieldDescriptorProto::TYPE_STRING);
7275   AddExtension(&file_proto, "google.protobuf.ExtensionRangeOptions", "test_ext_opt",
7276                1009, FieldDescriptorProto::LABEL_OPTIONAL,
7277                FieldDescriptorProto::TYPE_STRING);
7278   ASSERT_TRUE(pool.BuildFile(file_proto) != nullptr);
7279 
7280   // Copy and change the package of the descriptor.proto
7281   BuildFile(
7282       "name: 'google.protobuf.proto' "
7283       "syntax: 'proto2' "
7284       "message_type { "
7285       "  name: 'Container' extension_range { start: 1 end: 1000 } "
7286       "}");
7287   BuildFileWithErrors(
7288       "name: 'bar.proto' "
7289       "syntax: 'proto3' "
7290       "dependency: 'google.protobuf.proto' "
7291       "extension { "
7292       "  name: 'bar' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 "
7293       "  extendee: 'Container' "
7294       "}",
7295       "bar.proto: bar: EXTENDEE: Extensions in proto3 are only allowed for "
7296       "defining options.\n");
7297 }
7298 
7299 // Test that field names that may conflict in JSON is not allowed by protoc.
TEST_F(ValidationErrorTest,ValidateJsonNameConflictProto3)7300 TEST_F(ValidationErrorTest, ValidateJsonNameConflictProto3) {
7301   // The comparison is case-insensitive.
7302   BuildFileWithErrors(
7303       "name: 'foo.proto' "
7304       "syntax: 'proto3' "
7305       "message_type {"
7306       "  name: 'Foo'"
7307       "  field { name:'_name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7308       "  field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7309       "}",
7310       "foo.proto: Foo: NAME: The default JSON name of field \"Name\" "
7311       "(\"Name\") "
7312       "conflicts with the default JSON name of field \"_name\".\n");
7313 
7314   // Underscores are ignored.
7315   BuildFileWithErrors(
7316       "name: 'foo.proto' "
7317       "syntax: 'proto3' "
7318       "message_type {"
7319       "  name: 'Foo'"
7320       "  field { name:'AB' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7321       "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7322       "}",
7323       "foo.proto: Foo: NAME: The default JSON name of field \"_a__b_\" "
7324       "(\"AB\") "
7325       "conflicts with the default JSON name of field \"AB\".\n");
7326 }
7327 
TEST_F(ValidationErrorTest,ValidateJsonNameConflictProto2)7328 TEST_F(ValidationErrorTest, ValidateJsonNameConflictProto2) {
7329   BuildFileWithWarnings(
7330       "name: 'foo.proto' "
7331       "syntax: 'proto2' "
7332       "message_type {"
7333       "  name: 'Foo'"
7334       "  field { name:'AB' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7335       "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7336       "}",
7337       "foo.proto: Foo: NAME: The default JSON name of field \"_a__b_\" "
7338       "(\"AB\") "
7339       "conflicts with the default JSON name of field \"AB\".\n");
7340 }
7341 
7342 // Test that field names that may conflict in JSON is not allowed by protoc.
TEST_F(ValidationErrorTest,ValidateJsonNameConflictProto3Legacy)7343 TEST_F(ValidationErrorTest, ValidateJsonNameConflictProto3Legacy) {
7344   BuildFile(
7345       "name: 'foo.proto' "
7346       "syntax: 'proto3' "
7347       "message_type {"
7348       "  name: 'Foo'"
7349       "  options { deprecated_legacy_json_field_conflicts: true }"
7350       "  field { name:'AB' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7351       "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7352       "}");
7353 }
7354 
TEST_F(ValidationErrorTest,ValidateJsonNameConflictProto2Legacy)7355 TEST_F(ValidationErrorTest, ValidateJsonNameConflictProto2Legacy) {
7356   BuildFile(
7357       "name: 'foo.proto' "
7358       "syntax: 'proto2' "
7359       "message_type {"
7360       "  name: 'Foo'"
7361       "  options { deprecated_legacy_json_field_conflicts: true }"
7362       "  field { name:'AB' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7363       "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
7364       "}");
7365 }
7366 
7367 
TEST_F(ValidationErrorTest,UnusedImportWithOtherError)7368 TEST_F(ValidationErrorTest, UnusedImportWithOtherError) {
7369   BuildFile(
7370       "name: 'bar.proto' "
7371       "message_type {"
7372       "  name: 'Bar'"
7373       "}");
7374 
7375   pool_.AddDirectInputFile("foo.proto", true);
7376   BuildFileWithErrors(
7377       "name: 'foo.proto' "
7378       "dependency: 'bar.proto' "
7379       "message_type {"
7380       "  name: 'Foo'"
7381       "  extension { name:'foo' number:1 label:LABEL_OPTIONAL type:TYPE_INT32"
7382       "              extendee: 'Baz' }"
7383       "}",
7384 
7385       // Should not also contain unused import error.
7386       "foo.proto: Foo.foo: EXTENDEE: \"Baz\" is not defined.\n");
7387 }
7388 
TEST(IsGroupLike,GroupLikeDelimited)7389 TEST(IsGroupLike, GroupLikeDelimited) {
7390   using internal::cpp::IsGroupLike;
7391   const Descriptor& msg = *editions_unittest::TestDelimited::descriptor();
7392   const FileDescriptor& file =
7393       *editions_unittest::TestDelimited::descriptor()->file();
7394 
7395   EXPECT_EQ(msg.FindFieldByName("grouplike")->type(),
7396             FieldDescriptor::TYPE_GROUP);
7397   EXPECT_TRUE(IsGroupLike(*msg.FindFieldByName("grouplike")));
7398   EXPECT_EQ(file.FindExtensionByName("grouplikefilescope")->type(),
7399             FieldDescriptor::TYPE_GROUP);
7400   EXPECT_TRUE(IsGroupLike(*file.FindExtensionByName("grouplikefilescope")));
7401 }
7402 
TEST(IsGroupLike,GroupLikeNotDelimited)7403 TEST(IsGroupLike, GroupLikeNotDelimited) {
7404   using internal::cpp::IsGroupLike;
7405   const Descriptor& msg = *editions_unittest::TestDelimited::descriptor();
7406   const FileDescriptor& file =
7407       *editions_unittest::TestDelimited::descriptor()->file();
7408 
7409   EXPECT_EQ(msg.FindFieldByName("lengthprefixed")->type(),
7410             FieldDescriptor::TYPE_MESSAGE);
7411   EXPECT_FALSE(IsGroupLike(*msg.FindFieldByName("lengthprefixed")));
7412   EXPECT_EQ(file.FindExtensionByName("lengthprefixed")->type(),
7413             FieldDescriptor::TYPE_MESSAGE);
7414   EXPECT_FALSE(IsGroupLike(*file.FindExtensionByName("lengthprefixed")));
7415 }
7416 
TEST(IsGroupLike,GroupLikeMismatchedName)7417 TEST(IsGroupLike, GroupLikeMismatchedName) {
7418   using internal::cpp::IsGroupLike;
7419   const Descriptor& msg = *editions_unittest::TestDelimited::descriptor();
7420   const FileDescriptor& file =
7421       *editions_unittest::TestDelimited::descriptor()->file();
7422 
7423   EXPECT_EQ(msg.FindFieldByName("notgrouplike")->type(),
7424             FieldDescriptor::TYPE_GROUP);
7425   EXPECT_FALSE(IsGroupLike(*msg.FindFieldByName("notgrouplike")));
7426   EXPECT_EQ(file.FindExtensionByName("not_group_like_scope")->type(),
7427             FieldDescriptor::TYPE_GROUP);
7428   EXPECT_FALSE(IsGroupLike(*file.FindExtensionByName("not_group_like_scope")));
7429 }
7430 
TEST(IsGroupLike,GroupLikeMismatchedScope)7431 TEST(IsGroupLike, GroupLikeMismatchedScope) {
7432   using internal::cpp::IsGroupLike;
7433   const Descriptor& msg = *editions_unittest::TestDelimited::descriptor();
7434   const FileDescriptor& file =
7435       *editions_unittest::TestDelimited::descriptor()->file();
7436 
7437   EXPECT_EQ(msg.FindFieldByName("notgrouplikescope")->type(),
7438             FieldDescriptor::TYPE_GROUP);
7439   EXPECT_FALSE(IsGroupLike(*msg.FindFieldByName("notgrouplikescope")));
7440   EXPECT_EQ(file.FindExtensionByName("grouplike")->type(),
7441             FieldDescriptor::TYPE_GROUP);
7442   EXPECT_FALSE(IsGroupLike(*file.FindExtensionByName("grouplike")));
7443 }
7444 
TEST(IsGroupLike,GroupLikeMismatchedFile)7445 TEST(IsGroupLike, GroupLikeMismatchedFile) {
7446   using internal::cpp::IsGroupLike;
7447   const Descriptor& msg = *editions_unittest::TestDelimited::descriptor();
7448   const FileDescriptor& file =
7449       *editions_unittest::TestDelimited::descriptor()->file();
7450 
7451   EXPECT_EQ(msg.FindFieldByName("messageimport")->type(),
7452             FieldDescriptor::TYPE_GROUP);
7453   EXPECT_FALSE(IsGroupLike(*msg.FindFieldByName("messageimport")));
7454   EXPECT_EQ(file.FindExtensionByName("messageimport")->type(),
7455             FieldDescriptor::TYPE_GROUP);
7456   EXPECT_FALSE(IsGroupLike(*file.FindExtensionByName("messageimport")));
7457 }
7458 
7459 using FeaturesBaseTest = ValidationErrorTest;
7460 
7461 class FeaturesTest : public FeaturesBaseTest {
7462  protected:
SetUp()7463   void SetUp() override {
7464     ValidationErrorTest::SetUp();
7465 
7466     auto default_spec = FeatureResolver::CompileDefaults(
7467         FeatureSet::descriptor(),
7468         {GetExtensionReflection(pb::cpp), GetExtensionReflection(pb::test),
7469          GetExtensionReflection(pb::TestMessage::test_message),
7470          GetExtensionReflection(pb::TestMessage::Nested::test_nested)},
7471         EDITION_PROTO2, EDITION_99999_TEST_ONLY);
7472     ASSERT_OK(default_spec);
7473     ASSERT_OK(pool_.SetFeatureSetDefaults(std::move(default_spec).value()));
7474   }
7475 };
7476 
7477 template <typename T>
GetFeatures(const T * descriptor)7478 const FeatureSet& GetFeatures(const T* descriptor) {
7479   return internal::InternalFeatureHelper::GetFeatures<T>(*descriptor);
7480 }
7481 
7482 template <typename T>
GetCoreFeatures(const T * descriptor)7483 FeatureSet GetCoreFeatures(const T* descriptor) {
7484   FeatureSet features = GetFeatures(descriptor);
7485   // Strip test features to avoid excessive brittleness.
7486   features.ClearExtension(pb::test);
7487   features.ClearExtension(pb::TestMessage::test_message);
7488   features.ClearExtension(pb::TestMessage::Nested::test_nested);
7489   return features;
7490 }
7491 
TEST_F(FeaturesTest,InvalidProto2Features)7492 TEST_F(FeaturesTest, InvalidProto2Features) {
7493   BuildDescriptorMessagesInTestPool();
7494   BuildFileWithErrors(
7495       R"pb(
7496         name: "foo.proto"
7497         syntax: "proto2"
7498         options { features { field_presence: IMPLICIT } }
7499       )pb",
7500       "foo.proto: foo.proto: EDITIONS: Features are only valid under "
7501       "editions.\n");
7502 }
7503 
TEST_F(FeaturesTest,InvalidProto3Features)7504 TEST_F(FeaturesTest, InvalidProto3Features) {
7505   BuildDescriptorMessagesInTestPool();
7506   BuildFileWithErrors(
7507       R"pb(
7508         name: "foo.proto"
7509         syntax: "proto3"
7510         options { features { field_presence: IMPLICIT } }
7511       )pb",
7512       "foo.proto: foo.proto: EDITIONS: Features are only valid "
7513       "under editions.\n");
7514 }
7515 
TEST_F(FeaturesTest,Proto2Features)7516 TEST_F(FeaturesTest, Proto2Features) {
7517   FileDescriptorProto file_proto = ParseTextOrDie(R"pb(
7518     name: "foo.proto"
7519     message_type {
7520       name: "Foo"
7521       field { name: "bar" number: 1 label: LABEL_OPTIONAL type: TYPE_INT64 }
7522       field {
7523         name: "group"
7524         number: 2
7525         label: LABEL_OPTIONAL
7526         type: TYPE_GROUP
7527         type_name: ".Foo"
7528       }
7529       field { name: "str" number: 3 label: LABEL_OPTIONAL type: TYPE_STRING }
7530       field { name: "rep" number: 4 label: LABEL_REPEATED type: TYPE_INT32 }
7531       field {
7532         name: "packed"
7533         number: 5
7534         label: LABEL_REPEATED
7535         type: TYPE_INT64
7536         options { packed: true }
7537       }
7538       field { name: "utf8" number: 6 label: LABEL_REPEATED type: TYPE_STRING }
7539       field { name: "req" number: 7 label: LABEL_REQUIRED type: TYPE_INT32 }
7540       field {
7541         name: "cord"
7542         number: 8
7543         label: LABEL_OPTIONAL
7544         type: TYPE_BYTES
7545         options { ctype: CORD }
7546       }
7547       field {
7548         name: "piece"
7549         number: 9
7550         label: LABEL_OPTIONAL
7551         type: TYPE_STRING
7552         options { ctype: STRING_PIECE }
7553       }
7554     }
7555     enum_type {
7556       name: "Foo2"
7557       value { name: "BAR" number: 1 }
7558     }
7559   )pb");
7560 
7561   BuildDescriptorMessagesInTestPool();
7562   BuildFileInTestPool(pb::CppFeatures::GetDescriptor()->file());
7563   const FileDescriptor* file = ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
7564   const Descriptor* message = file->message_type(0);
7565   const FieldDescriptor* field = message->field(0);
7566   const FieldDescriptor* group = message->field(1);
7567   EXPECT_THAT(file->options(), EqualsProto(""));
7568   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).file_feature(),
7569             pb::VALUE1);
7570   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
7571                 field_presence: EXPLICIT
7572                 enum_type: CLOSED
7573                 repeated_field_encoding: EXPANDED
7574                 utf8_validation: NONE
7575                 message_encoding: LENGTH_PREFIXED
7576                 json_format: LEGACY_BEST_EFFORT
7577                 [pb.cpp] {
7578                   legacy_closed_enum: true
7579                   string_type: STRING
7580                   enum_name_uses_string_view: false
7581                 })pb"));
7582   EXPECT_THAT(GetCoreFeatures(field), EqualsProto(R"pb(
7583                 field_presence: EXPLICIT
7584                 enum_type: CLOSED
7585                 repeated_field_encoding: EXPANDED
7586                 utf8_validation: NONE
7587                 message_encoding: LENGTH_PREFIXED
7588                 json_format: LEGACY_BEST_EFFORT
7589                 [pb.cpp] {
7590                   legacy_closed_enum: true
7591                   string_type: STRING
7592                   enum_name_uses_string_view: false
7593                 })pb"));
7594   EXPECT_THAT(GetCoreFeatures(group), EqualsProto(R"pb(
7595                 field_presence: EXPLICIT
7596                 enum_type: CLOSED
7597                 repeated_field_encoding: EXPANDED
7598                 utf8_validation: NONE
7599                 message_encoding: DELIMITED
7600                 json_format: LEGACY_BEST_EFFORT
7601                 [pb.cpp] {
7602                   legacy_closed_enum: true
7603                   string_type: STRING
7604                   enum_name_uses_string_view: false
7605                 })pb"));
7606   EXPECT_TRUE(field->has_presence());
7607   EXPECT_FALSE(field->requires_utf8_validation());
7608   EXPECT_EQ(
7609       GetUtf8CheckMode(message->FindFieldByName("str"), /*is_lite=*/false),
7610       Utf8CheckMode::kVerify);
7611   EXPECT_EQ(GetUtf8CheckMode(message->FindFieldByName("str"), /*is_lite=*/true),
7612             Utf8CheckMode::kNone);
7613   EXPECT_EQ(GetCoreFeatures(message->FindFieldByName("cord"))
7614                 .GetExtension(pb::cpp)
7615                 .string_type(),
7616             pb::CppFeatures::CORD);
7617   EXPECT_FALSE(field->is_packed());
7618   EXPECT_FALSE(field->legacy_enum_field_treated_as_closed());
7619   EXPECT_FALSE(HasPreservingUnknownEnumSemantics(field));
7620   EXPECT_FALSE(message->FindFieldByName("str")->requires_utf8_validation());
7621   EXPECT_FALSE(message->FindFieldByName("rep")->is_packed());
7622   EXPECT_FALSE(message->FindFieldByName("utf8")->requires_utf8_validation());
7623   EXPECT_TRUE(message->FindFieldByName("packed")->is_packed());
7624   EXPECT_TRUE(message->FindFieldByName("req")->is_required());
7625   EXPECT_TRUE(file->enum_type(0)->is_closed());
7626 
7627   EXPECT_EQ(message->FindFieldByName("str")->cpp_string_type(),
7628             FieldDescriptor::CppStringType::kString);
7629   EXPECT_EQ(message->FindFieldByName("cord")->cpp_string_type(),
7630             FieldDescriptor::CppStringType::kCord);
7631 
7632   // Check round-trip consistency.
7633   FileDescriptorProto proto;
7634   file->CopyTo(&proto);
7635   std::string file_textproto;
7636   google::protobuf::TextFormat::PrintToString(file_proto, &file_textproto);
7637   EXPECT_THAT(proto, EqualsProto(file_textproto));
7638 }
7639 
TEST_F(FeaturesTest,Proto3Features)7640 TEST_F(FeaturesTest, Proto3Features) {
7641   FileDescriptorProto file_proto = ParseTextOrDie(R"pb(
7642     name: "foo.proto"
7643     syntax: "proto3"
7644     message_type {
7645       name: "Foo"
7646       field { name: "bar" number: 1 label: LABEL_OPTIONAL type: TYPE_INT64 }
7647       field { name: "rep" number: 2 label: LABEL_REPEATED type: TYPE_INT64 }
7648       field { name: "str" number: 3 label: LABEL_OPTIONAL type: TYPE_STRING }
7649       field {
7650         name: "expanded"
7651         number: 4
7652         label: LABEL_REPEATED
7653         type: TYPE_INT64
7654         options { packed: false }
7655       }
7656       field { name: "utf8" number: 5 label: LABEL_OPTIONAL type: TYPE_STRING }
7657     }
7658     enum_type {
7659       name: "Foo2"
7660       value { name: "DEFAULT" number: 0 }
7661       value { name: "BAR" number: 1 }
7662     })pb");
7663 
7664   BuildDescriptorMessagesInTestPool();
7665   const FileDescriptor* file = ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
7666   const Descriptor* message = file->message_type(0);
7667   const FieldDescriptor* field = message->field(0);
7668   EXPECT_THAT(file->options(), EqualsProto(""));
7669   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).file_feature(),
7670             pb::VALUE2);
7671   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
7672                 field_presence: IMPLICIT
7673                 enum_type: OPEN
7674                 repeated_field_encoding: PACKED
7675                 utf8_validation: VERIFY
7676                 message_encoding: LENGTH_PREFIXED
7677                 json_format: ALLOW
7678                 [pb.cpp] {
7679                   legacy_closed_enum: false
7680                   string_type: STRING
7681                   enum_name_uses_string_view: false
7682                 })pb"));
7683   EXPECT_THAT(GetCoreFeatures(field), EqualsProto(R"pb(
7684                 field_presence: IMPLICIT
7685                 enum_type: OPEN
7686                 repeated_field_encoding: PACKED
7687                 utf8_validation: VERIFY
7688                 message_encoding: LENGTH_PREFIXED
7689                 json_format: ALLOW
7690                 [pb.cpp] {
7691                   legacy_closed_enum: false
7692                   string_type: STRING
7693                   enum_name_uses_string_view: false
7694                 })pb"));
7695   EXPECT_FALSE(field->has_presence());
7696   EXPECT_FALSE(field->requires_utf8_validation());
7697   EXPECT_EQ(
7698       GetUtf8CheckMode(message->FindFieldByName("str"), /*is_lite=*/false),
7699       Utf8CheckMode::kStrict);
7700   EXPECT_EQ(GetUtf8CheckMode(message->FindFieldByName("str"), /*is_lite=*/true),
7701             Utf8CheckMode::kStrict);
7702   EXPECT_FALSE(field->is_packed());
7703   EXPECT_FALSE(field->legacy_enum_field_treated_as_closed());
7704   EXPECT_FALSE(HasPreservingUnknownEnumSemantics(field));
7705   EXPECT_TRUE(message->FindFieldByName("rep")->is_packed());
7706   EXPECT_TRUE(message->FindFieldByName("str")->requires_utf8_validation());
7707   EXPECT_FALSE(message->FindFieldByName("expanded")->is_packed());
7708   EXPECT_FALSE(file->enum_type(0)->is_closed());
7709 
7710   // Check round-trip consistency.
7711   FileDescriptorProto proto;
7712   file->CopyTo(&proto);
7713   std::string file_textproto;
7714   google::protobuf::TextFormat::PrintToString(file_proto, &file_textproto);
7715   EXPECT_THAT(proto, EqualsProto(file_textproto));
7716 }
7717 
TEST_F(FeaturesTest,Proto2Proto3EnumFeatures)7718 TEST_F(FeaturesTest, Proto2Proto3EnumFeatures) {
7719   BuildDescriptorMessagesInTestPool();
7720   BuildFileInTestPool(pb::CppFeatures::GetDescriptor()->file());
7721   const FileDescriptor* file_proto3 = BuildFile(R"pb(
7722     name: "foo3.proto"
7723     syntax: "proto3"
7724     enum_type {
7725       name: "Enum3"
7726       value { name: "DEFAULT_ENUM3" number: 0 }
7727       value { name: "BAR_ENUM3" number: 1 }
7728     }
7729     message_type {
7730       name: "Message3"
7731       field {
7732         name: "enum_field"
7733         number: 1
7734         label: LABEL_OPTIONAL
7735         type: TYPE_ENUM
7736         type_name: ".Enum3"
7737       }
7738     }
7739   )pb");
7740   const FileDescriptor* file_proto2 = BuildFile(R"pb(
7741     name: "foo2.proto"
7742     dependency: "foo3.proto"
7743     enum_type {
7744       name: "Enum2"
7745       value { name: "DEFAULT_ENUM2" number: 0 }
7746       value { name: "BAR_ENUM2" number: 1 }
7747     }
7748     message_type {
7749       name: "Message2"
7750       field {
7751         name: "enum_field2"
7752         number: 1
7753         label: LABEL_OPTIONAL
7754         type: TYPE_ENUM
7755         type_name: ".Enum2"
7756       }
7757       field {
7758         name: "enum_field3"
7759         number: 2
7760         label: LABEL_OPTIONAL
7761         type: TYPE_ENUM
7762         type_name: ".Enum3"
7763       }
7764     }
7765   )pb");
7766   const Descriptor* message_proto2 = file_proto2->message_type(0);
7767   const Descriptor* message_proto3 = file_proto3->message_type(0);
7768   const FieldDescriptor* field_proto3 = message_proto3->field(0);
7769   const FieldDescriptor* field_proto2_closed = message_proto2->field(0);
7770   const FieldDescriptor* field_proto2_open = message_proto2->field(1);
7771 
7772   EXPECT_FALSE(field_proto3->legacy_enum_field_treated_as_closed());
7773   EXPECT_TRUE(field_proto2_closed->legacy_enum_field_treated_as_closed());
7774   EXPECT_TRUE(field_proto2_open->legacy_enum_field_treated_as_closed());
7775 }
7776 
7777 // Reproduces the reported issue in b/286244726 where custom options in proto3
7778 // ended up losing implicit presence.  This only occurs when options are defined
7779 // and used in the same file.
TEST_F(FeaturesTest,Proto3Extensions)7780 TEST_F(FeaturesTest, Proto3Extensions) {
7781   BuildDescriptorMessagesInTestPool();
7782   const FileDescriptor* file = BuildFile(R"pb(
7783     name: "foo.proto"
7784     syntax: "proto3"
7785     dependency: "google/protobuf/descriptor.proto"
7786     message_type {
7787       name: "Ext"
7788       field { name: "bar" number: 1 label: LABEL_OPTIONAL type: TYPE_STRING }
7789       field { name: "baz" number: 2 label: LABEL_OPTIONAL type: TYPE_INT64 }
7790     }
7791     extension {
7792       name: "bar_ext"
7793       number: 99999
7794       label: LABEL_OPTIONAL
7795       type: TYPE_MESSAGE
7796       type_name: ".Ext"
7797       extendee: ".google.protobuf.EnumValueOptions"
7798     }
7799     enum_type {
7800       name: "Foo"
7801       value {
7802         name: "BAR"
7803         number: 0
7804         options {
7805           uninterpreted_option {
7806             name { name_part: "bar_ext" is_extension: true }
7807             aggregate_value: "bar: \"\" baz: 1"
7808           }
7809         }
7810       }
7811     }
7812   )pb");
7813   EXPECT_THAT(file->enum_type(0)->value(0)->options(),
7814               EqualsProtoSerialized(&pool_, "google.protobuf.EnumValueOptions",
7815                                     R"pb([bar_ext] { baz: 1 })pb"));
7816 }
7817 
TEST_F(FeaturesTest,Proto3ExtensionPresence)7818 TEST_F(FeaturesTest, Proto3ExtensionPresence) {
7819   BuildDescriptorMessagesInTestPool();
7820   const FileDescriptor* file = BuildFile(R"pb(
7821     name: "foo.proto"
7822     syntax: "proto3"
7823     dependency: "google/protobuf/descriptor.proto"
7824     extension {
7825       name: "singular_ext"
7826       number: 1001
7827       label: LABEL_OPTIONAL
7828       type: TYPE_STRING
7829       extendee: ".google.protobuf.FileOptions"
7830     }
7831     extension {
7832       name: "singular_proto3_optional_ext"
7833       number: 1002
7834       label: LABEL_OPTIONAL
7835       type: TYPE_STRING
7836       extendee: ".google.protobuf.FileOptions"
7837       proto3_optional: true
7838     }
7839     extension {
7840       name: "repeated_ext"
7841       number: 1003
7842       label: LABEL_REPEATED
7843       type: TYPE_STRING
7844       extendee: ".google.protobuf.FileOptions"
7845     }
7846   )pb");
7847 
7848   EXPECT_TRUE(file->extension(0)->has_presence());
7849   EXPECT_TRUE(file->extension(1)->has_presence());
7850   EXPECT_FALSE(file->extension(2)->has_presence());
7851 }
7852 
TEST_F(FeaturesTest,Edition2023Defaults)7853 TEST_F(FeaturesTest, Edition2023Defaults) {
7854   FileDescriptorProto file_proto = ParseTextOrDie(R"pb(
7855     name: "foo.proto"
7856     syntax: "editions"
7857     edition: EDITION_2023
7858   )pb");
7859 
7860   BuildDescriptorMessagesInTestPool();
7861   const FileDescriptor* file = ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
7862   EXPECT_THAT(file->options(), EqualsProto(""));
7863   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
7864                 field_presence: EXPLICIT
7865                 enum_type: OPEN
7866                 repeated_field_encoding: PACKED
7867                 utf8_validation: VERIFY
7868                 message_encoding: LENGTH_PREFIXED
7869                 json_format: ALLOW
7870                 [pb.cpp] {
7871                   legacy_closed_enum: false
7872                   string_type: STRING
7873                   enum_name_uses_string_view: false
7874                 }
7875               )pb"));
7876 
7877   // Since pb::test is registered in the pool, it should end up with defaults in
7878   // our FeatureSet.
7879   EXPECT_TRUE(GetFeatures(file).HasExtension(pb::test));
7880   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).file_feature(),
7881             pb::VALUE3);
7882 }
7883 
TEST_F(FeaturesTest,Edition2023InferredFeatures)7884 TEST_F(FeaturesTest, Edition2023InferredFeatures) {
7885   FileDescriptorProto file_proto = ParseTextOrDie(R"pb(
7886     name: "foo.proto"
7887     syntax: "editions"
7888     edition: EDITION_2023
7889     message_type {
7890       name: "Foo"
7891       field { name: "str" number: 1 label: LABEL_OPTIONAL type: TYPE_STRING }
7892       field {
7893         name: "cord"
7894         number: 2
7895         label: LABEL_OPTIONAL
7896         type: TYPE_STRING
7897         options { ctype: CORD }
7898       }
7899       field {
7900         name: "piece"
7901         number: 3
7902         label: LABEL_OPTIONAL
7903         type: TYPE_STRING
7904         options { ctype: STRING_PIECE }
7905       }
7906       field {
7907         name: "view"
7908         number: 4
7909         label: LABEL_OPTIONAL
7910         type: TYPE_STRING
7911         options {
7912           features {
7913             [pb.cpp] { string_type: VIEW }
7914           }
7915         }
7916       }
7917     }
7918   )pb");
7919 
7920   BuildDescriptorMessagesInTestPool();
7921   BuildFileInTestPool(pb::CppFeatures::GetDescriptor()->file());
7922   const FileDescriptor* file = ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
7923   const Descriptor* message = file->message_type(0);
7924 
7925   EXPECT_EQ(
7926       GetCoreFeatures(message->field(0)).GetExtension(pb::cpp).string_type(),
7927       pb::CppFeatures::STRING);
7928   EXPECT_EQ(
7929       GetCoreFeatures(message->field(1)).GetExtension(pb::cpp).string_type(),
7930       pb::CppFeatures::CORD);
7931   EXPECT_EQ(
7932       GetCoreFeatures(message->field(3)).GetExtension(pb::cpp).string_type(),
7933       pb::CppFeatures::VIEW);
7934 }
7935 
TEST_F(FeaturesTest,Edition2024Defaults)7936 TEST_F(FeaturesTest, Edition2024Defaults) {
7937   FileDescriptorProto file_proto = ParseTextOrDie(R"pb(
7938     name: "foo.proto"
7939     syntax: "editions"
7940     edition: EDITION_2024
7941   )pb");
7942 
7943   BuildDescriptorMessagesInTestPool();
7944   const FileDescriptor* file = ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
7945   EXPECT_THAT(file->options(), EqualsProto(""));
7946   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
7947                 field_presence: EXPLICIT
7948                 enum_type: OPEN
7949                 repeated_field_encoding: PACKED
7950                 utf8_validation: VERIFY
7951                 message_encoding: LENGTH_PREFIXED
7952                 json_format: ALLOW
7953                 [pb.cpp] {
7954                   legacy_closed_enum: false
7955                   string_type: VIEW
7956                   enum_name_uses_string_view: true
7957                 }
7958               )pb"));
7959 
7960   // Since pb::test is registered in the pool, it should end up with defaults in
7961   // our FeatureSet.
7962   EXPECT_TRUE(GetFeatures(file).HasExtension(pb::test));
7963   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).file_feature(),
7964             pb::VALUE3);
7965 }
7966 
TEST_F(FeaturesBaseTest,DefaultEdition2023Defaults)7967 TEST_F(FeaturesBaseTest, DefaultEdition2023Defaults) {
7968   BuildDescriptorMessagesInTestPool();
7969   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
7970   const FileDescriptor* file = BuildFile(R"pb(
7971     name: "foo.proto"
7972     syntax: "editions"
7973     edition: EDITION_2023
7974     dependency: "google/protobuf/unittest_features.proto"
7975   )pb");
7976   ASSERT_NE(file, nullptr);
7977 
7978   EXPECT_THAT(file->options(), EqualsProto(""));
7979   EXPECT_THAT(GetFeatures(file), EqualsProto(R"pb(
7980                 field_presence: EXPLICIT
7981                 enum_type: OPEN
7982                 repeated_field_encoding: PACKED
7983                 utf8_validation: VERIFY
7984                 message_encoding: LENGTH_PREFIXED
7985                 json_format: ALLOW
7986                 [pb.cpp] {
7987                   legacy_closed_enum: false
7988                   string_type: STRING
7989                   enum_name_uses_string_view: false
7990                 }
7991               )pb"));
7992   EXPECT_FALSE(GetFeatures(file).HasExtension(pb::test));
7993 }
7994 
TEST_F(FeaturesTest,ClearsOptions)7995 TEST_F(FeaturesTest, ClearsOptions) {
7996   BuildDescriptorMessagesInTestPool();
7997   const FileDescriptor* file = BuildFile(R"pb(
7998     name: "foo.proto"
7999     syntax: "editions"
8000     edition: EDITION_2023
8001     options {
8002       java_package: "bar"
8003       features { field_presence: IMPLICIT }
8004     }
8005   )pb");
8006   EXPECT_THAT(file->options(), EqualsProto("java_package: 'bar'"));
8007   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
8008                 field_presence: IMPLICIT
8009                 enum_type: OPEN
8010                 repeated_field_encoding: PACKED
8011                 utf8_validation: VERIFY
8012                 message_encoding: LENGTH_PREFIXED
8013                 json_format: ALLOW
8014                 [pb.cpp] {
8015                   legacy_closed_enum: false
8016                   string_type: STRING
8017                   enum_name_uses_string_view: false
8018                 })pb"));
8019 }
8020 
TEST_F(FeaturesTest,RestoresOptionsRoundTrip)8021 TEST_F(FeaturesTest, RestoresOptionsRoundTrip) {
8022   BuildDescriptorMessagesInTestPool();
8023   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8024   const FileDescriptor* file = BuildFile(R"pb(
8025     name: "foo.proto"
8026     syntax: "editions"
8027     edition: EDITION_2023
8028     dependency: "google/protobuf/unittest_features.proto"
8029     options {
8030       java_package: "bar"
8031       features {
8032         [pb.test] { file_feature: VALUE3 }
8033       }
8034     }
8035     message_type {
8036       name: "Foo"
8037       options {
8038         deprecated: true
8039         features {
8040           [pb.test] { message_feature: VALUE3 }
8041         }
8042       }
8043       field {
8044         name: "bar"
8045         number: 1
8046         label: LABEL_REPEATED
8047         type: TYPE_INT64
8048         options {
8049           deprecated: true
8050           features {
8051             [pb.test] { field_feature: VALUE9 }
8052           }
8053         }
8054       }
8055       field {
8056         name: "oneof_field"
8057         number: 2
8058         label: LABEL_OPTIONAL
8059         type: TYPE_INT64
8060         oneof_index: 0
8061       }
8062       oneof_decl {
8063         name: "foo_oneof"
8064         options {
8065           features {
8066             [pb.test] { oneof_feature: VALUE7 }
8067           }
8068         }
8069       }
8070       extension_range {
8071         start: 10
8072         end: 100
8073         options {
8074           verification: UNVERIFIED
8075           features {
8076             [pb.test] { extension_range_feature: VALUE15 }
8077           }
8078         }
8079       }
8080     }
8081     enum_type {
8082       name: "FooEnum"
8083       options {
8084         deprecated: true
8085         features {
8086           [pb.test] { enum_feature: VALUE4 }
8087         }
8088       }
8089       value {
8090         name: "BAR"
8091         number: 0
8092         options {
8093           deprecated: true
8094           features {
8095             [pb.test] { enum_entry_feature: VALUE8 }
8096           }
8097         }
8098       }
8099     }
8100     service {
8101       name: "FooService"
8102       options {
8103         deprecated: true
8104         features {
8105           [pb.test] { service_feature: VALUE11 }
8106         }
8107       }
8108       method {
8109         name: "BarMethod"
8110         input_type: "Foo"
8111         output_type: "Foo"
8112         options {
8113           deprecated: true
8114           features {
8115             [pb.test] { method_feature: VALUE12 }
8116           }
8117         }
8118       }
8119     }
8120   )pb");
8121   FileDescriptorProto proto;
8122   file->CopyTo(&proto);
8123   EXPECT_THAT(proto.options(),
8124               EqualsProto(R"pb(java_package: 'bar'
8125                                features {
8126                                  [pb.test] { file_feature: VALUE3 }
8127                                })pb"));
8128   EXPECT_THAT(proto.message_type(0).options(),
8129               EqualsProto(R"pb(deprecated: true
8130                                features {
8131                                  [pb.test] { message_feature: VALUE3 }
8132                                })pb"));
8133   EXPECT_THAT(proto.message_type(0).field(0).options(),
8134               EqualsProto(R"pb(deprecated: true
8135                                features {
8136                                  [pb.test] { field_feature: VALUE9 }
8137                                })pb"));
8138   EXPECT_THAT(proto.message_type(0).oneof_decl(0).options(),
8139               EqualsProto(R"pb(features {
8140                                  [pb.test] { oneof_feature: VALUE7 }
8141                                })pb"));
8142   EXPECT_THAT(proto.message_type(0).extension_range(0).options(),
8143               EqualsProto(R"pb(verification: UNVERIFIED
8144                                features {
8145                                  [pb.test] { extension_range_feature: VALUE15 }
8146                                })pb"));
8147   EXPECT_THAT(proto.enum_type(0).options(),
8148               EqualsProto(R"pb(deprecated: true
8149                                features {
8150                                  [pb.test] { enum_feature: VALUE4 }
8151                                })pb"));
8152   EXPECT_THAT(proto.enum_type(0).value(0).options(),
8153               EqualsProto(R"pb(deprecated: true
8154                                features {
8155                                  [pb.test] { enum_entry_feature: VALUE8 }
8156                                })pb"));
8157   EXPECT_THAT(proto.service(0).options(),
8158               EqualsProto(R"pb(deprecated: true
8159                                features {
8160                                  [pb.test] { service_feature: VALUE11 }
8161                                })pb"));
8162   EXPECT_THAT(proto.service(0).method(0).options(),
8163               EqualsProto(R"pb(deprecated: true
8164                                features {
8165                                  [pb.test] { method_feature: VALUE12 }
8166                                })pb"));
8167 }
8168 
TEST_F(FeaturesTest,ReusesFeaturesFromParent)8169 TEST_F(FeaturesTest, ReusesFeaturesFromParent) {
8170   BuildDescriptorMessagesInTestPool();
8171   const FileDescriptor* file = BuildFile(R"pb(
8172     name: "foo.proto"
8173     syntax: "editions"
8174     edition: EDITION_2023
8175     options { features { field_presence: IMPLICIT } }
8176     message_type {
8177       name: "Foo"
8178       options { deprecated: true }
8179       field {
8180         name: "bar"
8181         number: 1
8182         label: LABEL_REPEATED
8183         type: TYPE_INT64
8184         options { deprecated: true }
8185       }
8186     }
8187   )pb");
8188   EXPECT_EQ(&GetFeatures(file), &GetFeatures(file->message_type(0)));
8189   EXPECT_EQ(&GetFeatures(file), &GetFeatures(file->message_type(0)->field(0)));
8190 }
8191 
TEST_F(FeaturesTest,ReusesFeaturesFromSibling)8192 TEST_F(FeaturesTest, ReusesFeaturesFromSibling) {
8193   BuildDescriptorMessagesInTestPool();
8194   const FileDescriptor* file = BuildFile(R"pb(
8195     name: "foo.proto"
8196     syntax: "editions"
8197     edition: EDITION_2023
8198     options { features { field_presence: IMPLICIT } }
8199     message_type {
8200       name: "Foo"
8201       options { deprecated: true }
8202       field {
8203         name: "bar1"
8204         number: 1
8205         label: LABEL_OPTIONAL
8206         type: TYPE_INT64
8207         options {
8208           deprecated: true
8209           features { field_presence: EXPLICIT }
8210         }
8211       }
8212       field {
8213         name: "baz"
8214         number: 2
8215         label: LABEL_OPTIONAL
8216         type: TYPE_STRING
8217         options { features { field_presence: EXPLICIT } }
8218       }
8219     }
8220   )pb");
8221   const Descriptor* message = file->message_type(0);
8222   EXPECT_NE(&GetFeatures(file), &GetFeatures(message->field(0)));
8223   EXPECT_EQ(&GetFeatures(message->field(0)), &GetFeatures(message->field(1)));
8224 }
8225 
TEST_F(FeaturesTest,ReusesFeaturesFromDifferentFile)8226 TEST_F(FeaturesTest, ReusesFeaturesFromDifferentFile) {
8227   BuildDescriptorMessagesInTestPool();
8228   const FileDescriptor* file1 = BuildFile(R"pb(
8229     name: "foo.proto"
8230     syntax: "editions"
8231     edition: EDITION_2023
8232     options { features { field_presence: IMPLICIT } }
8233   )pb");
8234   const FileDescriptor* file2 = BuildFile(R"pb(
8235     name: "bar.proto"
8236     syntax: "editions"
8237     edition: EDITION_2023
8238     options { features { field_presence: IMPLICIT } }
8239   )pb");
8240   EXPECT_EQ(&GetFeatures(file1), &GetFeatures(file2));
8241 }
8242 
TEST_F(FeaturesTest,ReusesFeaturesExtension)8243 TEST_F(FeaturesTest, ReusesFeaturesExtension) {
8244   BuildDescriptorMessagesInTestPool();
8245   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8246   const FileDescriptor* file1 = BuildFile(R"pb(
8247     name: "foo.proto"
8248     syntax: "editions"
8249     edition: EDITION_2023
8250     options {
8251       features {
8252         [pb.TestMessage.test_message] { file_feature: VALUE6 }
8253         [pb.TestMessage.Nested.test_nested] { file_feature: VALUE5 }
8254         [pb.test] { file_feature: VALUE7 }
8255       }
8256     }
8257   )pb");
8258   const FileDescriptor* file2 = BuildFile(R"pb(
8259     name: "bar.proto"
8260     syntax: "editions"
8261     edition: EDITION_2023
8262     options {
8263       features {
8264         [pb.test] { file_feature: VALUE7 }
8265         [pb.TestMessage.test_message] { file_feature: VALUE6 }
8266         [pb.TestMessage.Nested.test_nested] { file_feature: VALUE5 }
8267       }
8268     }
8269   )pb");
8270   EXPECT_EQ(&GetFeatures(file1), &GetFeatures(file2));
8271 }
8272 
TEST_F(FeaturesTest,RestoresLabelRoundTrip)8273 TEST_F(FeaturesTest, RestoresLabelRoundTrip) {
8274   BuildDescriptorMessagesInTestPool();
8275   const FileDescriptor* file = BuildFile(R"pb(
8276     name: "foo.proto"
8277     syntax: "editions"
8278     edition: EDITION_2023
8279     message_type {
8280       name: "Foo"
8281       field {
8282         name: "bar"
8283         number: 1
8284         label: LABEL_OPTIONAL
8285         type: TYPE_STRING
8286         options { features { field_presence: LEGACY_REQUIRED } }
8287       }
8288     }
8289   )pb");
8290   const FieldDescriptor* field = file->message_type(0)->field(0);
8291   ASSERT_EQ(field->label(), FieldDescriptor::LABEL_REQUIRED);
8292   ASSERT_TRUE(field->is_required());
8293 
8294   FileDescriptorProto proto;
8295   file->CopyTo(&proto);
8296   const FieldDescriptorProto& field_proto = proto.message_type(0).field(0);
8297   EXPECT_EQ(field_proto.label(), FieldDescriptorProto::LABEL_OPTIONAL);
8298   EXPECT_THAT(
8299       field_proto.options(),
8300       EqualsProto(R"pb(features { field_presence: LEGACY_REQUIRED })pb"));
8301 }
8302 
TEST_F(FeaturesTest,RestoresGroupRoundTrip)8303 TEST_F(FeaturesTest, RestoresGroupRoundTrip) {
8304   BuildDescriptorMessagesInTestPool();
8305   const FileDescriptor* file = BuildFile(R"pb(
8306     name: "foo.proto"
8307     syntax: "editions"
8308     edition: EDITION_2023
8309     message_type {
8310       name: "Foo"
8311       nested_type {
8312         name: "FooGroup"
8313         field { name: "bar" number: 1 label: LABEL_OPTIONAL type: TYPE_STRING }
8314       }
8315       field {
8316         name: "baz"
8317         number: 1
8318         label: LABEL_OPTIONAL
8319         type: TYPE_MESSAGE
8320         type_name: ".Foo.FooGroup"
8321         options { features { message_encoding: DELIMITED } }
8322       }
8323     }
8324   )pb");
8325   const FieldDescriptor* field = file->message_type(0)->field(0);
8326   ASSERT_EQ(field->type(), FieldDescriptor::TYPE_GROUP);
8327   ASSERT_NE(field->message_type(), nullptr);
8328 
8329   FileDescriptorProto proto;
8330   file->CopyTo(&proto);
8331   const FieldDescriptorProto& field_proto = proto.message_type(0).field(0);
8332   EXPECT_EQ(field_proto.type(), FieldDescriptorProto::TYPE_MESSAGE);
8333   EXPECT_THAT(field_proto.options(),
8334               EqualsProto(R"pb(features { message_encoding: DELIMITED })pb"));
8335 }
8336 
TEST_F(FeaturesTest,OnlyMessagesInheritGroupEncoding)8337 TEST_F(FeaturesTest, OnlyMessagesInheritGroupEncoding) {
8338   BuildDescriptorMessagesInTestPool();
8339   const FileDescriptor* file = BuildFile(R"pb(
8340     name: "foo.proto"
8341     syntax: "editions"
8342     edition: EDITION_2023
8343     options { features { message_encoding: DELIMITED } }
8344     message_type {
8345       name: "Foo"
8346       nested_type {
8347         name: "FooGroup"
8348         field { name: "bar" number: 1 label: LABEL_OPTIONAL type: TYPE_STRING }
8349       }
8350       field {
8351         name: "baz"
8352         number: 1
8353         label: LABEL_OPTIONAL
8354         type: TYPE_MESSAGE
8355         type_name: ".Foo.FooGroup"
8356       }
8357       field { name: "str" number: 2 label: LABEL_OPTIONAL type: TYPE_STRING }
8358     }
8359   )pb");
8360   const FieldDescriptor* group_field = file->message_type(0)->field(0);
8361   const FieldDescriptor* string_field = file->message_type(0)->field(1);
8362   EXPECT_EQ(group_field->type(), FieldDescriptor::TYPE_GROUP);
8363   EXPECT_EQ(string_field->type(), FieldDescriptor::TYPE_STRING);
8364   EXPECT_NE(group_field->message_type(), nullptr);
8365   EXPECT_EQ(string_field->message_type(), nullptr);
8366 }
8367 
TEST_F(FeaturesTest,NoOptions)8368 TEST_F(FeaturesTest, NoOptions) {
8369   BuildDescriptorMessagesInTestPool();
8370   const FileDescriptor* file =
8371       BuildFile(R"pb(
8372         name: "foo.proto" syntax: "editions" edition: EDITION_2023
8373       )pb");
8374   EXPECT_EQ(&file->options(), &FileOptions::default_instance());
8375   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
8376                 field_presence: EXPLICIT
8377                 enum_type: OPEN
8378                 repeated_field_encoding: PACKED
8379                 utf8_validation: VERIFY
8380                 message_encoding: LENGTH_PREFIXED
8381                 json_format: ALLOW
8382                 [pb.cpp] {
8383                   legacy_closed_enum: false
8384                   string_type: STRING
8385                   enum_name_uses_string_view: false
8386                 })pb"));
8387 }
8388 
TEST_F(FeaturesTest,InvalidEdition)8389 TEST_F(FeaturesTest, InvalidEdition) {
8390   BuildDescriptorMessagesInTestPool();
8391   BuildFileWithErrors(
8392       R"pb(
8393         name: "foo.proto" syntax: "editions" edition: EDITION_1_TEST_ONLY
8394       )pb",
8395       "foo.proto: foo.proto: EDITIONS: Edition 1_TEST_ONLY is earlier than the "
8396       "minimum supported edition PROTO2\n");
8397 }
8398 
8399 TEST_F(FeaturesTest, FileFeatures) {
8400   BuildDescriptorMessagesInTestPool();
8401   const FileDescriptor* file = BuildFile(R"pb(
8402     name: "foo.proto"
8403     syntax: "editions"
8404     edition: EDITION_2023
8405     options { features { field_presence: IMPLICIT } }
8406   )pb");
8407   EXPECT_THAT(file->options(), EqualsProto(""));
8408   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
8409                 field_presence: IMPLICIT
8410                 enum_type: OPEN
8411                 repeated_field_encoding: PACKED
8412                 utf8_validation: VERIFY
8413                 message_encoding: LENGTH_PREFIXED
8414                 json_format: ALLOW
8415                 [pb.cpp] {
8416                   legacy_closed_enum: false
8417                   string_type: STRING
8418                   enum_name_uses_string_view: false
8419                 })pb"));
8420 }
8421 
TEST_F(FeaturesTest,FileFeaturesExtension)8422 TEST_F(FeaturesTest, FileFeaturesExtension) {
8423   BuildDescriptorMessagesInTestPool();
8424   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8425   const FileDescriptor* file = BuildFile(R"pb(
8426     name: "foo.proto"
8427     syntax: "editions"
8428     edition: EDITION_99998_TEST_ONLY
8429     dependency: "google/protobuf/unittest_features.proto"
8430     options { features { field_presence: IMPLICIT } }
8431   )pb");
8432   EXPECT_THAT(file->options(), EqualsProto(""));
8433   EXPECT_EQ(GetFeatures(file).field_presence(), FeatureSet::IMPLICIT);
8434   EXPECT_EQ(GetFeatures(file).enum_type(), FeatureSet::OPEN);
8435   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).file_feature(),
8436             pb::VALUE5);
8437   EXPECT_EQ(GetFeatures(file)
8438                 .GetExtension(pb::TestMessage::test_message)
8439                 .file_feature(),
8440             pb::VALUE5);
8441   EXPECT_EQ(GetFeatures(file)
8442                 .GetExtension(pb::TestMessage::Nested::test_nested)
8443                 .file_feature(),
8444             pb::VALUE5);
8445 }
8446 
TEST_F(FeaturesTest,FileFeaturesExtensionOverride)8447 TEST_F(FeaturesTest, FileFeaturesExtensionOverride) {
8448   BuildDescriptorMessagesInTestPool();
8449   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8450   const FileDescriptor* file = BuildFile(R"pb(
8451     name: "foo.proto"
8452     syntax: "editions"
8453     edition: EDITION_99998_TEST_ONLY
8454     dependency: "google/protobuf/unittest_features.proto"
8455     options {
8456       features {
8457         field_presence: IMPLICIT
8458         [pb.test] { file_feature: VALUE7 }
8459         [pb.TestMessage.test_message] { file_feature: VALUE6 }
8460         [pb.TestMessage.Nested.test_nested] { file_feature: VALUE5 }
8461       }
8462     }
8463   )pb");
8464   EXPECT_THAT(file->options(), EqualsProto(""));
8465   EXPECT_EQ(GetFeatures(file).field_presence(), FeatureSet::IMPLICIT);
8466   EXPECT_EQ(GetFeatures(file).enum_type(), FeatureSet::OPEN);
8467   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).file_feature(),
8468             pb::VALUE7);
8469   EXPECT_EQ(GetFeatures(file)
8470                 .GetExtension(pb::TestMessage::test_message)
8471                 .file_feature(),
8472             pb::VALUE6);
8473   EXPECT_EQ(GetFeatures(file)
8474                 .GetExtension(pb::TestMessage::Nested::test_nested)
8475                 .file_feature(),
8476             pb::VALUE5);
8477 }
8478 
TEST_F(FeaturesTest,MessageFeaturesDefault)8479 TEST_F(FeaturesTest, MessageFeaturesDefault) {
8480   BuildDescriptorMessagesInTestPool();
8481   const FileDescriptor* file = BuildFile(R"pb(
8482     name: "foo.proto"
8483     syntax: "editions"
8484     edition: EDITION_2023
8485     message_type { name: "Foo" }
8486   )pb");
8487   const Descriptor* message = file->message_type(0);
8488   EXPECT_THAT(message->options(), EqualsProto(""));
8489   EXPECT_THAT(GetCoreFeatures(message), EqualsProto(R"pb(
8490                 field_presence: EXPLICIT
8491                 enum_type: OPEN
8492                 repeated_field_encoding: PACKED
8493                 utf8_validation: VERIFY
8494                 message_encoding: LENGTH_PREFIXED
8495                 json_format: ALLOW
8496                 [pb.cpp] {
8497                   legacy_closed_enum: false
8498                   string_type: STRING
8499                   enum_name_uses_string_view: false
8500                 })pb"));
8501 }
8502 
TEST_F(FeaturesTest,MessageFeaturesInherit)8503 TEST_F(FeaturesTest, MessageFeaturesInherit) {
8504   BuildDescriptorMessagesInTestPool();
8505   const FileDescriptor* file = BuildFile(R"pb(
8506     name: "foo.proto"
8507     syntax: "editions"
8508     edition: EDITION_2023
8509     options { features { field_presence: IMPLICIT } }
8510     message_type { name: "Foo" }
8511   )pb");
8512   const Descriptor* message = file->message_type(0);
8513   EXPECT_THAT(message->options(), EqualsProto(""));
8514   EXPECT_EQ(GetFeatures(message).field_presence(), FeatureSet::IMPLICIT);
8515 }
8516 
TEST_F(FeaturesTest,MessageFeaturesOverride)8517 TEST_F(FeaturesTest, MessageFeaturesOverride) {
8518   BuildDescriptorMessagesInTestPool();
8519   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8520   const FileDescriptor* file = BuildFile(R"pb(
8521     name: "foo.proto"
8522     syntax: "editions"
8523     edition: EDITION_2023
8524     dependency: "google/protobuf/unittest_features.proto"
8525     options {
8526       features {
8527         [pb.test] { multiple_feature: VALUE2 }
8528       }
8529     }
8530     message_type {
8531       name: "Foo"
8532       options {
8533         features {
8534           [pb.test] { multiple_feature: VALUE9 }
8535         }
8536       }
8537     }
8538   )pb");
8539   const Descriptor* message = file->message_type(0);
8540   EXPECT_THAT(message->options(), EqualsProto(""));
8541   EXPECT_EQ(GetFeatures(message).GetExtension(pb::test).multiple_feature(),
8542             pb::VALUE9);
8543 }
8544 
TEST_F(FeaturesTest,NestedMessageFeaturesOverride)8545 TEST_F(FeaturesTest, NestedMessageFeaturesOverride) {
8546   BuildDescriptorMessagesInTestPool();
8547   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8548   const FileDescriptor* file = BuildFile(R"pb(
8549     name: "foo.proto"
8550     syntax: "editions"
8551     edition: EDITION_2023
8552     dependency: "google/protobuf/unittest_features.proto"
8553     options {
8554       features {
8555         [pb.test] { multiple_feature: VALUE2 file_feature: VALUE7 }
8556       }
8557     }
8558     message_type {
8559       name: "Foo"
8560       options {
8561         features {
8562           [pb.test] { multiple_feature: VALUE10 message_feature: VALUE3 }
8563         }
8564       }
8565       nested_type {
8566         name: "Bar"
8567         options {
8568           features {
8569             [pb.test] { multiple_feature: VALUE5 }
8570           }
8571         }
8572       }
8573     }
8574   )pb");
8575   const Descriptor* message = file->message_type(0)->nested_type(0);
8576   EXPECT_THAT(message->options(), EqualsProto(""));
8577   EXPECT_EQ(GetFeatures(message).GetExtension(pb::test).field_feature(),
8578             pb::VALUE1);
8579   EXPECT_EQ(GetFeatures(message).GetExtension(pb::test).multiple_feature(),
8580             pb::VALUE5);
8581   EXPECT_EQ(GetFeatures(message).GetExtension(pb::test).file_feature(),
8582             pb::VALUE7);
8583   EXPECT_EQ(GetFeatures(message).GetExtension(pb::test).message_feature(),
8584             pb::VALUE3);
8585 }
8586 
TEST_F(FeaturesTest,FieldFeaturesDefault)8587 TEST_F(FeaturesTest, FieldFeaturesDefault) {
8588   BuildDescriptorMessagesInTestPool();
8589   const FileDescriptor* file = BuildFile(R"pb(
8590     name: "foo.proto"
8591     syntax: "editions"
8592     edition: EDITION_2023
8593     message_type {
8594       name: "Foo"
8595       field { name: "bar" number: 1 label: LABEL_REPEATED type: TYPE_INT64 }
8596     }
8597   )pb");
8598   const FieldDescriptor* field = file->message_type(0)->field(0);
8599   EXPECT_THAT(field->options(), EqualsProto(""));
8600   EXPECT_THAT(GetCoreFeatures(field), EqualsProto(R"pb(
8601                 field_presence: EXPLICIT
8602                 enum_type: OPEN
8603                 repeated_field_encoding: PACKED
8604                 utf8_validation: VERIFY
8605                 message_encoding: LENGTH_PREFIXED
8606                 json_format: ALLOW
8607                 [pb.cpp] {
8608                   legacy_closed_enum: false
8609                   string_type: STRING
8610                   enum_name_uses_string_view: false
8611                 })pb"));
8612 }
8613 
TEST_F(FeaturesTest,FieldFeaturesInherit)8614 TEST_F(FeaturesTest, FieldFeaturesInherit) {
8615   BuildDescriptorMessagesInTestPool();
8616   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8617   const FileDescriptor* file = BuildFile(R"pb(
8618     name: "foo.proto"
8619     syntax: "editions"
8620     edition: EDITION_2023
8621     dependency: "google/protobuf/unittest_features.proto"
8622     options {
8623       features {
8624         field_presence: IMPLICIT
8625         [pb.test] { multiple_feature: VALUE1 }
8626       }
8627     }
8628     message_type {
8629       name: "Foo"
8630       options {
8631         features {
8632           [pb.test] { multiple_feature: VALUE9 }
8633         }
8634       }
8635       field { name: "bar" number: 1 label: LABEL_REPEATED type: TYPE_INT64 }
8636     }
8637   )pb");
8638   const FieldDescriptor* field = file->message_type(0)->field(0);
8639   EXPECT_THAT(field->options(), EqualsProto(""));
8640   EXPECT_EQ(GetFeatures(field).field_presence(), FeatureSet::IMPLICIT);
8641   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
8642             pb::VALUE9);
8643 }
8644 
TEST_F(FeaturesTest,FieldFeaturesOverride)8645 TEST_F(FeaturesTest, FieldFeaturesOverride) {
8646   BuildDescriptorMessagesInTestPool();
8647   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8648   const FileDescriptor* file = BuildFile(R"pb(
8649     name: "foo.proto"
8650     syntax: "editions"
8651     edition: EDITION_2023
8652     dependency: "google/protobuf/unittest_features.proto"
8653     options {
8654       features {
8655         enum_type: CLOSED
8656         field_presence: IMPLICIT
8657         [pb.test] { multiple_feature: VALUE2 }
8658       }
8659     }
8660     message_type {
8661       name: "Foo"
8662       options {
8663         features {
8664           [pb.test] { multiple_feature: VALUE3 }
8665         }
8666       }
8667       field {
8668         name: "bar"
8669         number: 1
8670         label: LABEL_OPTIONAL
8671         type: TYPE_STRING
8672         options {
8673           features {
8674             field_presence: EXPLICIT
8675             [pb.test] { multiple_feature: VALUE9 }
8676           }
8677         }
8678       }
8679     }
8680   )pb");
8681   const FieldDescriptor* field = file->message_type(0)->field(0);
8682   EXPECT_THAT(field->options(), EqualsProto(""));
8683   EXPECT_EQ(GetFeatures(field).field_presence(), FeatureSet::EXPLICIT);
8684   EXPECT_EQ(GetFeatures(field).enum_type(), FeatureSet::CLOSED);
8685   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
8686             pb::VALUE9);
8687 }
8688 
TEST_F(FeaturesTest,OneofFieldFeaturesInherit)8689 TEST_F(FeaturesTest, OneofFieldFeaturesInherit) {
8690   BuildDescriptorMessagesInTestPool();
8691   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8692   const FileDescriptor* file = BuildFile(R"pb(
8693     name: "foo.proto"
8694     syntax: "editions"
8695     edition: EDITION_2023
8696     dependency: "google/protobuf/unittest_features.proto"
8697     options {
8698       features {
8699         field_presence: IMPLICIT
8700         [pb.test] { multiple_feature: VALUE1 }
8701       }
8702     }
8703     message_type {
8704       name: "Foo"
8705       options {
8706         features {
8707           [pb.test] { multiple_feature: VALUE6 }
8708         }
8709       }
8710       field {
8711         name: "bar"
8712         number: 1
8713         label: LABEL_OPTIONAL
8714         type: TYPE_INT64
8715         oneof_index: 0
8716       }
8717       oneof_decl {
8718         name: "foo_oneof"
8719         options {
8720           features {
8721             [pb.test] { multiple_feature: VALUE9 }
8722           }
8723         }
8724       }
8725     }
8726   )pb");
8727   const FieldDescriptor* field = file->message_type(0)->field(0);
8728   EXPECT_THAT(field->options(), EqualsProto(""));
8729   EXPECT_EQ(GetFeatures(field).field_presence(), FeatureSet::IMPLICIT);
8730   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
8731             pb::VALUE9);
8732 }
8733 
TEST_F(FeaturesTest,OneofFieldFeaturesOverride)8734 TEST_F(FeaturesTest, OneofFieldFeaturesOverride) {
8735   BuildDescriptorMessagesInTestPool();
8736   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8737   const FileDescriptor* file = BuildFile(R"pb(
8738     name: "foo.proto"
8739     syntax: "editions"
8740     edition: EDITION_2023
8741     dependency: "google/protobuf/unittest_features.proto"
8742     options {
8743       features {
8744         [pb.test] { multiple_feature: VALUE2 file_feature: VALUE4 }
8745       }
8746     }
8747     message_type {
8748       name: "Foo"
8749       options {
8750         features {
8751           [pb.test] { multiple_feature: VALUE3 message_feature: VALUE3 }
8752         }
8753       }
8754       field {
8755         name: "bar"
8756         number: 1
8757         label: LABEL_OPTIONAL
8758         type: TYPE_STRING
8759         options {
8760           features {
8761             [pb.test] { multiple_feature: VALUE9 }
8762           }
8763         }
8764         oneof_index: 0
8765       }
8766       oneof_decl {
8767         name: "foo_oneof"
8768         options {
8769           features {
8770             [pb.test] { multiple_feature: VALUE6 oneof_feature: VALUE6 }
8771           }
8772         }
8773       }
8774     }
8775   )pb");
8776   const FieldDescriptor* field = file->message_type(0)->field(0);
8777   EXPECT_THAT(field->options(), EqualsProto(""));
8778   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
8779             pb::VALUE9);
8780   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).oneof_feature(),
8781             pb::VALUE6);
8782   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).message_feature(),
8783             pb::VALUE3);
8784   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).file_feature(),
8785             pb::VALUE4);
8786 }
8787 
TEST_F(FeaturesTest,MapFieldFeaturesOverride)8788 TEST_F(FeaturesTest, MapFieldFeaturesOverride) {
8789   BuildDescriptorMessagesInTestPool();
8790   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8791   const FileDescriptor* file = ParseAndBuildFile("foo.proto", R"schema(
8792     edition = "2023";
8793 
8794     import "google/protobuf/unittest_features.proto";
8795 
8796     option features.(pb.test).file_feature = VALUE7;
8797     option features.(pb.test).multiple_feature = VALUE1;
8798 
8799     message Foo {
8800       option features.(pb.test).message_feature = VALUE8;
8801       option features.(pb.test).multiple_feature = VALUE2;
8802 
8803       map<string, string> map_field = 1 [
8804         features.(pb.test).field_feature = VALUE10,
8805         features.(pb.test).multiple_feature = VALUE3
8806       ];
8807     }
8808   )schema");
8809   ASSERT_THAT(file, NotNull());
8810 
8811   const FieldDescriptor* map_field = file->message_type(0)->field(0);
8812   const FieldDescriptor* key = map_field->message_type()->field(0);
8813   const FieldDescriptor* value = map_field->message_type()->field(1);
8814 
__anon064ad7990302(const FieldDescriptor* desc) 8815   auto validate = [](const FieldDescriptor* desc) {
8816     EXPECT_EQ(GetFeatures(desc).GetExtension(pb::test).file_feature(),
8817               pb::VALUE7)
8818         << desc->DebugString();
8819     EXPECT_EQ(GetFeatures(desc).GetExtension(pb::test).message_feature(),
8820               pb::VALUE8)
8821         << desc->DebugString();
8822     EXPECT_EQ(GetFeatures(desc).GetExtension(pb::test).field_feature(),
8823               pb::VALUE10)
8824         << desc->DebugString();
8825     EXPECT_EQ(GetFeatures(desc).GetExtension(pb::test).multiple_feature(),
8826               pb::VALUE3)
8827         << desc->DebugString();
8828   };
8829 
8830   validate(map_field);
8831   validate(key);
8832   validate(value);
8833 }
8834 
8835 TEST_F(FeaturesTest, MapFieldFeaturesStringValidation) {
8836   BuildDescriptorMessagesInTestPool();
8837   const FileDescriptor* file = ParseAndBuildFile("foo.proto", R"schema(
8838     edition = "2023";
8839 
8840     message Foo {
8841       map<string, string> map_field = 1 [
8842         features.utf8_validation = NONE
8843       ];
8844       map<int32, string> map_field_value = 2 [
8845         features.utf8_validation = NONE
8846       ];
8847       map<string, int32> map_field_key = 3 [
8848         features.utf8_validation = NONE
8849       ];
8850     }
8851   )schema");
8852   ASSERT_THAT(file, NotNull());
8853 
__anon064ad7990402(const FieldDescriptor* field) 8854   auto validate_map_field = [](const FieldDescriptor* field) {
8855     const FieldDescriptor* key = field->message_type()->field(0);
8856     const FieldDescriptor* value = field->message_type()->field(1);
8857 
8858     EXPECT_FALSE(field->requires_utf8_validation()) << field->DebugString();
8859     EXPECT_FALSE(key->requires_utf8_validation()) << field->DebugString();
8860     EXPECT_FALSE(value->requires_utf8_validation()) << field->DebugString();
8861   };
8862 
8863   validate_map_field(file->message_type(0)->field(0));
8864   validate_map_field(file->message_type(0)->field(1));
8865   validate_map_field(file->message_type(0)->field(2));
8866 }
8867 
8868 TEST_F(FeaturesTest, MapFieldFeaturesImplicitPresence) {
8869   BuildDescriptorMessagesInTestPool();
8870   const FileDescriptor* editions = ParseAndBuildFile("editions.proto", R"schema(
8871     edition = "2023";
8872 
8873     option features.field_presence = IMPLICIT;
8874 
8875     message Foo {
8876       map<string, Foo> message_map = 1;
8877       map<string, string> string_map = 2;
8878     }
8879   )schema");
8880   ASSERT_THAT(editions, NotNull());
8881   const FileDescriptor* proto3 = ParseAndBuildFile("proto3.proto", R"schema(
8882     syntax = "proto3";
8883 
8884     message Bar {
8885       map<string, Bar> message_map = 1;
8886       map<string, string> string_map = 2;
8887     }
8888   )schema");
8889   ASSERT_THAT(proto3, NotNull());
8890 
__anon064ad7990502(const FileDescriptor* file) 8891   auto validate_maps = [](const FileDescriptor* file) {
8892     const FieldDescriptor* message_map = file->message_type(0)->field(0);
8893     EXPECT_FALSE(message_map->has_presence());
8894     EXPECT_FALSE(message_map->message_type()->field(0)->has_presence());
8895     EXPECT_TRUE(message_map->message_type()->field(1)->has_presence());
8896 
8897     const FieldDescriptor* string_map = file->message_type(0)->field(1);
8898     EXPECT_FALSE(string_map->has_presence());
8899     EXPECT_FALSE(string_map->message_type()->field(0)->has_presence());
8900     EXPECT_FALSE(string_map->message_type()->field(1)->has_presence());
8901   };
8902   validate_maps(editions);
8903   validate_maps(proto3);
8904 }
8905 
8906 TEST_F(FeaturesTest, MapFieldFeaturesExplicitPresence) {
8907   BuildDescriptorMessagesInTestPool();
8908   const FileDescriptor* editions = ParseAndBuildFile("editions.proto", R"schema(
8909     edition = "2023";
8910 
8911     message Foo {
8912       map<string, Foo> message_map = 1;
8913       map<string, string> string_map = 2;
8914     }
8915   )schema");
8916   ASSERT_THAT(editions, NotNull());
8917   const FileDescriptor* proto2 = ParseAndBuildFile("google.protobuf.proto", R"schema(
8918     syntax = "proto2";
8919 
8920     message Bar {
8921       map<string, Bar> message_map = 1;
8922       map<string, string> string_map = 2;
8923     }
8924   )schema");
8925   ASSERT_THAT(proto2, NotNull());
8926 
__anon064ad7990602(const FileDescriptor* file) 8927   auto validate_maps = [](const FileDescriptor* file) {
8928     const FieldDescriptor* message_map = file->message_type(0)->field(0);
8929     EXPECT_FALSE(message_map->has_presence());
8930     EXPECT_TRUE(message_map->message_type()->field(0)->has_presence());
8931     EXPECT_TRUE(message_map->message_type()->field(1)->has_presence());
8932 
8933     const FieldDescriptor* string_map = file->message_type(0)->field(1);
8934     EXPECT_FALSE(string_map->has_presence());
8935     EXPECT_TRUE(string_map->message_type()->field(0)->has_presence());
8936     EXPECT_TRUE(string_map->message_type()->field(1)->has_presence());
8937   };
8938   validate_maps(editions);
8939   validate_maps(proto2);
8940 }
8941 
8942 TEST_F(FeaturesTest, MapFieldFeaturesInheritedMessageEncoding) {
8943   BuildDescriptorMessagesInTestPool();
8944   const FileDescriptor* file = ParseAndBuildFile("foo.proto", R"schema(
8945     edition = "2023";
8946 
8947     option features.message_encoding = DELIMITED;
8948 
8949     message Foo {
8950       map<int32, Foo> message_map = 1;
8951       map<string, string> string_map = 2;
8952     }
8953   )schema");
8954   ASSERT_THAT(file, NotNull());
8955 
8956   const FieldDescriptor* message_map = file->message_type(0)->field(0);
8957   EXPECT_EQ(message_map->type(), FieldDescriptor::TYPE_MESSAGE);
8958   EXPECT_EQ(message_map->message_type()->field(0)->type(),
8959             FieldDescriptor::TYPE_INT32);
8960   EXPECT_EQ(message_map->message_type()->field(1)->type(),
8961             FieldDescriptor::TYPE_MESSAGE);
8962 
8963   const FieldDescriptor* string_map = file->message_type(0)->field(1);
8964   EXPECT_EQ(string_map->type(), FieldDescriptor::TYPE_MESSAGE);
8965   EXPECT_EQ(string_map->message_type()->field(0)->type(),
8966             FieldDescriptor::TYPE_STRING);
8967   EXPECT_EQ(string_map->message_type()->field(1)->type(),
8968             FieldDescriptor::TYPE_STRING);
8969 }
8970 
TEST_F(FeaturesTest,RootExtensionFeaturesOverride)8971 TEST_F(FeaturesTest, RootExtensionFeaturesOverride) {
8972   BuildDescriptorMessagesInTestPool();
8973   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
8974   const FileDescriptor* file = BuildFile(R"pb(
8975     name: "foo.proto"
8976     syntax: "editions"
8977     edition: EDITION_2023
8978     dependency: "google/protobuf/unittest_features.proto"
8979     options {
8980       features {
8981         enum_type: CLOSED
8982         field_presence: IMPLICIT
8983         [pb.test] { multiple_feature: VALUE2 }
8984       }
8985     }
8986     extension {
8987       name: "bar"
8988       number: 1
8989       label: LABEL_OPTIONAL
8990       type: TYPE_STRING
8991       options {
8992         features {
8993           enum_type: OPEN
8994           [pb.test] { multiple_feature: VALUE9 }
8995         }
8996       }
8997       extendee: "Foo"
8998     }
8999     message_type {
9000       name: "Foo"
9001       extension_range { start: 1 end: 2 }
9002     }
9003   )pb");
9004   const FieldDescriptor* field = file->extension(0);
9005   EXPECT_THAT(field->options(), EqualsProto(""));
9006   EXPECT_EQ(GetFeatures(field).field_presence(), FeatureSet::IMPLICIT);
9007   EXPECT_EQ(GetFeatures(field).enum_type(), FeatureSet::OPEN);
9008   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
9009             pb::VALUE9);
9010 }
9011 
TEST_F(FeaturesTest,MessageExtensionFeaturesOverride)9012 TEST_F(FeaturesTest, MessageExtensionFeaturesOverride) {
9013   BuildDescriptorMessagesInTestPool();
9014   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9015   const FileDescriptor* file = BuildFile(R"pb(
9016     name: "foo.proto"
9017     syntax: "editions"
9018     edition: EDITION_2023
9019     dependency: "google/protobuf/unittest_features.proto"
9020     options {
9021       features {
9022         enum_type: CLOSED
9023         field_presence: IMPLICIT
9024         [pb.test] { multiple_feature: VALUE2 }
9025       }
9026     }
9027     message_type {
9028       name: "Foo"
9029       options {
9030         features {
9031           [pb.test] { multiple_feature: VALUE3 }
9032         }
9033       }
9034       extension {
9035         name: "bar"
9036         number: 1
9037         label: LABEL_OPTIONAL
9038         type: TYPE_STRING
9039         options { features { enum_type: OPEN } }
9040         extendee: "Foo2"
9041       }
9042     }
9043     message_type {
9044       name: "Foo2"
9045       extension_range { start: 1 end: 2 }
9046       options {
9047         features {
9048           [pb.test] { multiple_feature: VALUE7 }
9049         }
9050       }
9051     }
9052   )pb");
9053   const FieldDescriptor* field = file->message_type(0)->extension(0);
9054   EXPECT_THAT(field->options(), EqualsProto(""));
9055   EXPECT_EQ(GetFeatures(field).field_presence(), FeatureSet::IMPLICIT);
9056   EXPECT_EQ(GetFeatures(field).enum_type(), FeatureSet::OPEN);
9057   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
9058             pb::VALUE3);
9059 }
9060 
TEST_F(FeaturesTest,EnumFeaturesDefault)9061 TEST_F(FeaturesTest, EnumFeaturesDefault) {
9062   BuildDescriptorMessagesInTestPool();
9063   const FileDescriptor* file = BuildFile(R"pb(
9064     name: "foo.proto"
9065     syntax: "editions"
9066     edition: EDITION_2023
9067     enum_type {
9068       name: "Foo"
9069       value { name: "BAR" number: 0 }
9070     }
9071   )pb");
9072   const EnumDescriptor* enm = file->enum_type(0);
9073   EXPECT_THAT(enm->options(), EqualsProto(""));
9074   EXPECT_THAT(GetCoreFeatures(enm), EqualsProto(R"pb(
9075                 field_presence: EXPLICIT
9076                 enum_type: OPEN
9077                 repeated_field_encoding: PACKED
9078                 utf8_validation: VERIFY
9079                 message_encoding: LENGTH_PREFIXED
9080                 json_format: ALLOW
9081                 [pb.cpp] {
9082                   legacy_closed_enum: false
9083                   string_type: STRING
9084                   enum_name_uses_string_view: false
9085                 })pb"));
9086 }
9087 
TEST_F(FeaturesTest,EnumFeaturesInherit)9088 TEST_F(FeaturesTest, EnumFeaturesInherit) {
9089   BuildDescriptorMessagesInTestPool();
9090   const FileDescriptor* file = BuildFile(R"pb(
9091     name: "foo.proto"
9092     syntax: "editions"
9093     edition: EDITION_2023
9094     options { features { enum_type: CLOSED } }
9095     enum_type {
9096       name: "Foo"
9097       value { name: "BAR" number: 0 }
9098     }
9099   )pb");
9100   const EnumDescriptor* enm = file->enum_type(0);
9101   EXPECT_THAT(enm->options(), EqualsProto(""));
9102   EXPECT_EQ(GetFeatures(enm).enum_type(), FeatureSet::CLOSED);
9103 }
9104 
TEST_F(FeaturesTest,EnumFeaturesOverride)9105 TEST_F(FeaturesTest, EnumFeaturesOverride) {
9106   BuildDescriptorMessagesInTestPool();
9107   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9108   const FileDescriptor* file = BuildFile(R"pb(
9109     name: "foo.proto"
9110     syntax: "editions"
9111     edition: EDITION_2023
9112     dependency: "google/protobuf/unittest_features.proto"
9113     options {
9114       features {
9115         [pb.test] { multiple_feature: VALUE2 }
9116       }
9117     }
9118     enum_type {
9119       name: "Foo"
9120       options {
9121         features {
9122           [pb.test] { multiple_feature: VALUE9 }
9123         }
9124       }
9125       value { name: "BAR" number: 0 }
9126     }
9127   )pb");
9128   const EnumDescriptor* enm = file->enum_type(0);
9129   EXPECT_THAT(enm->options(), EqualsProto(""));
9130   EXPECT_EQ(GetFeatures(enm).GetExtension(pb::test).multiple_feature(),
9131             pb::VALUE9);
9132 }
9133 
TEST_F(FeaturesTest,NestedEnumFeatures)9134 TEST_F(FeaturesTest, NestedEnumFeatures) {
9135   BuildDescriptorMessagesInTestPool();
9136   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9137   const FileDescriptor* file = BuildFile(R"pb(
9138     name: "foo.proto"
9139     syntax: "editions"
9140     edition: EDITION_2023
9141     dependency: "google/protobuf/unittest_features.proto"
9142     options {
9143       features {
9144         [pb.test] { multiple_feature: VALUE2 file_feature: VALUE7 }
9145       }
9146     }
9147     message_type {
9148       name: "Foo"
9149       options {
9150         features {
9151           [pb.test] { multiple_feature: VALUE10 message_feature: VALUE3 }
9152         }
9153       }
9154       enum_type {
9155         name: "Bar"
9156         options {
9157           features {
9158             [pb.test] { multiple_feature: VALUE5 }
9159           }
9160         }
9161         value { name: "BAR" number: 0 }
9162       }
9163     }
9164   )pb");
9165   const EnumDescriptor* enm = file->message_type(0)->enum_type(0);
9166   EXPECT_THAT(enm->options(), EqualsProto(""));
9167   EXPECT_EQ(GetFeatures(enm).GetExtension(pb::test).field_feature(),
9168             pb::VALUE1);
9169   EXPECT_EQ(GetFeatures(enm).GetExtension(pb::test).multiple_feature(),
9170             pb::VALUE5);
9171   EXPECT_EQ(GetFeatures(enm).GetExtension(pb::test).file_feature(), pb::VALUE7);
9172   EXPECT_EQ(GetFeatures(enm).GetExtension(pb::test).message_feature(),
9173             pb::VALUE3);
9174 }
9175 
TEST_F(FeaturesTest,EnumValueFeaturesDefault)9176 TEST_F(FeaturesTest, EnumValueFeaturesDefault) {
9177   BuildDescriptorMessagesInTestPool();
9178   const FileDescriptor* file = BuildFile(R"pb(
9179     name: "foo.proto"
9180     syntax: "editions"
9181     edition: EDITION_2023
9182     enum_type {
9183       name: "Foo"
9184       value { name: "BAR" number: 0 }
9185     }
9186   )pb");
9187   const EnumValueDescriptor* value = file->enum_type(0)->value(0);
9188   EXPECT_THAT(value->options(), EqualsProto(""));
9189   EXPECT_THAT(GetCoreFeatures(value), EqualsProto(R"pb(
9190                 field_presence: EXPLICIT
9191                 enum_type: OPEN
9192                 repeated_field_encoding: PACKED
9193                 utf8_validation: VERIFY
9194                 message_encoding: LENGTH_PREFIXED
9195                 json_format: ALLOW
9196                 [pb.cpp] {
9197                   legacy_closed_enum: false
9198                   string_type: STRING
9199                   enum_name_uses_string_view: false
9200                 })pb"));
9201 }
9202 
TEST_F(FeaturesTest,EnumValueFeaturesInherit)9203 TEST_F(FeaturesTest, EnumValueFeaturesInherit) {
9204   BuildDescriptorMessagesInTestPool();
9205   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9206   const FileDescriptor* file = BuildFile(R"pb(
9207     name: "foo.proto"
9208     syntax: "editions"
9209     edition: EDITION_2023
9210     dependency: "google/protobuf/unittest_features.proto"
9211     options { features { enum_type: CLOSED } }
9212     enum_type {
9213       name: "Foo"
9214       options {
9215         features {
9216           [pb.test] { enum_feature: VALUE9 }
9217         }
9218       }
9219       value { name: "BAR" number: 0 }
9220     }
9221   )pb");
9222   const EnumValueDescriptor* value = file->enum_type(0)->value(0);
9223   EXPECT_THAT(value->options(), EqualsProto(""));
9224   EXPECT_EQ(GetFeatures(value).enum_type(), FeatureSet::CLOSED);
9225   EXPECT_EQ(GetFeatures(value).GetExtension(pb::test).enum_feature(),
9226             pb::VALUE9);
9227 }
9228 
TEST_F(FeaturesTest,EnumValueFeaturesOverride)9229 TEST_F(FeaturesTest, EnumValueFeaturesOverride) {
9230   BuildDescriptorMessagesInTestPool();
9231   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9232   const FileDescriptor* file = BuildFile(R"pb(
9233     name: "foo.proto"
9234     syntax: "editions"
9235     edition: EDITION_2023
9236     dependency: "google/protobuf/unittest_features.proto"
9237     options {
9238       features {
9239         [pb.test] { multiple_feature: VALUE7 }
9240       }
9241     }
9242     enum_type {
9243       name: "Foo"
9244       options {
9245         features {
9246           [pb.test] { multiple_feature: VALUE8 }
9247         }
9248       }
9249       value {
9250         name: "BAR"
9251         number: 0
9252         options {
9253           features {
9254             [pb.test] { multiple_feature: VALUE9 enum_entry_feature: VALUE8 }
9255           }
9256         }
9257       }
9258     }
9259   )pb");
9260   const EnumValueDescriptor* value = file->enum_type(0)->value(0);
9261   EXPECT_THAT(value->options(), EqualsProto(""));
9262   EXPECT_EQ(GetFeatures(value).GetExtension(pb::test).multiple_feature(),
9263             pb::VALUE9);
9264   EXPECT_EQ(GetFeatures(value).GetExtension(pb::test).enum_entry_feature(),
9265             pb::VALUE8);
9266 }
9267 
TEST_F(FeaturesTest,OneofFeaturesDefault)9268 TEST_F(FeaturesTest, OneofFeaturesDefault) {
9269   BuildDescriptorMessagesInTestPool();
9270   const FileDescriptor* file = BuildFile(R"pb(
9271     name: "foo.proto"
9272     syntax: "editions"
9273     edition: EDITION_2023
9274     message_type {
9275       name: "Foo"
9276       field {
9277         name: "oneof_field"
9278         number: 1
9279         label: LABEL_OPTIONAL
9280         type: TYPE_INT64
9281         oneof_index: 0
9282       }
9283       oneof_decl { name: "foo_oneof" }
9284     }
9285   )pb");
9286   const OneofDescriptor* oneof = file->message_type(0)->oneof_decl(0);
9287   EXPECT_THAT(oneof->options(), EqualsProto(""));
9288   EXPECT_THAT(GetCoreFeatures(oneof), EqualsProto(R"pb(
9289                 field_presence: EXPLICIT
9290                 enum_type: OPEN
9291                 repeated_field_encoding: PACKED
9292                 utf8_validation: VERIFY
9293                 message_encoding: LENGTH_PREFIXED
9294                 json_format: ALLOW
9295                 [pb.cpp] {
9296                   legacy_closed_enum: false
9297                   string_type: STRING
9298                   enum_name_uses_string_view: false
9299                 })pb"));
9300 }
9301 
TEST_F(FeaturesTest,OneofFeaturesInherit)9302 TEST_F(FeaturesTest, OneofFeaturesInherit) {
9303   BuildDescriptorMessagesInTestPool();
9304   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9305   const FileDescriptor* file = BuildFile(R"pb(
9306     name: "foo.proto"
9307     syntax: "editions"
9308     edition: EDITION_2023
9309     dependency: "google/protobuf/unittest_features.proto"
9310     options { features { enum_type: CLOSED } }
9311     message_type {
9312       name: "Foo"
9313       field {
9314         name: "oneof_field"
9315         number: 1
9316         label: LABEL_OPTIONAL
9317         type: TYPE_INT64
9318         oneof_index: 0
9319       }
9320       oneof_decl { name: "foo_oneof" }
9321       options {
9322         features {
9323           [pb.test] { message_feature: VALUE9 }
9324         }
9325       }
9326     }
9327   )pb");
9328   const OneofDescriptor* oneof = file->message_type(0)->oneof_decl(0);
9329   EXPECT_THAT(oneof->options(), EqualsProto(""));
9330   EXPECT_EQ(GetFeatures(oneof).enum_type(), FeatureSet::CLOSED);
9331   EXPECT_EQ(GetFeatures(oneof).GetExtension(pb::test).message_feature(),
9332             pb::VALUE9);
9333 }
9334 
TEST_F(FeaturesTest,OneofFeaturesOverride)9335 TEST_F(FeaturesTest, OneofFeaturesOverride) {
9336   BuildDescriptorMessagesInTestPool();
9337   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9338   const FileDescriptor* file = BuildFile(R"pb(
9339     name: "foo.proto"
9340     syntax: "editions"
9341     edition: EDITION_2023
9342     dependency: "google/protobuf/unittest_features.proto"
9343     options {
9344       features {
9345         [pb.test] { multiple_feature: VALUE2 file_feature: VALUE4 }
9346       }
9347     }
9348     message_type {
9349       name: "Foo"
9350       field {
9351         name: "oneof_field"
9352         number: 1
9353         label: LABEL_OPTIONAL
9354         type: TYPE_INT64
9355         oneof_index: 0
9356       }
9357       oneof_decl {
9358         name: "foo_oneof"
9359         options {
9360           features {
9361             [pb.test] { multiple_feature: VALUE9 }
9362           }
9363         }
9364       }
9365       options {
9366         features {
9367           [pb.test] { multiple_feature: VALUE5 message_feature: VALUE5 }
9368         }
9369       }
9370     }
9371   )pb");
9372   const OneofDescriptor* oneof = file->message_type(0)->oneof_decl(0);
9373   EXPECT_THAT(oneof->options(), EqualsProto(""));
9374   EXPECT_EQ(GetFeatures(oneof).GetExtension(pb::test).multiple_feature(),
9375             pb::VALUE9);
9376   EXPECT_EQ(GetFeatures(oneof).GetExtension(pb::test).message_feature(),
9377             pb::VALUE5);
9378   EXPECT_EQ(GetFeatures(oneof).GetExtension(pb::test).file_feature(),
9379             pb::VALUE4);
9380 }
9381 
TEST_F(FeaturesTest,ExtensionRangeFeaturesDefault)9382 TEST_F(FeaturesTest, ExtensionRangeFeaturesDefault) {
9383   BuildDescriptorMessagesInTestPool();
9384   const FileDescriptor* file = BuildFile(R"pb(
9385     name: "foo.proto"
9386     syntax: "editions"
9387     edition: EDITION_2023
9388     message_type {
9389       name: "Foo"
9390       extension_range { start: 1 end: 100 }
9391     }
9392   )pb");
9393   const Descriptor::ExtensionRange* range =
9394       file->message_type(0)->extension_range(0);
9395   EXPECT_THAT(range->options(), EqualsProto(""));
9396   EXPECT_THAT(GetCoreFeatures(range), EqualsProto(R"pb(
9397                 field_presence: EXPLICIT
9398                 enum_type: OPEN
9399                 repeated_field_encoding: PACKED
9400                 utf8_validation: VERIFY
9401                 message_encoding: LENGTH_PREFIXED
9402                 json_format: ALLOW
9403                 [pb.cpp] {
9404                   legacy_closed_enum: false
9405                   string_type: STRING
9406                   enum_name_uses_string_view: false
9407                 })pb"));
9408 }
9409 
TEST_F(FeaturesTest,ExtensionRangeFeaturesInherit)9410 TEST_F(FeaturesTest, ExtensionRangeFeaturesInherit) {
9411   BuildDescriptorMessagesInTestPool();
9412   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9413   const FileDescriptor* file = BuildFile(R"pb(
9414     name: "foo.proto"
9415     syntax: "editions"
9416     edition: EDITION_2023
9417     dependency: "google/protobuf/unittest_features.proto"
9418     options { features { enum_type: CLOSED } }
9419     message_type {
9420       name: "Foo"
9421       options {
9422         features {
9423           [pb.test] { message_feature: VALUE9 }
9424         }
9425       }
9426       extension_range { start: 1 end: 100 }
9427     }
9428   )pb");
9429   const Descriptor::ExtensionRange* range =
9430       file->message_type(0)->extension_range(0);
9431   EXPECT_THAT(range->options(), EqualsProto(""));
9432   EXPECT_EQ(GetFeatures(range).enum_type(), FeatureSet::CLOSED);
9433   EXPECT_EQ(GetFeatures(range).GetExtension(pb::test).message_feature(),
9434             pb::VALUE9);
9435 }
9436 
TEST_F(FeaturesTest,ExtensionRangeFeaturesOverride)9437 TEST_F(FeaturesTest, ExtensionRangeFeaturesOverride) {
9438   BuildDescriptorMessagesInTestPool();
9439   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9440   const FileDescriptor* file = BuildFile(R"pb(
9441     name: "foo.proto"
9442     syntax: "editions"
9443     edition: EDITION_2023
9444     dependency: "google/protobuf/unittest_features.proto"
9445     options {
9446       features {
9447         [pb.test] { multiple_feature: VALUE2 file_feature: VALUE4 }
9448       }
9449     }
9450     message_type {
9451       name: "Foo"
9452       options {
9453         features {
9454           [pb.test] { multiple_feature: VALUE5 message_feature: VALUE5 }
9455         }
9456       }
9457       extension_range {
9458         start: 1
9459         end: 100
9460         options {
9461           features {
9462             [pb.test] { multiple_feature: VALUE9 }
9463           }
9464         }
9465       }
9466     }
9467   )pb");
9468   const Descriptor::ExtensionRange* range =
9469       file->message_type(0)->extension_range(0);
9470   EXPECT_THAT(range->options(), EqualsProto(""));
9471   EXPECT_EQ(GetFeatures(range).GetExtension(pb::test).multiple_feature(),
9472             pb::VALUE9);
9473   EXPECT_EQ(GetFeatures(range).GetExtension(pb::test).message_feature(),
9474             pb::VALUE5);
9475   EXPECT_EQ(GetFeatures(range).GetExtension(pb::test).file_feature(),
9476             pb::VALUE4);
9477 }
9478 
TEST_F(FeaturesTest,ServiceFeaturesDefault)9479 TEST_F(FeaturesTest, ServiceFeaturesDefault) {
9480   BuildDescriptorMessagesInTestPool();
9481   const FileDescriptor* file = BuildFile(R"pb(
9482     name: "foo.proto"
9483     syntax: "editions"
9484     edition: EDITION_2023
9485     service { name: "Foo" }
9486   )pb");
9487   const ServiceDescriptor* service = file->service(0);
9488   EXPECT_THAT(service->options(), EqualsProto(""));
9489   EXPECT_THAT(GetCoreFeatures(service), EqualsProto(R"pb(
9490                 field_presence: EXPLICIT
9491                 enum_type: OPEN
9492                 repeated_field_encoding: PACKED
9493                 utf8_validation: VERIFY
9494                 message_encoding: LENGTH_PREFIXED
9495                 json_format: ALLOW
9496                 [pb.cpp] {
9497                   legacy_closed_enum: false
9498                   string_type: STRING
9499                   enum_name_uses_string_view: false
9500                 })pb"));
9501 }
9502 
TEST_F(FeaturesTest,ServiceFeaturesInherit)9503 TEST_F(FeaturesTest, ServiceFeaturesInherit) {
9504   BuildDescriptorMessagesInTestPool();
9505   const FileDescriptor* file = BuildFile(R"pb(
9506     name: "foo.proto"
9507     syntax: "editions"
9508     edition: EDITION_2023
9509     options { features { enum_type: CLOSED } }
9510     service { name: "Foo" }
9511   )pb");
9512   const ServiceDescriptor* service = file->service(0);
9513   EXPECT_THAT(service->options(), EqualsProto(""));
9514   EXPECT_EQ(GetFeatures(service).enum_type(), FeatureSet::CLOSED);
9515 }
9516 
TEST_F(FeaturesTest,ServiceFeaturesOverride)9517 TEST_F(FeaturesTest, ServiceFeaturesOverride) {
9518   BuildDescriptorMessagesInTestPool();
9519   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9520   const FileDescriptor* file = BuildFile(R"pb(
9521     name: "foo.proto"
9522     syntax: "editions"
9523     edition: EDITION_2023
9524     dependency: "google/protobuf/unittest_features.proto"
9525     options {
9526       features {
9527         [pb.test] { multiple_feature: VALUE2 }
9528       }
9529     }
9530     service {
9531       name: "Foo"
9532       options {
9533         features {
9534           [pb.test] { multiple_feature: VALUE9 }
9535         }
9536       }
9537     }
9538   )pb");
9539   const ServiceDescriptor* service = file->service(0);
9540   EXPECT_THAT(service->options(), EqualsProto(""));
9541   EXPECT_EQ(GetFeatures(service).GetExtension(pb::test).multiple_feature(),
9542             pb::VALUE9);
9543 }
9544 
TEST_F(FeaturesTest,MethodFeaturesDefault)9545 TEST_F(FeaturesTest, MethodFeaturesDefault) {
9546   BuildDescriptorMessagesInTestPool();
9547   const FileDescriptor* file = BuildFile(R"pb(
9548     name: "foo.proto"
9549     syntax: "editions"
9550     edition: EDITION_2023
9551     message_type { name: "EmptyMsg" }
9552     service {
9553       name: "Foo"
9554       method { name: "Bar" input_type: "EmptyMsg" output_type: "EmptyMsg" }
9555     }
9556   )pb");
9557   const MethodDescriptor* method = file->service(0)->method(0);
9558   EXPECT_THAT(method->options(), EqualsProto(""));
9559   EXPECT_THAT(GetCoreFeatures(method), EqualsProto(R"pb(
9560                 field_presence: EXPLICIT
9561                 enum_type: OPEN
9562                 repeated_field_encoding: PACKED
9563                 utf8_validation: VERIFY
9564                 message_encoding: LENGTH_PREFIXED
9565                 json_format: ALLOW
9566                 [pb.cpp] {
9567                   legacy_closed_enum: false
9568                   string_type: STRING
9569                   enum_name_uses_string_view: false
9570                 })pb"));
9571 }
9572 
TEST_F(FeaturesTest,MethodFeaturesInherit)9573 TEST_F(FeaturesTest, MethodFeaturesInherit) {
9574   BuildDescriptorMessagesInTestPool();
9575   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9576   const FileDescriptor* file = BuildFile(R"pb(
9577     name: "foo.proto"
9578     syntax: "editions"
9579     edition: EDITION_2023
9580     dependency: "google/protobuf/unittest_features.proto"
9581     message_type { name: "EmptyMsg" }
9582     options { features { enum_type: CLOSED } }
9583     service {
9584       name: "Foo"
9585       options {
9586         features {
9587           [pb.test] { service_feature: VALUE9 }
9588         }
9589       }
9590       method { name: "Bar" input_type: "EmptyMsg" output_type: "EmptyMsg" }
9591     }
9592   )pb");
9593   const MethodDescriptor* method = file->service(0)->method(0);
9594   EXPECT_THAT(method->options(), EqualsProto(""));
9595   EXPECT_EQ(GetFeatures(method).enum_type(), FeatureSet::CLOSED);
9596   EXPECT_EQ(GetFeatures(method).GetExtension(pb::test).service_feature(),
9597             pb::VALUE9);
9598 }
9599 
TEST_F(FeaturesTest,MethodFeaturesOverride)9600 TEST_F(FeaturesTest, MethodFeaturesOverride) {
9601   BuildDescriptorMessagesInTestPool();
9602   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9603   const FileDescriptor* file = BuildFile(R"pb(
9604     name: "foo.proto"
9605     syntax: "editions"
9606     edition: EDITION_2023
9607     dependency: "google/protobuf/unittest_features.proto"
9608     message_type { name: "EmptyMsg" }
9609     options {
9610       features {
9611         enum_type: CLOSED
9612         [pb.test] { multiple_feature: VALUE2 }
9613       }
9614     }
9615     service {
9616       name: "Foo"
9617       options {
9618         features {
9619           [pb.test] { service_feature: VALUE4 multiple_feature: VALUE4 }
9620         }
9621       }
9622       method {
9623         name: "Bar"
9624         input_type: "EmptyMsg"
9625         output_type: "EmptyMsg"
9626         options {
9627           features {
9628             [pb.test] { multiple_feature: VALUE9 }
9629           }
9630         }
9631       }
9632     }
9633   )pb");
9634   const MethodDescriptor* method = file->service(0)->method(0);
9635   EXPECT_THAT(method->options(), EqualsProto(""));
9636   EXPECT_EQ(GetFeatures(method).enum_type(), FeatureSet::CLOSED);
9637   EXPECT_EQ(GetFeatures(method).GetExtension(pb::test).service_feature(),
9638             pb::VALUE4);
9639   EXPECT_EQ(GetFeatures(method).GetExtension(pb::test).multiple_feature(),
9640             pb::VALUE9);
9641 }
9642 
TEST_F(FeaturesTest,FieldFeatureHelpers)9643 TEST_F(FeaturesTest, FieldFeatureHelpers) {
9644   BuildDescriptorMessagesInTestPool();
9645   const FileDescriptor* file = BuildFile(R"pb(
9646     name: "foo.proto"
9647     syntax: "editions"
9648     edition: EDITION_2023
9649     message_type {
9650       name: "Foo"
9651       field { name: "def" number: 1 label: LABEL_OPTIONAL type: TYPE_STRING }
9652       field { name: "rep" number: 2 label: LABEL_REPEATED type: TYPE_INT32 }
9653       field {
9654         name: "implicit_field"
9655         number: 3
9656         label: LABEL_OPTIONAL
9657         type: TYPE_STRING
9658         options { features { field_presence: IMPLICIT } }
9659       }
9660       field {
9661         name: "required_field"
9662         number: 4
9663         label: LABEL_OPTIONAL
9664         type: TYPE_STRING
9665         options { features { field_presence: LEGACY_REQUIRED } }
9666       }
9667       field {
9668         name: "required_message_field"
9669         number: 5
9670         label: LABEL_OPTIONAL
9671         type: TYPE_MESSAGE
9672         type_name: "Foo"
9673         options { features { field_presence: LEGACY_REQUIRED } }
9674       }
9675       field {
9676         name: "expanded_field"
9677         number: 6
9678         label: LABEL_REPEATED
9679         type: TYPE_STRING
9680         options { features { repeated_field_encoding: EXPANDED } }
9681       }
9682       field {
9683         name: "utf8_verify_field"
9684         number: 7
9685         label: LABEL_REPEATED
9686         type: TYPE_STRING
9687         options { features { utf8_validation: NONE } }
9688       }
9689     }
9690   )pb");
9691   const Descriptor* message = file->message_type(0);
9692   const FieldDescriptor* default_field = message->field(0);
9693   const FieldDescriptor* default_repeated_field = message->field(1);
9694   const FieldDescriptor* implicit_field = message->field(2);
9695   const FieldDescriptor* required_field = message->field(3);
9696   const FieldDescriptor* required_message_field = message->field(4);
9697   const FieldDescriptor* expanded_field = message->field(5);
9698   const FieldDescriptor* utf8_verify_field = message->field(6);
9699 
9700   EXPECT_FALSE(default_field->is_packed());
9701   EXPECT_FALSE(default_field->is_required());
9702   EXPECT_TRUE(default_field->has_presence());
9703   EXPECT_TRUE(default_field->requires_utf8_validation());
9704   EXPECT_EQ(GetUtf8CheckMode(default_field, /*is_lite=*/false),
9705             Utf8CheckMode::kStrict);
9706   EXPECT_EQ(GetUtf8CheckMode(default_field, /*is_lite=*/true),
9707             Utf8CheckMode::kStrict);
9708 
9709   EXPECT_TRUE(default_repeated_field->is_packed());
9710   EXPECT_FALSE(default_repeated_field->has_presence());
9711   EXPECT_FALSE(default_repeated_field->requires_utf8_validation());
9712   EXPECT_EQ(GetUtf8CheckMode(default_repeated_field, /*is_lite=*/false),
9713             Utf8CheckMode::kNone);
9714   EXPECT_EQ(GetUtf8CheckMode(default_repeated_field, /*is_lite=*/true),
9715             Utf8CheckMode::kNone);
9716 
9717   EXPECT_TRUE(required_field->has_presence());
9718   EXPECT_TRUE(required_field->is_required());
9719   EXPECT_TRUE(required_message_field->has_presence());
9720   EXPECT_TRUE(required_message_field->is_required());
9721 
9722   EXPECT_FALSE(implicit_field->has_presence());
9723   EXPECT_FALSE(expanded_field->is_packed());
9724   EXPECT_FALSE(utf8_verify_field->requires_utf8_validation());
9725   EXPECT_EQ(GetUtf8CheckMode(utf8_verify_field, /*is_lite=*/false),
9726             Utf8CheckMode::kVerify);
9727   EXPECT_EQ(GetUtf8CheckMode(utf8_verify_field, /*is_lite=*/true),
9728             Utf8CheckMode::kNone);
9729   EXPECT_EQ(GetUtf8CheckMode(utf8_verify_field, /*is_lite=*/false),
9730             Utf8CheckMode::kVerify);
9731   EXPECT_EQ(GetUtf8CheckMode(utf8_verify_field, /*is_lite=*/true),
9732             Utf8CheckMode::kNone);
9733 }
9734 
TEST_F(FeaturesTest,EnumFeatureHelpers)9735 TEST_F(FeaturesTest, EnumFeatureHelpers) {
9736   BuildDescriptorMessagesInTestPool();
9737   BuildFileInTestPool(pb::CppFeatures::GetDescriptor()->file());
9738   const FileDescriptor* file = BuildFile(R"pb(
9739     name: "foo.proto"
9740     syntax: "editions"
9741     dependency: "google/protobuf/cpp_features.proto"
9742     edition: EDITION_2023
9743     enum_type {
9744       name: "FooOpen"
9745       value { name: "BAR" number: 0 }
9746     }
9747     enum_type {
9748       name: "FooClosed"
9749       value { name: "BAZ" number: 0 }
9750       options { features { enum_type: CLOSED } }
9751     }
9752     message_type {
9753       name: "FooMessage"
9754       field {
9755         name: "open"
9756         number: 1
9757         label: LABEL_OPTIONAL
9758         type: TYPE_ENUM
9759         type_name: "FooOpen"
9760       }
9761       field {
9762         name: "closed"
9763         number: 2
9764         label: LABEL_OPTIONAL
9765         type: TYPE_ENUM
9766         type_name: "FooClosed"
9767       }
9768       field {
9769         name: "legacy_closed"
9770         number: 3
9771         label: LABEL_OPTIONAL
9772         type: TYPE_ENUM
9773         type_name: "FooOpen"
9774         options {
9775           features {
9776             [pb.cpp] { legacy_closed_enum: true }
9777           }
9778         }
9779       }
9780     }
9781   )pb");
9782   const EnumDescriptor* open = file->enum_type(0);
9783   const EnumDescriptor* closed = file->enum_type(1);
9784   const FieldDescriptor* field_open = file->message_type(0)->field(0);
9785   const FieldDescriptor* field_closed = file->message_type(0)->field(1);
9786   const FieldDescriptor* field_legacy_closed = file->message_type(0)->field(2);
9787   ASSERT_EQ(field_legacy_closed->enum_type(), field_open->enum_type());
9788 
9789   EXPECT_FALSE(open->is_closed());
9790   EXPECT_TRUE(closed->is_closed());
9791   EXPECT_FALSE(field_open->legacy_enum_field_treated_as_closed());
9792   EXPECT_TRUE(field_closed->legacy_enum_field_treated_as_closed());
9793   EXPECT_TRUE(field_legacy_closed->legacy_enum_field_treated_as_closed());
9794   EXPECT_TRUE(HasPreservingUnknownEnumSemantics(field_open));
9795   EXPECT_FALSE(HasPreservingUnknownEnumSemantics(field_closed));
9796   EXPECT_FALSE(HasPreservingUnknownEnumSemantics(field_legacy_closed));
9797 }
9798 
TEST_F(FeaturesTest,FieldCppStringType)9799 TEST_F(FeaturesTest, FieldCppStringType) {
9800   BuildDescriptorMessagesInTestPool();
9801   const std::string file_contents = absl::Substitute(
9802       R"pb(
9803         name: "foo.proto"
9804         syntax: "editions"
9805         edition: EDITION_2024
9806         message_type {
9807           name: "Foo"
9808           field {
9809             name: "view"
9810             number: 1
9811             label: LABEL_OPTIONAL
9812             type: TYPE_STRING
9813           }
9814           field {
9815             name: "str"
9816             number: 2
9817             label: LABEL_OPTIONAL
9818             type: TYPE_STRING
9819             options {
9820               features {
9821                 [pb.cpp] { string_type: STRING }
9822               }
9823             }
9824           }
9825           field {
9826             name: "cord"
9827             number: 3
9828             label: LABEL_OPTIONAL
9829             type: TYPE_STRING
9830             options {
9831               features {
9832                 [pb.cpp] { string_type: CORD }
9833               }
9834             }
9835           }
9836           field {
9837             name: "cord_bytes"
9838             number: 4
9839             label: LABEL_OPTIONAL
9840             type: TYPE_BYTES
9841             options {
9842               features {
9843                 [pb.cpp] { string_type: CORD }
9844               }
9845             }
9846           } $0
9847         }
9848       )pb",
9849       ""
9850   );
9851   const FileDescriptor* file = BuildFile(file_contents);
9852   const Descriptor* message = file->message_type(0);
9853   const FieldDescriptor* view = message->field(0);
9854   const FieldDescriptor* str = message->field(1);
9855   const FieldDescriptor* cord = message->field(2);
9856   const FieldDescriptor* cord_bytes = message->field(3);
9857 
9858   EXPECT_EQ(view->cpp_string_type(), FieldDescriptor::CppStringType::kView);
9859   EXPECT_EQ(str->cpp_string_type(), FieldDescriptor::CppStringType::kString);
9860   EXPECT_EQ(cord_bytes->cpp_string_type(),
9861             FieldDescriptor::CppStringType::kCord);
9862   EXPECT_EQ(cord->cpp_string_type(), FieldDescriptor::CppStringType::kString);
9863 
9864 }
9865 
TEST_F(FeaturesTest,MergeFeatureValidationFailed)9866 TEST_F(FeaturesTest, MergeFeatureValidationFailed) {
9867   BuildDescriptorMessagesInTestPool();
9868   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9869   BuildFileWithErrors(
9870       R"pb(
9871         name: "foo.proto"
9872         syntax: "editions"
9873         edition: EDITION_2023
9874         dependency: "google/protobuf/unittest_features.proto"
9875         options { features { field_presence: FIELD_PRESENCE_UNKNOWN } }
9876       )pb",
9877       "foo.proto: foo.proto: EDITIONS: Feature field "
9878       "`field_presence` must resolve to a known value, found "
9879       "FIELD_PRESENCE_UNKNOWN\n");
9880 }
9881 
TEST_F(FeaturesTest,FeaturesOutsideEditions)9882 TEST_F(FeaturesTest, FeaturesOutsideEditions) {
9883   BuildDescriptorMessagesInTestPool();
9884   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
9885   BuildFileWithErrors(
9886       R"pb(
9887         name: "foo.proto"
9888         syntax: "proto2"
9889         dependency: "google/protobuf/unittest_features.proto"
9890         options { features { field_presence: IMPLICIT } }
9891       )pb",
9892       "foo.proto: foo.proto: EDITIONS: Features are only valid under "
9893       "editions.\n");
9894 }
9895 
TEST_F(FeaturesTest,InvalidFileRequiredPresence)9896 TEST_F(FeaturesTest, InvalidFileRequiredPresence) {
9897   BuildDescriptorMessagesInTestPool();
9898   BuildFileWithErrors(
9899       R"pb(
9900         name: "foo.proto"
9901         syntax: "editions"
9902         edition: EDITION_2023
9903         options { features { field_presence: LEGACY_REQUIRED } }
9904       )pb",
9905       "foo.proto: foo.proto: EDITIONS: Required presence can't be specified "
9906       "by default.\n");
9907 }
9908 
TEST_F(FeaturesTest,InvalidFileJavaStringCheckUtf8)9909 TEST_F(FeaturesTest, InvalidFileJavaStringCheckUtf8) {
9910   BuildDescriptorMessagesInTestPool();
9911   BuildFileWithErrors(
9912       R"pb(
9913         name: "foo.proto"
9914         syntax: "editions"
9915         edition: EDITION_2023
9916         options { java_string_check_utf8: true }
9917       )pb",
9918       "foo.proto: foo.proto: EDITIONS: File option java_string_check_utf8 is "
9919       "not allowed under editions. Use the (pb.java).utf8_validation feature "
9920       "to control this behavior.\n");
9921 }
9922 
9923 TEST_F(FeaturesTest, Proto2FileJavaStringCheckUtf8) {
9924   BuildDescriptorMessagesInTestPool();
9925   const FileDescriptor* file = BuildFile(
9926       R"pb(
9927         name: "foo.proto"
9928         syntax: "proto2"
9929         options { java_string_check_utf8: true }
9930       )pb");
9931   EXPECT_EQ(file->options().java_string_check_utf8(), true);
9932 }
9933 TEST_F(FeaturesTest, InvalidFieldPacked) {
9934   BuildDescriptorMessagesInTestPool();
9935   BuildFileWithErrors(
9936       R"pb(
9937         name: "foo.proto"
9938         syntax: "editions"
9939         edition: EDITION_2023
9940         message_type {
9941           name: "Foo"
9942           field {
9943             name: "bar"
9944             number: 1
9945             label: LABEL_REPEATED
9946             type: TYPE_INT64
9947             options { packed: true }
9948           }
9949         }
9950       )pb",
9951       "foo.proto: Foo.bar: NAME: Field option packed is not allowed under "
9952       "editions.  Use the repeated_field_encoding feature to control this "
9953       "behavior.\n");
9954 }
9955 
9956 TEST_F(FeaturesTest, NoCtypeFromEdition2024) {
9957   BuildDescriptorMessagesInTestPool();
9958   BuildFileWithErrors(
9959       R"pb(
9960         name: "foo.proto"
9961         syntax: "editions"
9962         edition: EDITION_2024
9963         message_type {
9964           name: "Foo"
9965           field { name: "foo" number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 }
9966           field {
9967             name: "bar"
9968             number: 2
9969             label: LABEL_OPTIONAL
9970             type: TYPE_STRING
9971             options { ctype: CORD }
9972           }
9973         }
9974       )pb",
9975       "foo.proto: Foo.bar: NAME: ctype option is not allowed under edition "
9976       "2024 and beyond. Use the feature string_type = VIEW|CORD|STRING|... "
9977       "instead.\n");
9978 }
9979 
9980 
9981 TEST_F(FeaturesTest, InvalidFieldImplicitDefault) {
9982   BuildDescriptorMessagesInTestPool();
9983   BuildFileWithErrors(
9984       R"pb(
9985         name: "foo.proto"
9986         syntax: "editions"
9987         edition: EDITION_2023
9988         message_type {
9989           name: "Foo"
9990           field {
9991             name: "bar"
9992             number: 1
9993             label: LABEL_OPTIONAL
9994             type: TYPE_STRING
9995             default_value: "Hello world"
9996             options { features { field_presence: IMPLICIT } }
9997           }
9998         }
9999       )pb",
10000       "foo.proto: Foo.bar: NAME: Implicit presence fields can't specify "
10001       "defaults.\n");
10002 }
10003 
10004 TEST_F(FeaturesTest, ValidExtensionFieldImplicitDefault) {
10005   BuildDescriptorMessagesInTestPool();
10006   const FileDescriptor* file = BuildFile(
10007       R"pb(
10008         name: "foo.proto"
10009         syntax: "editions"
10010         edition: EDITION_2023
10011         options { features { field_presence: IMPLICIT } }
10012         message_type {
10013           name: "Foo"
10014           extension_range { start: 1 end: 100 }
10015         }
10016         extension {
10017           name: "bar"
10018           number: 1
10019           label: LABEL_OPTIONAL
10020           type: TYPE_STRING
10021           default_value: "Hello world"
10022           extendee: "Foo"
10023         }
10024       )pb");
10025   ASSERT_THAT(file, NotNull());
10026 
10027   EXPECT_TRUE(file->extension(0)->has_presence());
10028   EXPECT_EQ(file->extension(0)->default_value_string(), "Hello world");
10029 }
10030 
TEST_F(FeaturesTest,ValidOneofFieldImplicitDefault)10031 TEST_F(FeaturesTest, ValidOneofFieldImplicitDefault) {
10032   BuildDescriptorMessagesInTestPool();
10033   const FileDescriptor* file = BuildFile(
10034       R"pb(
10035         name: "foo.proto"
10036         syntax: "editions"
10037         edition: EDITION_2023
10038         options { features { field_presence: IMPLICIT } }
10039         message_type {
10040           name: "Foo"
10041           field {
10042             name: "bar"
10043             number: 1
10044             label: LABEL_OPTIONAL
10045             type: TYPE_STRING
10046             default_value: "Hello world"
10047             oneof_index: 0
10048           }
10049           oneof_decl { name: "_foo" }
10050         }
10051       )pb");
10052   ASSERT_THAT(file, NotNull());
10053 
10054   EXPECT_TRUE(file->message_type(0)->field(0)->has_presence());
10055   EXPECT_EQ(file->message_type(0)->field(0)->default_value_string(),
10056             "Hello world");
10057 }
10058 
TEST_F(FeaturesTest,InvalidFieldImplicitClosed)10059 TEST_F(FeaturesTest, InvalidFieldImplicitClosed) {
10060   BuildDescriptorMessagesInTestPool();
10061   BuildFileWithErrors(
10062       R"pb(
10063         name: "foo.proto"
10064         syntax: "editions"
10065         edition: EDITION_2023
10066         message_type {
10067           name: "Foo"
10068           field {
10069             name: "bar"
10070             number: 1
10071             label: LABEL_OPTIONAL
10072             type: TYPE_ENUM
10073             type_name: "Enum"
10074             options { features { field_presence: IMPLICIT } }
10075           }
10076         }
10077         enum_type {
10078           name: "Enum"
10079           value { name: "BAR" number: 0 }
10080           options { features { enum_type: CLOSED } }
10081         }
10082       )pb",
10083       "foo.proto: Foo.bar: NAME: Implicit presence enum fields must always "
10084       "be open.\n");
10085 }
10086 
TEST_F(FeaturesTest,ValidRepeatedFieldImplicitClosed)10087 TEST_F(FeaturesTest, ValidRepeatedFieldImplicitClosed) {
10088   BuildDescriptorMessagesInTestPool();
10089   const FileDescriptor* file = BuildFile(
10090       R"pb(
10091         name: "foo.proto"
10092         syntax: "editions"
10093         edition: EDITION_2023
10094         options { features { field_presence: IMPLICIT } }
10095         message_type {
10096           name: "Foo"
10097           field {
10098             name: "bar"
10099             number: 1
10100             label: LABEL_REPEATED
10101             type: TYPE_ENUM
10102             type_name: "Enum"
10103           }
10104         }
10105         enum_type {
10106           name: "Enum"
10107           value { name: "BAR" number: 0 }
10108           options { features { enum_type: CLOSED } }
10109         }
10110       )pb");
10111   ASSERT_THAT(file, NotNull());
10112 
10113   EXPECT_FALSE(file->message_type(0)->field(0)->has_presence());
10114   EXPECT_TRUE(file->enum_type(0)->is_closed());
10115 }
10116 
TEST_F(FeaturesTest,ValidOneofFieldImplicitClosed)10117 TEST_F(FeaturesTest, ValidOneofFieldImplicitClosed) {
10118   BuildDescriptorMessagesInTestPool();
10119   const FileDescriptor* file = BuildFile(
10120       R"pb(
10121         name: "foo.proto"
10122         syntax: "editions"
10123         edition: EDITION_2023
10124         options { features { field_presence: IMPLICIT } }
10125         message_type {
10126           name: "Foo"
10127           field {
10128             name: "bar"
10129             number: 1
10130             label: LABEL_OPTIONAL
10131             type: TYPE_ENUM
10132             type_name: "Enum"
10133             oneof_index: 0
10134           }
10135           oneof_decl { name: "_foo" }
10136         }
10137         enum_type {
10138           name: "Enum"
10139           value { name: "BAR" number: 0 }
10140           options { features { enum_type: CLOSED } }
10141         }
10142       )pb");
10143   ASSERT_THAT(file, NotNull());
10144 
10145   EXPECT_TRUE(file->message_type(0)->field(0)->has_presence());
10146   EXPECT_TRUE(file->enum_type(0)->is_closed());
10147 }
10148 
TEST_F(FeaturesTest,InvalidFieldRequiredExtension)10149 TEST_F(FeaturesTest, InvalidFieldRequiredExtension) {
10150   BuildDescriptorMessagesInTestPool();
10151   BuildFileWithErrors(
10152       R"pb(
10153         name: "foo.proto"
10154         syntax: "editions"
10155         edition: EDITION_2023
10156         message_type {
10157           name: "Foo"
10158           extension_range { start: 1 end: 100 }
10159         }
10160         extension {
10161           name: "bar"
10162           number: 1
10163           label: LABEL_OPTIONAL
10164           type: TYPE_STRING
10165           options { features { field_presence: LEGACY_REQUIRED } }
10166           extendee: "Foo"
10167         }
10168       )pb",
10169       "foo.proto: bar: NAME: Extensions can't be required.\n");
10170 }
10171 
TEST_F(FeaturesTest,InvalidFieldImplicitExtension)10172 TEST_F(FeaturesTest, InvalidFieldImplicitExtension) {
10173   BuildDescriptorMessagesInTestPool();
10174   BuildFileWithErrors(
10175       R"pb(
10176         name: "foo.proto"
10177         syntax: "editions"
10178         edition: EDITION_2023
10179         message_type {
10180           name: "Foo"
10181           extension_range { start: 1 end: 100 }
10182         }
10183         extension {
10184           name: "bar"
10185           number: 1
10186           label: LABEL_OPTIONAL
10187           type: TYPE_STRING
10188           options { features { field_presence: IMPLICIT } }
10189           extendee: "Foo"
10190         }
10191       )pb",
10192       "foo.proto: bar: NAME: Extensions can't specify field presence.\n");
10193 }
10194 
10195 TEST_F(FeaturesTest, InvalidFieldMessageImplicit) {
10196   BuildDescriptorMessagesInTestPool();
10197   BuildFileWithErrors(
10198       R"pb(
10199         name: "foo.proto"
10200         syntax: "editions"
10201         edition: EDITION_2023
10202         message_type {
10203           name: "Foo"
10204           field {
10205             name: "bar"
10206             number: 1
10207             label: LABEL_OPTIONAL
10208             type: TYPE_MESSAGE
10209             type_name: "Foo"
10210             options { features { field_presence: IMPLICIT } }
10211           }
10212         }
10213       )pb",
10214       "foo.proto: Foo.bar: NAME: Message fields can't specify implicit "
10215       "presence.\n");
10216 }
10217 
TEST_F(FeaturesTest,InvalidFieldRepeatedImplicit)10218 TEST_F(FeaturesTest, InvalidFieldRepeatedImplicit) {
10219   BuildDescriptorMessagesInTestPool();
10220   BuildFileWithErrors(
10221       R"pb(
10222         name: "foo.proto"
10223         syntax: "editions"
10224         edition: EDITION_2023
10225         message_type {
10226           name: "Foo"
10227           field {
10228             name: "bar"
10229             number: 1
10230             label: LABEL_REPEATED
10231             type: TYPE_STRING
10232             options { features { field_presence: IMPLICIT } }
10233           }
10234         }
10235       )pb",
10236       "foo.proto: Foo.bar: NAME: Repeated fields can't specify field "
10237       "presence.\n");
10238 }
10239 
10240 TEST_F(FeaturesTest, InvalidFieldMapImplicit) {
10241   constexpr absl::string_view kProtoFile = R"schema(
10242     edition = "2023";
10243 
10244     message Foo {
10245       map<string, Foo> bar = 1 [
10246         features.field_presence = IMPLICIT
10247       ];
10248     }
10249   )schema";
10250   io::ArrayInputStream input_stream(kProtoFile.data(), kProtoFile.size());
10251   SimpleErrorCollector error_collector;
10252   io::Tokenizer tokenizer(&input_stream, &error_collector);
10253   compiler::Parser parser;
10254   parser.RecordErrorsTo(&error_collector);
10255   FileDescriptorProto proto;
10256   ASSERT_TRUE(parser.Parse(&tokenizer, &proto))
10257       << error_collector.last_error() << "\n"
10258       << kProtoFile;
10259   ASSERT_EQ("", error_collector.last_error());
10260   proto.set_name("foo.proto");
10261 
10262   BuildDescriptorMessagesInTestPool();
10263   BuildFileWithErrors(proto,
10264                       "foo.proto: Foo.bar: NAME: Repeated fields can't specify "
10265                       "field presence.\n");
10266 }
10267 
TEST_F(FeaturesTest,InvalidFieldOneofImplicit)10268 TEST_F(FeaturesTest, InvalidFieldOneofImplicit) {
10269   BuildDescriptorMessagesInTestPool();
10270   BuildFileWithErrors(
10271       R"pb(
10272         name: "foo.proto"
10273         syntax: "editions"
10274         edition: EDITION_2023
10275         message_type {
10276           name: "Foo"
10277           field {
10278             name: "bar"
10279             number: 1
10280             oneof_index: 0
10281             label: LABEL_OPTIONAL
10282             type: TYPE_INT64
10283             options { features { field_presence: IMPLICIT } }
10284           }
10285           oneof_decl { name: "_foo" }
10286         }
10287       )pb",
10288       "foo.proto: Foo.bar: NAME: Oneof fields can't specify field presence.\n");
10289 }
10290 
10291 TEST_F(FeaturesTest, InvalidFieldRepeatedRequired) {
10292   BuildDescriptorMessagesInTestPool();
10293   BuildFileWithErrors(
10294       R"pb(
10295         name: "foo.proto"
10296         syntax: "editions"
10297         edition: EDITION_2023
10298         message_type {
10299           name: "Foo"
10300           field {
10301             name: "bar"
10302             number: 1
10303             label: LABEL_REPEATED
10304             type: TYPE_STRING
10305             options { features { field_presence: LEGACY_REQUIRED } }
10306           }
10307         }
10308       )pb",
10309       "foo.proto: Foo.bar: NAME: Repeated fields can't specify field "
10310       "presence.\n");
10311 }
10312 
TEST_F(FeaturesTest,InvalidFieldOneofRequired)10313 TEST_F(FeaturesTest, InvalidFieldOneofRequired) {
10314   BuildDescriptorMessagesInTestPool();
10315   BuildFileWithErrors(
10316       R"pb(
10317         name: "foo.proto"
10318         syntax: "editions"
10319         edition: EDITION_2023
10320         message_type {
10321           name: "Foo"
10322           field {
10323             name: "bar"
10324             number: 1
10325             oneof_index: 0
10326             label: LABEL_OPTIONAL
10327             type: TYPE_INT64
10328             options { features { field_presence: LEGACY_REQUIRED } }
10329           }
10330           oneof_decl { name: "_foo" }
10331         }
10332       )pb",
10333       "foo.proto: Foo.bar: NAME: Oneof fields can't specify field presence.\n");
10334 }
10335 
10336 TEST_F(FeaturesTest, InvalidFieldNonStringWithStringValidation) {
10337   BuildDescriptorMessagesInTestPool();
10338   BuildFileWithErrors(
10339       R"pb(
10340         name: "foo.proto"
10341         syntax: "editions"
10342         edition: EDITION_2023
10343         message_type {
10344           name: "Foo"
10345           field {
10346             name: "bar"
10347             number: 1
10348             label: LABEL_OPTIONAL
10349             type: TYPE_INT64
10350             options { features { utf8_validation: NONE } }
10351           }
10352         }
10353       )pb",
10354       "foo.proto: Foo.bar: NAME: Only string fields can specify "
10355       "utf8 validation.\n");
10356 }
10357 
TEST_F(FeaturesTest,InvalidFieldNonStringMapWithStringValidation)10358 TEST_F(FeaturesTest, InvalidFieldNonStringMapWithStringValidation) {
10359   BuildDescriptorMessagesInTestPool();
10360   BuildFileWithErrors(
10361       R"pb(
10362         name: "foo.proto"
10363         syntax: "editions"
10364         edition: EDITION_2023
10365         message_type {
10366           name: "Foo"
10367           nested_type {
10368             name: "MapFieldEntry"
10369             field {
10370               name: "key"
10371               number: 1
10372               label: LABEL_OPTIONAL
10373               type: TYPE_INT32
10374               options {
10375                 uninterpreted_option {
10376                   name { name_part: "features" is_extension: false }
10377                   name { name_part: "utf8_validation" is_extension: false }
10378                   identifier_value: "NONE"
10379                 }
10380               }
10381             }
10382             field {
10383               name: "value"
10384               number: 2
10385               label: LABEL_OPTIONAL
10386               type: TYPE_INT32
10387               options {
10388                 uninterpreted_option {
10389                   name { name_part: "features" is_extension: false }
10390                   name { name_part: "utf8_validation" is_extension: false }
10391                   identifier_value: "NONE"
10392                 }
10393               }
10394             }
10395             options { map_entry: true }
10396           }
10397           field {
10398             name: "map_field"
10399             number: 1
10400             label: LABEL_REPEATED
10401             type_name: "MapFieldEntry"
10402             options {
10403               uninterpreted_option {
10404                 name { name_part: "features" is_extension: false }
10405                 name { name_part: "utf8_validation" is_extension: false }
10406                 identifier_value: "NONE"
10407               }
10408             }
10409           }
10410         }
10411       )pb",
10412       "foo.proto: Foo.map_field: NAME: Only string fields can specify "
10413       "utf8 validation.\n");
10414 }
10415 
TEST_F(FeaturesTest,InvalidFieldNonRepeatedWithRepeatedEncoding)10416 TEST_F(FeaturesTest, InvalidFieldNonRepeatedWithRepeatedEncoding) {
10417   BuildDescriptorMessagesInTestPool();
10418   BuildFileWithErrors(
10419       R"pb(
10420         name: "foo.proto"
10421         syntax: "editions"
10422         edition: EDITION_2023
10423         message_type {
10424           name: "Foo"
10425           field {
10426             name: "bar"
10427             number: 1
10428             label: LABEL_OPTIONAL
10429             type: TYPE_INT64
10430             options { features { repeated_field_encoding: EXPANDED } }
10431           }
10432         }
10433       )pb",
10434       "foo.proto: Foo.bar: NAME: Only repeated fields can specify repeated "
10435       "field encoding.\n");
10436 }
10437 
TEST_F(FeaturesTest,InvalidFieldNonPackableWithPackedRepeatedEncoding)10438 TEST_F(FeaturesTest, InvalidFieldNonPackableWithPackedRepeatedEncoding) {
10439   BuildDescriptorMessagesInTestPool();
10440   BuildFileWithErrors(
10441       R"pb(
10442         name: "foo.proto"
10443         syntax: "editions"
10444         edition: EDITION_2023
10445         message_type {
10446           name: "Foo"
10447           field {
10448             name: "bar"
10449             number: 1
10450             label: LABEL_REPEATED
10451             type: TYPE_STRING
10452             options { features { repeated_field_encoding: PACKED } }
10453           }
10454         }
10455       )pb",
10456       "foo.proto: Foo.bar: NAME: Only repeated primitive fields can specify "
10457       "PACKED repeated field encoding.\n");
10458 }
10459 
TEST_F(FeaturesTest,InvalidFieldNonMessageWithMessageEncoding)10460 TEST_F(FeaturesTest, InvalidFieldNonMessageWithMessageEncoding) {
10461   BuildDescriptorMessagesInTestPool();
10462   BuildFileWithErrors(
10463       R"pb(
10464         name: "foo.proto"
10465         syntax: "editions"
10466         edition: EDITION_2023
10467         message_type {
10468           name: "Foo"
10469           field {
10470             name: "bar"
10471             number: 1
10472             label: LABEL_OPTIONAL
10473             type: TYPE_INT64
10474             options { features { message_encoding: DELIMITED } }
10475           }
10476         }
10477       )pb",
10478       "foo.proto: Foo.bar: NAME: Only message fields can specify message "
10479       "encoding.\n");
10480 }
10481 
TEST_F(FeaturesTest,InvalidFieldMapWithMessageEncoding)10482 TEST_F(FeaturesTest, InvalidFieldMapWithMessageEncoding) {
10483   constexpr absl::string_view kProtoFile = R"schema(
10484     edition = "2023";
10485 
10486     message Foo {
10487       map<string, Foo> bar = 1 [
10488         features.message_encoding = DELIMITED
10489       ];
10490     }
10491   )schema";
10492   io::ArrayInputStream input_stream(kProtoFile.data(), kProtoFile.size());
10493   SimpleErrorCollector error_collector;
10494   io::Tokenizer tokenizer(&input_stream, &error_collector);
10495   compiler::Parser parser;
10496   parser.RecordErrorsTo(&error_collector);
10497   FileDescriptorProto proto;
10498   ASSERT_TRUE(parser.Parse(&tokenizer, &proto))
10499       << error_collector.last_error() << "\n"
10500       << kProtoFile;
10501   ASSERT_EQ("", error_collector.last_error());
10502   proto.set_name("foo.proto");
10503 
10504   BuildDescriptorMessagesInTestPool();
10505   BuildFileWithErrors(
10506       proto,
10507       "foo.proto: Foo.bar: NAME: Only message fields can specify message "
10508       "encoding.\n");
10509 }
10510 
TEST_F(FeaturesTest,InvalidOpenEnumNonZeroFirstValue)10511 TEST_F(FeaturesTest, InvalidOpenEnumNonZeroFirstValue) {
10512   BuildDescriptorMessagesInTestPool();
10513   BuildFileWithErrors(
10514       R"pb(
10515         name: "foo.proto"
10516         syntax: "editions"
10517         edition: EDITION_2023
10518         enum_type {
10519           name: "Enum"
10520           value { name: "BAR" number: 1 }
10521           options { features { enum_type: OPEN } }
10522         }
10523       )pb",
10524       "foo.proto: Enum: NUMBER: The first enum value must be zero for open "
10525       "enums.\n");
10526 }
10527 
TEST_F(FeaturesTest,InvalidUseFeaturesInSameFile)10528 TEST_F(FeaturesTest, InvalidUseFeaturesInSameFile) {
10529   BuildDescriptorMessagesInTestPool();
10530   ParseAndBuildFileWithErrors("foo.proto", R"schema(
10531     edition = "2023";
10532 
10533     package test;
10534     import "google/protobuf/descriptor.proto";
10535 
10536     message Foo {
10537       string bar = 1 [
10538         features.(test.custom).foo = "xyz",
10539         features.(test.another) = {foo: -321}
10540       ];
10541     }
10542 
10543     message Custom {
10544       string foo = 1 [features = { [test.custom]: {foo: "abc"} }];
10545     }
10546     message Another {
10547       Enum foo = 1;
10548     }
10549 
10550     enum Enum {
10551       option features.enum_type = CLOSED;
10552       ZERO = 0;
10553       ONE = 1;
10554     }
10555 
10556     extend google.protobuf.FeatureSet {
10557       Custom custom = 1002 [features.message_encoding=DELIMITED];
10558       Another another = 1001;
10559     }
10560   )schema",
10561                               "foo.proto: test.Foo.bar: OPTION_NAME: Feature "
10562                               "\"features.(test.custom)\" can't be used in the "
10563                               "same file it's defined in.\n");
10564 }
10565 
TEST_F(FeaturesTest,ClosedEnumNonZeroFirstValue)10566 TEST_F(FeaturesTest, ClosedEnumNonZeroFirstValue) {
10567   BuildDescriptorMessagesInTestPool();
10568   const FileDescriptor* file = BuildFile(
10569       R"pb(
10570         name: "foo.proto"
10571         syntax: "editions"
10572         edition: EDITION_2023
10573         enum_type {
10574           name: "Enum"
10575           value { name: "BAR" number: 9 }
10576           options { features { enum_type: CLOSED } }
10577         }
10578       )pb");
10579 
10580   EXPECT_EQ(file->enum_type(0)->value(0)->number(), 9);
10581 }
10582 
TEST_F(FeaturesTest,CopyToIncludesFeatures)10583 TEST_F(FeaturesTest, CopyToIncludesFeatures) {
10584   BuildDescriptorMessagesInTestPool();
10585   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
10586   const FileDescriptor* file = BuildFile(R"pb(
10587     name: "foo.proto"
10588     syntax: "editions"
10589     edition: EDITION_2023
10590     dependency: "google/protobuf/unittest_features.proto"
10591     options {
10592       java_package: "pkg"
10593       features { field_presence: IMPLICIT }
10594     }
10595     message_type {
10596       name: "Foo"
10597       options {
10598         features {
10599           [pb.test] { multiple_feature: VALUE9 }
10600         }
10601       }
10602       field {
10603         name: "bar"
10604         number: 1
10605         label: LABEL_REPEATED
10606         type: TYPE_INT64
10607         options { features { repeated_field_encoding: EXPANDED } }
10608       }
10609     }
10610   )pb");
10611   FileDescriptorProto proto;
10612   file->CopyTo(&proto);
10613   EXPECT_THAT(proto.options(),
10614               EqualsProto(R"pb(java_package: "pkg"
10615                                features { field_presence: IMPLICIT })pb"));
10616   EXPECT_THAT(proto.message_type(0).options(),
10617               EqualsProto(R"pb(features {
10618                                  [pb.test] { multiple_feature: VALUE9 }
10619                                })pb"));
10620   EXPECT_THAT(
10621       proto.message_type(0).field(0).options(),
10622       EqualsProto(R"pb(features { repeated_field_encoding: EXPANDED })pb"));
10623 }
10624 
TEST_F(FeaturesTest,UninterpretedOptions)10625 TEST_F(FeaturesTest, UninterpretedOptions) {
10626   BuildDescriptorMessagesInTestPool();
10627   const FileDescriptor* file = BuildFile(R"pb(
10628     name: "foo.proto"
10629     syntax: "editions"
10630     edition: EDITION_2023
10631     options {
10632       uninterpreted_option {
10633         name { name_part: "features" is_extension: false }
10634         name { name_part: "field_presence" is_extension: false }
10635         identifier_value: "IMPLICIT"
10636       }
10637     }
10638   )pb");
10639   EXPECT_THAT(file->options(), EqualsProto(""));
10640   EXPECT_THAT(GetCoreFeatures(file), EqualsProto(R"pb(
10641                 field_presence: IMPLICIT
10642                 enum_type: OPEN
10643                 repeated_field_encoding: PACKED
10644                 utf8_validation: VERIFY
10645                 message_encoding: LENGTH_PREFIXED
10646                 json_format: ALLOW
10647                 [pb.cpp] {
10648                   legacy_closed_enum: false
10649                   string_type: STRING
10650                   enum_name_uses_string_view: false
10651                 })pb"));
10652 }
10653 
TEST_F(FeaturesTest,UninterpretedOptionsMerge)10654 TEST_F(FeaturesTest, UninterpretedOptionsMerge) {
10655   BuildDescriptorMessagesInTestPool();
10656   const FileDescriptor* file = BuildFile(R"pb(
10657     name: "foo.proto"
10658     syntax: "editions"
10659     edition: EDITION_2023
10660     options {
10661       uninterpreted_option {
10662         name { name_part: "features" is_extension: false }
10663         name { name_part: "enum_type" is_extension: false }
10664         identifier_value: "CLOSED"
10665       }
10666     }
10667     message_type {
10668       name: "Foo"
10669       field {
10670         name: "bar"
10671         number: 1
10672         label: LABEL_OPTIONAL
10673         type: TYPE_STRING
10674         options {
10675           uninterpreted_option {
10676             name { name_part: "features" is_extension: false }
10677             name { name_part: "enum_type" is_extension: false }
10678             identifier_value: "OPEN"
10679           }
10680         }
10681       }
10682     }
10683   )pb");
10684   const FieldDescriptor* field = file->message_type(0)->field(0);
10685   EXPECT_THAT(file->options(), EqualsProto(""));
10686   EXPECT_THAT(field->options(), EqualsProto(""));
10687   EXPECT_EQ(GetFeatures(file).enum_type(), FeatureSet::CLOSED);
10688   EXPECT_EQ(GetFeatures(field).enum_type(), FeatureSet::OPEN);
10689 }
10690 
TEST_F(FeaturesTest,UninterpretedOptionsMergeExtension)10691 TEST_F(FeaturesTest, UninterpretedOptionsMergeExtension) {
10692   BuildDescriptorMessagesInTestPool();
10693   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
10694   const FileDescriptor* file = BuildFile(R"pb(
10695     name: "foo.proto"
10696     syntax: "editions"
10697     edition: EDITION_2023
10698     dependency: "google/protobuf/unittest_features.proto"
10699     options {
10700       uninterpreted_option {
10701         name { name_part: "features" is_extension: false }
10702         name { name_part: "pb.test" is_extension: true }
10703         name { name_part: "multiple_feature" is_extension: false }
10704         identifier_value: "VALUE5"
10705       }
10706       uninterpreted_option {
10707         name { name_part: "features" is_extension: false }
10708         name { name_part: "pb.test" is_extension: true }
10709         name { name_part: "file_feature" is_extension: false }
10710         identifier_value: "VALUE5"
10711       }
10712     }
10713     message_type {
10714       name: "Foo"
10715       options {
10716         uninterpreted_option {
10717           name { name_part: "features" is_extension: false }
10718           name { name_part: "pb.test" is_extension: true }
10719           name { name_part: "multiple_feature" is_extension: false }
10720           identifier_value: "VALUE6"
10721         }
10722         uninterpreted_option {
10723           name { name_part: "features" is_extension: false }
10724           name { name_part: "pb.test" is_extension: true }
10725           name { name_part: "message_feature" is_extension: false }
10726           identifier_value: "VALUE6"
10727         }
10728       }
10729       field {
10730         name: "bar"
10731         number: 1
10732         label: LABEL_OPTIONAL
10733         type: TYPE_STRING
10734         options {
10735           uninterpreted_option {
10736             name { name_part: "features" is_extension: false }
10737             name { name_part: "pb.test" is_extension: true }
10738             name { name_part: "multiple_feature" is_extension: false }
10739             identifier_value: "VALUE7"
10740           }
10741           uninterpreted_option {
10742             name { name_part: "features" is_extension: false }
10743             name { name_part: "pb.test" is_extension: true }
10744             name { name_part: "field_feature" is_extension: false }
10745             identifier_value: "VALUE7"
10746           }
10747         }
10748       }
10749     }
10750   )pb");
10751   const FieldDescriptor* field = file->message_type(0)->field(0);
10752   EXPECT_THAT(field->options(), EqualsProto(""));
10753   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).file_feature(),
10754             pb::VALUE5);
10755   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).message_feature(),
10756             pb::VALUE6);
10757   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).field_feature(),
10758             pb::VALUE7);
10759   EXPECT_EQ(GetFeatures(field).GetExtension(pb::test).multiple_feature(),
10760             pb::VALUE7);
10761 }
10762 
TEST_F(FeaturesTest,InvalidJsonUniquenessDefaultWarning)10763 TEST_F(FeaturesTest, InvalidJsonUniquenessDefaultWarning) {
10764   BuildFileWithWarnings(
10765       R"pb(
10766         name: "foo.proto"
10767         syntax: "editions"
10768         edition: EDITION_2023
10769         message_type {
10770           name: "Foo"
10771           field {
10772             name: "bar"
10773             number: 1
10774             label: LABEL_OPTIONAL
10775             type: TYPE_STRING
10776           }
10777           field {
10778             name: "bar_"
10779             number: 2
10780             label: LABEL_OPTIONAL
10781             type: TYPE_STRING
10782           }
10783           options { features { json_format: LEGACY_BEST_EFFORT } }
10784         }
10785       )pb",
10786       "foo.proto: Foo: NAME: The default JSON name of field \"bar_\" (\"bar\") "
10787       "conflicts with the default JSON name of field \"bar\".\n");
10788 }
10789 
TEST_F(FeaturesTest,InvalidJsonUniquenessDefaultError)10790 TEST_F(FeaturesTest, InvalidJsonUniquenessDefaultError) {
10791   BuildFileWithErrors(
10792       R"pb(
10793         name: "foo.proto"
10794         syntax: "editions"
10795         edition: EDITION_2023
10796         message_type {
10797           name: "Foo"
10798           field {
10799             name: "bar"
10800             number: 1
10801             label: LABEL_OPTIONAL
10802             type: TYPE_STRING
10803           }
10804           field {
10805             name: "bar_"
10806             number: 2
10807             label: LABEL_OPTIONAL
10808             type: TYPE_STRING
10809           }
10810           options { features { json_format: ALLOW } }
10811         }
10812       )pb",
10813       "foo.proto: Foo: NAME: The default JSON name of field \"bar_\" (\"bar\") "
10814       "conflicts with the default JSON name of field \"bar\".\n");
10815 }
10816 
TEST_F(FeaturesTest,InvalidJsonUniquenessCustomError)10817 TEST_F(FeaturesTest, InvalidJsonUniquenessCustomError) {
10818   BuildFileWithErrors(
10819       R"pb(
10820         name: "foo.proto"
10821         syntax: "editions"
10822         edition: EDITION_2023
10823         message_type {
10824           name: "Foo"
10825           field {
10826             name: "bar"
10827             json_name: "baz"
10828             number: 1
10829             label: LABEL_OPTIONAL
10830             type: TYPE_STRING
10831           }
10832           field {
10833             name: "bar2"
10834             json_name: "baz"
10835             number: 2
10836             label: LABEL_OPTIONAL
10837             type: TYPE_STRING
10838           }
10839           options { features { json_format: LEGACY_BEST_EFFORT } }
10840         }
10841       )pb",
10842       "foo.proto: Foo: NAME: The custom JSON name of field \"bar2\" (\"baz\") "
10843       "conflicts with the custom JSON name of field \"bar\".\n");
10844 }
10845 
TEST_F(FeaturesTest,InvalidRequiredLabel)10846 TEST_F(FeaturesTest, InvalidRequiredLabel) {
10847   BuildDescriptorMessagesInTestPool();
10848   BuildFileWithErrors(
10849       R"pb(
10850         name: "foo.proto"
10851         syntax: "editions"
10852         edition: EDITION_2023
10853         message_type {
10854           name: "Foo"
10855           field {
10856             name: "bar"
10857             number: 1
10858             label: LABEL_REQUIRED
10859             type: TYPE_STRING
10860           }
10861         }
10862       )pb",
10863       "foo.proto: Foo.bar: NAME: Required label is not allowed under editions. "
10864       " Use the feature field_presence = LEGACY_REQUIRED to control this "
10865       "behavior.\n");
10866 }
10867 
TEST_F(FeaturesTest,InvalidGroupLabel)10868 TEST_F(FeaturesTest, InvalidGroupLabel) {
10869   BuildDescriptorMessagesInTestPool();
10870   BuildFileWithErrors(
10871       R"pb(
10872         name: "foo.proto"
10873         syntax: "editions"
10874         edition: EDITION_2023
10875         message_type {
10876           name: "Foo"
10877           field {
10878             name: "bar"
10879             number: 1
10880             type_name: ".Foo"
10881             label: LABEL_OPTIONAL
10882             type: TYPE_GROUP
10883           }
10884         }
10885       )pb",
10886       "foo.proto: Foo.bar: NAME: Group types are not allowed under editions.  "
10887       "Use the feature message_encoding = DELIMITED to control this "
10888       "behavior.\n");
10889 }
10890 
TEST_F(FeaturesTest,DeprecatedFeature)10891 TEST_F(FeaturesTest, DeprecatedFeature) {
10892   pool_.AddDirectInputFile("foo.proto");
10893   BuildDescriptorMessagesInTestPool();
10894   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
10895   BuildFileWithWarnings(
10896       R"pb(
10897         name: "foo.proto"
10898         syntax: "editions"
10899         edition: EDITION_2023
10900         dependency: "google/protobuf/unittest_features.proto"
10901         options {
10902           uninterpreted_option {
10903             name { name_part: "features" is_extension: false }
10904             name { name_part: "pb.test" is_extension: true }
10905             name { name_part: "removed_feature" is_extension: false }
10906             identifier_value: "VALUE9"
10907           }
10908         }
10909       )pb",
10910       "foo.proto: foo.proto: NAME: Feature "
10911       "pb.TestFeatures.removed_feature has been deprecated in edition 2023: "
10912       "Custom feature deprecation warning\n");
10913   const FileDescriptor* file = pool_.FindFileByName("foo.proto");
10914   ASSERT_THAT(file, NotNull());
10915 
10916   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).removed_feature(),
10917             pb::VALUE9);
10918 }
10919 
TEST_F(FeaturesTest,IgnoreDeprecatedFeature)10920 TEST_F(FeaturesTest, IgnoreDeprecatedFeature) {
10921   BuildDescriptorMessagesInTestPool();
10922   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
10923   BuildFileWithWarnings(
10924       R"pb(
10925         name: "foo.proto"
10926         syntax: "editions"
10927         edition: EDITION_2023
10928         dependency: "google/protobuf/unittest_features.proto"
10929         options {
10930           uninterpreted_option {
10931             name { name_part: "features" is_extension: false }
10932             name { name_part: "pb.test" is_extension: true }
10933             name { name_part: "removed_feature" is_extension: false }
10934             identifier_value: "VALUE9"
10935           }
10936         }
10937       )pb",
10938       "");
10939 }
10940 
TEST_F(FeaturesTest,IgnoreTransitiveFeature)10941 TEST_F(FeaturesTest, IgnoreTransitiveFeature) {
10942   pool_.AddDirectInputFile("bar.proto");
10943   BuildDescriptorMessagesInTestPool();
10944   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
10945   BuildFileWithWarnings(
10946       R"pb(
10947         name: "foo.proto"
10948         syntax: "editions"
10949         edition: EDITION_2023
10950         dependency: "google/protobuf/unittest_features.proto"
10951         options {
10952           uninterpreted_option {
10953             name { name_part: "features" is_extension: false }
10954             name { name_part: "pb.test" is_extension: true }
10955             name { name_part: "removed_feature" is_extension: false }
10956             identifier_value: "VALUE9"
10957           }
10958         }
10959         message_type { name: "Foo" }
10960       )pb",
10961       "");
10962   BuildFileWithWarnings(
10963       R"pb(
10964         name: "bar.proto"
10965         syntax: "editions"
10966         edition: EDITION_2023
10967         dependency: "foo.proto"
10968         message_type {
10969           name: "Bar"
10970           field {
10971             name: "bar"
10972             number: 1
10973             label: LABEL_OPTIONAL
10974             type: TYPE_MESSAGE
10975             type_name: ".Foo"
10976           }
10977         }
10978       )pb",
10979       "");
10980 }
10981 
TEST_F(FeaturesTest,RemovedFeature)10982 TEST_F(FeaturesTest, RemovedFeature) {
10983   BuildDescriptorMessagesInTestPool();
10984   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
10985   BuildFileWithErrors(
10986       R"pb(
10987         name: "foo.proto"
10988         syntax: "editions"
10989         edition: EDITION_2024
10990         dependency: "google/protobuf/unittest_features.proto"
10991         options {
10992           features {
10993             [pb.test] { removed_feature: VALUE9 }
10994           }
10995         }
10996       )pb",
10997       "foo.proto: foo.proto: NAME: Feature "
10998       "pb.TestFeatures.removed_feature has been removed in edition 2024 and "
10999       "can't be used in edition 2024\n");
11000 }
11001 
TEST_F(FeaturesTest,RemovedFeatureDefault)11002 TEST_F(FeaturesTest, RemovedFeatureDefault) {
11003   BuildDescriptorMessagesInTestPool();
11004   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
11005   const FileDescriptor* file =
11006       BuildFile(R"pb(
11007         name: "foo.proto" syntax: "editions" edition: EDITION_2024
11008       )pb");
11009   ASSERT_THAT(file, NotNull());
11010   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).removed_feature(),
11011             pb::VALUE3);
11012 }
11013 
TEST_F(FeaturesTest,FutureFeature)11014 TEST_F(FeaturesTest, FutureFeature) {
11015   BuildDescriptorMessagesInTestPool();
11016   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
11017   BuildFileWithErrors(
11018       R"pb(
11019         name: "foo.proto"
11020         syntax: "editions"
11021         edition: EDITION_2023
11022         dependency: "google/protobuf/unittest_features.proto"
11023         options {
11024           features {
11025             [pb.test] { future_feature: VALUE9 }
11026           }
11027         }
11028       )pb",
11029       "foo.proto: foo.proto: NAME: Feature "
11030       "pb.TestFeatures.future_feature wasn't introduced until edition 2024 and "
11031       "can't be used in edition 2023\n");
11032 }
11033 
TEST_F(FeaturesTest,FutureFeatureDefault)11034 TEST_F(FeaturesTest, FutureFeatureDefault) {
11035   BuildDescriptorMessagesInTestPool();
11036   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
11037   const FileDescriptor* file =
11038       BuildFile(R"pb(
11039         name: "foo.proto" syntax: "editions" edition: EDITION_2023
11040       )pb");
11041   ASSERT_THAT(file, NotNull());
11042   EXPECT_EQ(GetFeatures(file).GetExtension(pb::test).future_feature(),
11043             pb::VALUE1);
11044 }
11045 
11046 // Test that the result of FileDescriptor::DebugString() can be used to create
11047 // the original descriptors.
11048 class FeaturesDebugStringTest
11049     : public FeaturesTest,
11050       public testing::WithParamInterface<
11051           std::tuple<absl::string_view, absl::string_view>> {
11052  protected:
LoadFile(absl::string_view name,absl::string_view content)11053   const FileDescriptor* LoadFile(absl::string_view name,
11054                                  absl::string_view content) {
11055     io::ArrayInputStream input_stream(content.data(), content.size());
11056     SimpleErrorCollector error_collector;
11057     io::Tokenizer tokenizer(&input_stream, &error_collector);
11058     compiler::Parser parser;
11059     parser.RecordErrorsTo(&error_collector);
11060     FileDescriptorProto proto;
11061     ABSL_CHECK(parser.Parse(&tokenizer, &proto))
11062         << error_collector.last_error() << "\n"
11063         << content;
11064     ABSL_CHECK_EQ("", error_collector.last_error());
11065     proto.set_name(name);
11066     return ABSL_DIE_IF_NULL(roundtrip_pool_.BuildFile(proto));
11067   }
11068 
GetFileProto()11069   std::string GetFileProto() { return std::string(std::get<1>(GetParam())); }
11070 
EqualsRoundTrip()11071   auto EqualsRoundTrip() { return EqualsProto(std::get<1>(GetParam())); }
11072 
11073  private:
11074   DescriptorPool roundtrip_pool_;
11075 };
11076 
TEST_P(FeaturesDebugStringTest,RoundTrip)11077 TEST_P(FeaturesDebugStringTest, RoundTrip) {
11078   BuildDescriptorMessagesInTestPool();
11079   BuildFileInTestPool(pb::TestFeatures::descriptor()->file());
11080   const FileDescriptor* file = BuildFile(GetFileProto());
11081   ASSERT_THAT(file, NotNull());
11082 
11083   LoadFile("google/protobuf/descriptor.proto",
11084            DescriptorProto::GetDescriptor()->file()->DebugString());
11085   LoadFile("google/protobuf/unittest_features.proto",
11086            pb::TestFeatures::GetDescriptor()->file()->DebugString());
11087   const FileDescriptor* roundtripped =
11088       LoadFile(file->name(), file->DebugString());
11089 
11090   FileDescriptorProto roundtripped_proto;
11091   roundtripped->CopyTo(&roundtripped_proto);
11092   EXPECT_THAT(roundtripped_proto, EqualsRoundTrip())
11093       << "With generated proto file: \n"
11094       << file->DebugString();
11095 }
11096 
11097 INSTANTIATE_TEST_SUITE_P(
11098     FeaturesDebugStringTestInst, FeaturesDebugStringTest,
11099     testing::Values(
11100         std::make_tuple("Empty", R"pb(name: "foo.proto"
11101                                       syntax: "editions"
11102                                       edition: EDITION_2023
11103         )pb"),
11104         std::make_tuple(
11105             "FileFeature",
11106             R"pb(name: "foo.proto"
11107                  syntax: "editions"
11108                  edition: EDITION_2023
11109                  dependency: "google/protobuf/unittest_features.proto"
11110                  options {
11111                    features {
11112                      [pb.test] { file_feature: VALUE3 }
11113                    }
11114                  }
11115             )pb"),
11116         std::make_tuple("FieldFeature",
11117                         R"pb(name: "foo.proto"
11118                              syntax: "editions"
11119                              edition: EDITION_2023
11120                              message_type {
11121                                name: "Foo"
11122                                field {
11123                                  name: "bar"
11124                                  number: 1
11125                                  label: LABEL_OPTIONAL
11126                                  type: TYPE_INT64
11127                                  options {
11128                                    features { field_presence: IMPLICIT }
11129                                  }
11130                                }
11131                              }
11132                         )pb"),
11133         std::make_tuple("Required",
11134                         R"pb(name: "foo.proto"
11135                              syntax: "editions"
11136                              edition: EDITION_2023
11137                              message_type {
11138                                name: "Foo"
11139                                field {
11140                                  name: "bar"
11141                                  number: 1
11142                                  label: LABEL_OPTIONAL
11143                                  type: TYPE_INT64
11144                                  options {
11145                                    features { field_presence: LEGACY_REQUIRED }
11146                                  }
11147                                }
11148                              }
11149                         )pb"),
11150         std::make_tuple("Group",
11151                         R"pb(name: "foo.proto"
11152                              syntax: "editions"
11153                              edition: EDITION_2023
11154                              message_type {
11155                                name: "Foo"
11156                                nested_type {
11157                                  name: "Bar"
11158                                  field {
11159                                    name: "baz"
11160                                    number: 1
11161                                    label: LABEL_OPTIONAL
11162                                    type: TYPE_INT32
11163                                  }
11164                                }
11165                                field {
11166                                  name: "bar"
11167                                  number: 1
11168                                  label: LABEL_OPTIONAL
11169                                  type: TYPE_MESSAGE
11170                                  type_name: ".Foo.Bar"
11171                                  options {
11172                                    features { message_encoding: DELIMITED }
11173                                  }
11174                                }
11175                              }
11176                         )pb"),
11177         std::make_tuple("MessageFeature",
11178                         R"pb(name: "foo.proto"
11179                              syntax: "editions"
11180                              edition: EDITION_2023
11181                              message_type {
11182                                name: "Foo"
11183                                options {
11184                                  features { json_format: LEGACY_BEST_EFFORT }
11185                                }
11186                              }
11187                         )pb"),
11188         std::make_tuple(
11189             "OneofFeature",
11190             R"pb(name: "foo.proto"
11191                  syntax: "editions"
11192                  edition: EDITION_2023
11193                  dependency: "google/protobuf/unittest_features.proto"
11194                  message_type {
11195                    name: "Foo"
11196                    field {
11197                      name: "bar"
11198                      number: 2
11199                      label: LABEL_OPTIONAL
11200                      type: TYPE_INT64
11201                      oneof_index: 0
11202                    }
11203                    oneof_decl {
11204                      name: "foo_oneof"
11205                      options {
11206                        features {
11207                          [pb.test] { oneof_feature: VALUE7 }
11208                        }
11209                      }
11210                    }
11211                  })pb"),
11212         std::make_tuple(
11213             "ExtensionRangeFeature",
11214             R"pb(name: "foo.proto"
11215                  syntax: "editions"
11216                  edition: EDITION_2023
11217                  dependency: "google/protobuf/unittest_features.proto"
11218                  message_type {
11219                    name: "Foo"
11220                    extension_range {
11221                      start: 10
11222                      end: 100
11223                      options {
11224                        features {
11225                          [pb.test] { extension_range_feature: VALUE15 }
11226                        }
11227                      }
11228                    }
11229                  }
11230             )pb"),
11231         std::make_tuple("EnumFeature",
11232                         R"pb(name: "foo.proto"
11233                              syntax: "editions"
11234                              edition: EDITION_2023
11235                              enum_type {
11236                                name: "Foo"
11237                                value { name: "BAR" number: 1 }
11238                                options { features { enum_type: CLOSED } }
11239                              }
11240                         )pb"),
11241         std::make_tuple(
11242             "EnumValueFeature",
11243             R"pb(name: "foo.proto"
11244                  syntax: "editions"
11245                  edition: EDITION_2023
11246                  dependency: "google/protobuf/unittest_features.proto"
11247                  enum_type {
11248                    name: "Foo"
11249                    value {
11250                      name: "BAR"
11251                      number: 0
11252                      options {
11253                        features {
11254                          [pb.test] { enum_entry_feature: VALUE1 }
11255                        }
11256                      }
11257                    }
11258 
11259                  }
11260             )pb"),
11261         std::make_tuple(
11262             "ServiceFeature",
11263             R"pb(name: "foo.proto"
11264                  syntax: "editions"
11265                  edition: EDITION_2023
11266                  dependency: "google/protobuf/unittest_features.proto"
11267                  service {
11268                    name: "FooService"
11269                    options {
11270                      features {
11271                        [pb.test] { service_feature: VALUE11 }
11272                      }
11273                    }
11274                  }
11275             )pb"),
11276         std::make_tuple(
11277             "MethodFeature",
11278             R"pb(name: "foo.proto"
11279                  syntax: "editions"
11280                  edition: EDITION_2023
11281                  dependency: "google/protobuf/unittest_features.proto"
11282                  message_type { name: "EmptyMessage" }
11283                  service {
11284                    name: "FooService"
11285                    method {
11286                      name: "BarMethod"
11287                      input_type: ".EmptyMessage"
11288                      output_type: ".EmptyMessage"
11289                      options {
11290                        features {
11291                          [pb.test] { method_feature: VALUE12 }
11292                        }
11293                      }
11294                    }
11295                  })pb")),
11296     [](const ::testing::TestParamInfo<FeaturesDebugStringTest::ParamType>&
__anon064ad7990702(const ::testing::TestParamInfo<FeaturesDebugStringTest::ParamType>& info) 11297            info) { return std::string(std::get<0>(info.param)); });
11298 
11299 using DescriptorPoolFeaturesTest = FeaturesBaseTest;
11300 
TEST_F(DescriptorPoolFeaturesTest,BuildStarted)11301 TEST_F(DescriptorPoolFeaturesTest, BuildStarted) {
11302   BuildDescriptorMessagesInTestPool();
11303   FeatureSetDefaults defaults = ParseTextOrDie(R"pb()pb");
11304   EXPECT_THAT(pool_.SetFeatureSetDefaults(std::move(defaults)),
11305               StatusIs(absl::StatusCode::kFailedPrecondition,
11306                        HasSubstr("defaults can't be changed")));
11307 }
11308 
TEST_F(DescriptorPoolFeaturesTest,InvalidRange)11309 TEST_F(DescriptorPoolFeaturesTest, InvalidRange) {
11310   FeatureSetDefaults defaults = ParseTextOrDie(R"pb(
11311     minimum_edition: EDITION_2023
11312     maximum_edition: EDITION_PROTO2
11313   )pb");
11314   EXPECT_THAT(pool_.SetFeatureSetDefaults(std::move(defaults)),
11315               StatusIs(absl::StatusCode::kInvalidArgument,
11316                        AllOf(HasSubstr("Invalid edition range"),
11317                              HasSubstr("PROTO2"), HasSubstr("2023"))));
11318 }
11319 
TEST_F(DescriptorPoolFeaturesTest,UnknownDefaults)11320 TEST_F(DescriptorPoolFeaturesTest, UnknownDefaults) {
11321   FeatureSetDefaults defaults = ParseTextOrDie(R"pb(
11322     defaults {
11323       edition: EDITION_UNKNOWN
11324       overridable_features {}
11325     }
11326     minimum_edition: EDITION_PROTO2
11327     maximum_edition: EDITION_2023
11328   )pb");
11329   EXPECT_THAT(pool_.SetFeatureSetDefaults(std::move(defaults)),
11330               StatusIs(absl::StatusCode::kInvalidArgument,
11331                        AllOf(HasSubstr("Invalid edition UNKNOWN"))));
11332 }
11333 
TEST_F(DescriptorPoolFeaturesTest,NotStrictlyIncreasing)11334 TEST_F(DescriptorPoolFeaturesTest, NotStrictlyIncreasing) {
11335   FeatureSetDefaults defaults = ParseTextOrDie(R"pb(
11336     defaults {
11337       edition: EDITION_PROTO3
11338       overridable_features {}
11339     }
11340     defaults {
11341       edition: EDITION_PROTO2
11342       overridable_features {}
11343     }
11344     minimum_edition: EDITION_PROTO2
11345     maximum_edition: EDITION_2023
11346   )pb");
11347   EXPECT_THAT(
11348       pool_.SetFeatureSetDefaults(std::move(defaults)),
11349       StatusIs(
11350           absl::StatusCode::kInvalidArgument,
11351           AllOf(
11352               HasSubstr("not strictly increasing"),
11353               HasSubstr("PROTO3 is greater than or equal to edition PROTO2"))));
11354 }
11355 
TEST_F(DescriptorPoolFeaturesTest,OverrideDefaults)11356 TEST_F(DescriptorPoolFeaturesTest, OverrideDefaults) {
11357   FeatureSetDefaults defaults = ParseTextOrDie(R"pb(
11358     defaults {
11359       edition: EDITION_PROTO2
11360       overridable_features {
11361         field_presence: EXPLICIT
11362         enum_type: CLOSED
11363         repeated_field_encoding: EXPANDED
11364         utf8_validation: VERIFY
11365         message_encoding: LENGTH_PREFIXED
11366         json_format: ALLOW
11367       }
11368     }
11369     minimum_edition: EDITION_PROTO2
11370     maximum_edition: EDITION_2023
11371   )pb");
11372   EXPECT_OK(pool_.SetFeatureSetDefaults(std::move(defaults)));
11373 
11374   FileDescriptorProto file_proto = ParseTextOrDie(R"pb(
11375     name: "foo.proto"
11376     syntax: "editions"
11377     edition: EDITION_PROTO3
11378   )pb");
11379 
11380   BuildDescriptorMessagesInTestPool();
11381   const FileDescriptor* file = ABSL_DIE_IF_NULL(pool_.BuildFile(file_proto));
11382   EXPECT_THAT(GetFeatures(file), EqualsProto(R"pb(
11383                 field_presence: EXPLICIT
11384                 enum_type: CLOSED
11385                 repeated_field_encoding: EXPANDED
11386                 utf8_validation: VERIFY
11387                 message_encoding: LENGTH_PREFIXED
11388                 json_format: ALLOW
11389               )pb"));
11390 }
11391 
11392 
11393 
11394 
TEST_F(ValidationErrorTest,ExtensionDeclarationsMatchFullNameCompile)11395 TEST_F(ValidationErrorTest, ExtensionDeclarationsMatchFullNameCompile) {
11396   BuildFile(R"pb(
11397     name: "foo.proto"
11398     package: "ext.test"
11399     message_type {
11400       name: "Foo"
11401       extension_range {
11402         start: 11
11403         end: 999
11404         options: {
11405           declaration: {
11406             number: 100
11407             full_name: ".ext.test.foo"
11408             type: ".ext.test.Bar"
11409           }
11410         }
11411       }
11412     }
11413     message_type { name: "Bar" }
11414     extension { extendee: "Foo" name: "foo" number: 100 type_name: "Bar" }
11415   )pb");
11416 }
11417 
TEST_F(ValidationErrorTest,ExtensionDeclarationsMismatchFullName)11418 TEST_F(ValidationErrorTest, ExtensionDeclarationsMismatchFullName) {
11419   BuildFileWithErrors(
11420       R"pb(
11421         name: "foo.proto"
11422         package: "ext.test"
11423         message_type {
11424           name: "Foo"
11425           extension_range {
11426             start: 11
11427             end: 999
11428             options: {
11429               declaration: {
11430                 number: 100
11431                 full_name: ".ext.test.buz"
11432                 type: ".ext.test.Bar"
11433               }
11434             }
11435           }
11436         }
11437         message_type { name: "Bar" }
11438         extension { extendee: "Foo" name: "foo" number: 100 type_name: "Bar" }
11439       )pb",
11440       "foo.proto: ext.test.foo: EXTENDEE: \"ext.test.Foo\" extension field 100"
11441       " is expected to have field name \".ext.test.buz\", not "
11442       "\".ext.test.foo\".\n");
11443 }
11444 
TEST_F(ValidationErrorTest,ExtensionDeclarationsMismatchFullNameAllowed)11445 TEST_F(ValidationErrorTest, ExtensionDeclarationsMismatchFullNameAllowed) {
11446   // Make sure that extension declaration names and types are not validated
11447   // outside of protoc. This is important for allowing extensions to be renamed
11448   // safely.
11449   pool_.EnforceExtensionDeclarations(false);
11450   BuildFile(
11451       R"pb(
11452         name: "foo.proto"
11453         package: "ext.test"
11454         message_type {
11455           name: "Foo"
11456           extension_range {
11457             start: 11
11458             end: 999
11459             options: {
11460               declaration: {
11461                 number: 100
11462                 full_name: ".ext.test.buz"
11463                 type: ".ext.test.Bar"
11464               }
11465             }
11466           }
11467         }
11468         message_type { name: "Bar" }
11469         extension { extendee: "Foo" name: "foo" number: 100 type_name: "Bar" }
11470       )pb");
11471 }
11472 
TEST_F(ValidationErrorTest,ExtensionDeclarationsFullNameDoesNotLookLikeIdentifier)11473 TEST_F(ValidationErrorTest,
11474        ExtensionDeclarationsFullNameDoesNotLookLikeIdentifier) {
11475   BuildFileWithErrors(
11476       R"pb(
11477         name: "foo.proto"
11478         message_type {
11479           name: "Foo"
11480           extension_range {
11481             start: 10
11482             end: 11
11483             options: {
11484               declaration: {
11485                 number: 10
11486                 full_name: ".ext..test.bar"
11487                 type: ".baz"
11488               }
11489             }
11490           }
11491         }
11492       )pb",
11493       "foo.proto: Foo: NAME: \".ext..test.bar\" contains invalid "
11494       "identifiers.\n");
11495 }
11496 
TEST_F(ValidationErrorTest,ExtensionDeclarationsDuplicateNames)11497 TEST_F(ValidationErrorTest, ExtensionDeclarationsDuplicateNames) {
11498   BuildFileWithErrors(
11499       R"pb(
11500         name: "foo.proto"
11501         message_type {
11502           name: "Foo"
11503           extension_range {
11504             start: 11
11505             end: 1000
11506             options: {
11507               declaration: {
11508                 number: 123
11509                 full_name: ".foo.Bar.baz",
11510                 type: ".Bar"
11511               }
11512               declaration: {
11513                 number: 999
11514                 full_name: ".foo.Bar.baz",
11515                 type: "int32"
11516               }
11517             }
11518           }
11519         }
11520       )pb",
11521       "foo.proto: .foo.Bar.baz: NAME: Extension field name \".foo.Bar.baz\" is "
11522       "declared multiple times.\n");
11523 }
11524 
TEST_F(ValidationErrorTest,ExtensionDeclarationMissingFullNameOrType)11525 TEST_F(ValidationErrorTest, ExtensionDeclarationMissingFullNameOrType) {
11526   BuildFileWithErrors(
11527       R"pb(
11528         name: "foo.proto"
11529         message_type {
11530           name: "Foo"
11531           extension_range {
11532             start: 10
11533             end: 11
11534             options: { declaration: { number: 10 full_name: ".foo.Bar.foo" } }
11535           }
11536           extension_range {
11537             start: 11
11538             end: 12
11539             options: { declaration: { number: 11 type: ".Baz" } }
11540           }
11541         }
11542       )pb",
11543       "foo.proto: Foo: EXTENDEE: Extension declaration #10 should have both"
11544       " \"full_name\" and \"type\" set.\n"
11545       "foo.proto: Foo: EXTENDEE: Extension declaration #11 should have both"
11546       " \"full_name\" and \"type\" set.\n");
11547 }
11548 
TEST_F(ValidationErrorTest,ExtensionDeclarationsNumberNotInRange)11549 TEST_F(ValidationErrorTest, ExtensionDeclarationsNumberNotInRange) {
11550   BuildFileWithErrors(
11551       R"pb(
11552         name: "foo.proto"
11553         message_type {
11554           name: "Foo"
11555           extension_range {
11556             start: 4
11557             end: 9999
11558             options: {
11559               declaration: { number: 9999 full_name: ".abc" type: ".Bar" }
11560             }
11561           }
11562         }
11563       )pb",
11564       "foo.proto: Foo: NUMBER: Extension declaration number 9999 is not in the "
11565       "extension range.\n");
11566 }
11567 
TEST_F(ValidationErrorTest,ExtensionDeclarationsFullNameMissingLeadingDot)11568 TEST_F(ValidationErrorTest, ExtensionDeclarationsFullNameMissingLeadingDot) {
11569   BuildFileWithErrors(
11570       R"pb(
11571         name: "foo.proto"
11572         message_type {
11573           name: "Foo"
11574           extension_range {
11575             start: 4
11576             end: 9999
11577             options: {
11578               declaration: { number: 10 full_name: "bar" type: "fixed64" }
11579             }
11580           }
11581         }
11582       )pb",
11583       "foo.proto: Foo: NAME: \"bar\" must have a leading dot to indicate the "
11584       "fully-qualified scope.\n");
11585 }
11586 
11587 struct ExtensionDeclarationsTestParams {
11588   std::string test_name;
11589 };
11590 
11591 // For OSS, we only have declaration to test with.
11592 using ExtensionDeclarationsTest =
11593     testing::TestWithParam<ExtensionDeclarationsTestParams>;
11594 
11595 // For OSS, this is a function that directly returns the parsed
11596 // FileDescriptorProto.
ParameterizeFileProto(absl::string_view file_text,const ExtensionDeclarationsTestParams & param)11597 absl::StatusOr<FileDescriptorProto> ParameterizeFileProto(
11598     absl::string_view file_text, const ExtensionDeclarationsTestParams& param) {
11599   (void)file_text;  // Parameter is used by Google-internal code.
11600   (void)param;      // Parameter is used by Google-internal code.
11601   FileDescriptorProto file_proto;
11602   if (!TextFormat::ParseFromString(file_text, &file_proto)) {
11603     return absl::InvalidArgumentError("Failed to parse the input file text.");
11604   }
11605 
11606   return file_proto;
11607 }
11608 
TEST_P(ExtensionDeclarationsTest,DotPrefixTypeCompile)11609 TEST_P(ExtensionDeclarationsTest, DotPrefixTypeCompile) {
11610   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11611       R"pb(
11612         name: "foo.proto"
11613         package: "ext.test"
11614         message_type {
11615           name: "Foo"
11616           extension_range {
11617             start: 4
11618             end: 99999
11619             options: {
11620               declaration: {
11621                 number: 10
11622                 full_name: ".ext.test.bar"
11623                 type: ".ext.test.Bar"
11624               }
11625             }
11626           }
11627         }
11628         message_type { name: "Bar" }
11629         extension { extendee: "Foo" name: "bar" number: 10 type_name: "Bar" }
11630       )pb",
11631       GetParam());
11632   ASSERT_OK(file_proto);
11633 
11634   DescriptorPool pool;
11635   pool.EnforceExtensionDeclarations(true);
11636   EXPECT_NE(pool.BuildFile(*file_proto), nullptr);
11637 }
11638 
TEST_P(ExtensionDeclarationsTest,EnumTypeCompile)11639 TEST_P(ExtensionDeclarationsTest, EnumTypeCompile) {
11640   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11641       R"pb(
11642         name: "foo.proto"
11643         package: "ext.test"
11644         message_type {
11645           name: "Foo"
11646           extension_range {
11647             start: 4
11648             end: 99999
11649             options: {
11650               declaration: {
11651                 number: 10
11652                 full_name: ".ext.test.bar"
11653                 type: ".ext.test.Bar"
11654               }
11655             }
11656           }
11657         }
11658         enum_type {
11659           name: "Bar"
11660           value: { name: "BUZ" number: 123 }
11661         }
11662         extension { extendee: "Foo" name: "bar" number: 10 type_name: "Bar" }
11663       )pb",
11664       GetParam());
11665   ASSERT_OK(file_proto);
11666 
11667   DescriptorPool pool;
11668   pool.EnforceExtensionDeclarations(true);
11669   EXPECT_NE(pool.BuildFile(*file_proto), nullptr);
11670 }
11671 
TEST_P(ExtensionDeclarationsTest,MismatchEnumType)11672 TEST_P(ExtensionDeclarationsTest, MismatchEnumType) {
11673   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11674       R"pb(
11675         name: "foo.proto"
11676         package: "ext.test"
11677         message_type {
11678           name: "Foo"
11679           extension_range {
11680             start: 4
11681             end: 99999
11682             options: {
11683               declaration: {
11684                 number: 10
11685                 full_name: ".ext.test.bar"
11686                 type: ".ext.test.Bar"
11687               }
11688             }
11689           }
11690         }
11691         enum_type {
11692           name: "Bar"
11693           value: { name: "BUZ1" number: 123 }
11694         }
11695         enum_type {
11696           name: "Abc"
11697           value: { name: "BUZ2" number: 456 }
11698         }
11699         extension { extendee: "Foo" name: "bar" number: 10 type_name: "Abc" }
11700       )pb",
11701       GetParam());
11702   ASSERT_OK(file_proto);
11703 
11704   DescriptorPool pool;
11705   pool.EnforceExtensionDeclarations(true);
11706   MockErrorCollector error_collector;
11707   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11708             nullptr);
11709   EXPECT_EQ(
11710       error_collector.text_,
11711       "foo.proto: ext.test.bar: EXTENDEE: \"ext.test.Foo\" extension field 10 "
11712       "is expected to be type \".ext.test.Bar\", not \".ext.test.Abc\".\n");
11713 }
11714 
TEST_P(ExtensionDeclarationsTest,DotPrefixFullNameCompile)11715 TEST_P(ExtensionDeclarationsTest, DotPrefixFullNameCompile) {
11716   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11717       R"pb(
11718         name: "foo.proto"
11719         package: "ext.test"
11720         message_type {
11721           name: "Foo"
11722           extension_range {
11723             start: 4
11724             end: 99999
11725             options: {
11726               declaration: {
11727                 number: 10
11728                 full_name: ".ext.test.bar"
11729                 type: ".ext.test.Bar"
11730               }
11731             }
11732           }
11733         }
11734         message_type { name: "Bar" }
11735         extension { extendee: "Foo" name: "bar" number: 10 type_name: "Bar" }
11736       )pb",
11737       GetParam());
11738   ASSERT_OK(file_proto);
11739 
11740   DescriptorPool pool;
11741   pool.EnforceExtensionDeclarations(true);
11742   EXPECT_NE(pool.BuildFile(*file_proto), nullptr);
11743 }
11744 
TEST_P(ExtensionDeclarationsTest,MismatchDotPrefixTypeExpectingMessage)11745 TEST_P(ExtensionDeclarationsTest, MismatchDotPrefixTypeExpectingMessage) {
11746   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11747       R"pb(
11748         name: "foo.proto"
11749         package: "ext.test"
11750         message_type {
11751           name: "Foo"
11752           extension_range {
11753             start: 4
11754             end: 99999
11755             options: {
11756               declaration: {
11757                 number: 10
11758                 full_name: ".ext.test.bar"
11759                 type: ".int32"
11760               }
11761             }
11762           }
11763         }
11764         extension { name: "bar" number: 10 type: TYPE_INT32 extendee: "Foo" }
11765       )pb",
11766       GetParam());
11767   ASSERT_OK(file_proto);
11768 
11769   DescriptorPool pool;
11770   pool.EnforceExtensionDeclarations(true);
11771   MockErrorCollector error_collector;
11772   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11773             nullptr);
11774   EXPECT_EQ(error_collector.text_,
11775             "foo.proto: ext.test.bar: EXTENDEE: \"ext.test.Foo\" extension "
11776             "field 10 is expected to be type \".int32\", not \"int32\".\n");
11777 }
11778 
TEST_P(ExtensionDeclarationsTest,MismatchDotPrefixTypeExpectingNonMessage)11779 TEST_P(ExtensionDeclarationsTest, MismatchDotPrefixTypeExpectingNonMessage) {
11780   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11781       R"pb(
11782         name: "foo.proto"
11783         message_type {
11784           name: "Foo"
11785           extension_range {
11786             start: 4
11787             end: 99999
11788             options: {
11789               declaration: { number: 10 full_name: ".bar" type: "int32" }
11790             }
11791           }
11792         }
11793         message_type { name: "int32" }
11794         extension { name: "bar" number: 10 type_name: "int32" extendee: "Foo" }
11795       )pb",
11796       GetParam());
11797   ASSERT_OK(file_proto);
11798 
11799   DescriptorPool pool;
11800   pool.EnforceExtensionDeclarations(true);
11801   MockErrorCollector error_collector;
11802   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11803             nullptr);
11804   EXPECT_EQ(error_collector.text_,
11805             "foo.proto: bar: EXTENDEE: \"Foo\" extension field 10 is expected "
11806             "to be type \"int32\", not \".int32\".\n");
11807 }
11808 
TEST_P(ExtensionDeclarationsTest,MismatchMessageType)11809 TEST_P(ExtensionDeclarationsTest, MismatchMessageType) {
11810   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11811       R"pb(
11812         name: "foo.proto"
11813         package: "ext.test"
11814         message_type {
11815           name: "Foo"
11816           extension_range {
11817             start: 4
11818             end: 99999
11819             options: {
11820               declaration: {
11821                 number: 10
11822                 full_name: ".ext.test.foo"
11823                 type: ".ext.test.Foo"
11824               }
11825             }
11826           }
11827         }
11828         message_type { name: "Bar" }
11829         extension { extendee: "Foo" name: "foo" number: 10 type_name: "Bar" }
11830       )pb",
11831       GetParam());
11832   ASSERT_OK(file_proto);
11833 
11834   DescriptorPool pool;
11835   pool.EnforceExtensionDeclarations(true);
11836   MockErrorCollector error_collector;
11837   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11838             nullptr);
11839   EXPECT_EQ(
11840       error_collector.text_,
11841       "foo.proto: ext.test.foo: EXTENDEE: \"ext.test.Foo\" extension field 10 "
11842       "is expected to be type \".ext.test.Foo\", not \".ext.test.Bar\".\n");
11843 }
11844 
TEST_P(ExtensionDeclarationsTest,NonMessageTypeCompile)11845 TEST_P(ExtensionDeclarationsTest, NonMessageTypeCompile) {
11846   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11847       R"pb(
11848         name: "foo.proto"
11849         message_type {
11850           name: "Foo"
11851           extension_range {
11852             start: 10
11853             end: 11
11854             options: {
11855               declaration: { number: 10 full_name: ".bar" type: "fixed64" }
11856             }
11857           }
11858         }
11859         extension { name: "bar" number: 10 type: TYPE_FIXED64 extendee: "Foo" }
11860       )pb",
11861       GetParam());
11862   ASSERT_OK(file_proto);
11863 
11864   DescriptorPool pool;
11865   pool.EnforceExtensionDeclarations(true);
11866   EXPECT_NE(pool.BuildFile(*file_proto), nullptr);
11867 }
11868 
TEST_P(ExtensionDeclarationsTest,MismatchNonMessageType)11869 TEST_P(ExtensionDeclarationsTest, MismatchNonMessageType) {
11870   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11871       R"pb(
11872         name: "foo.proto"
11873         package: "ext.test"
11874         message_type {
11875           name: "Foo"
11876           extension_range {
11877             start: 10
11878             end: 11
11879             options: {
11880               declaration: {
11881                 number: 10
11882                 full_name: ".ext.test.bar"
11883                 type: "int32"
11884               }
11885             }
11886           }
11887         }
11888         extension { name: "bar" number: 10 type: TYPE_FIXED64 extendee: "Foo" }
11889       )pb",
11890       GetParam());
11891   ASSERT_OK(file_proto);
11892 
11893   DescriptorPool pool;
11894   pool.EnforceExtensionDeclarations(true);
11895   MockErrorCollector error_collector;
11896   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11897             nullptr);
11898   EXPECT_EQ(error_collector.text_,
11899             "foo.proto: ext.test.bar: EXTENDEE: \"ext.test.Foo\" extension "
11900             "field 10 is expected to be type \"int32\", not \"fixed64\".\n");
11901 }
11902 
TEST_P(ExtensionDeclarationsTest,MismatchCardinalityExpectingRepeated)11903 TEST_P(ExtensionDeclarationsTest, MismatchCardinalityExpectingRepeated) {
11904   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11905       R"pb(
11906         name: "foo.proto"
11907         package: "ext.test"
11908         message_type {
11909           name: "Foo"
11910           extension_range {
11911             start: 10
11912             end: 11
11913             options: {
11914               declaration: {
11915                 number: 10
11916                 full_name: ".ext.test.bar"
11917                 type: "fixed64"
11918                 repeated: true
11919               }
11920             }
11921           }
11922         }
11923         extension { name: "bar" number: 10 type: TYPE_FIXED64 extendee: "Foo" }
11924       )pb",
11925       GetParam());
11926   ASSERT_OK(file_proto);
11927 
11928   DescriptorPool pool;
11929   pool.EnforceExtensionDeclarations(true);
11930   MockErrorCollector error_collector;
11931   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11932             nullptr);
11933   EXPECT_EQ(error_collector.text_,
11934             "foo.proto: ext.test.bar: EXTENDEE: \"ext.test.Foo\" extension "
11935             "field 10 is expected to be repeated.\n");
11936 }
11937 
TEST_P(ExtensionDeclarationsTest,MismatchCardinalityExpectingOptional)11938 TEST_P(ExtensionDeclarationsTest, MismatchCardinalityExpectingOptional) {
11939   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11940       R"pb(
11941         name: "foo.proto"
11942         package: "ext.test"
11943         message_type {
11944           name: "Foo"
11945           extension_range {
11946             start: 10
11947             end: 11
11948             options: {
11949               declaration: {
11950                 number: 10
11951                 full_name: ".ext.test.bar"
11952                 type: "fixed64"
11953               }
11954             }
11955           }
11956         }
11957         extension {
11958           name: "bar"
11959           number: 10
11960           type: TYPE_FIXED64
11961           extendee: "Foo"
11962           label: LABEL_REPEATED
11963         }
11964       )pb",
11965       GetParam());
11966   ASSERT_OK(file_proto);
11967 
11968   DescriptorPool pool;
11969   pool.EnforceExtensionDeclarations(true);
11970   MockErrorCollector error_collector;
11971   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
11972             nullptr);
11973   EXPECT_EQ(error_collector.text_,
11974             "foo.proto: ext.test.bar: EXTENDEE: \"ext.test.Foo\" extension "
11975             "field 10 is expected to be optional.\n");
11976 }
11977 
TEST_P(ExtensionDeclarationsTest,TypeDoesNotLookLikeIdentifier)11978 TEST_P(ExtensionDeclarationsTest, TypeDoesNotLookLikeIdentifier) {
11979   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
11980       R"pb(
11981         name: "foo.proto"
11982         message_type {
11983           name: "Foo"
11984           extension_range {
11985             start: 10
11986             end: 11
11987             options: {
11988               declaration: {
11989                 number: 10
11990                 full_name: ".ext.test.bar"
11991                 type: ".b#az"
11992               }
11993             }
11994           }
11995         }
11996       )pb",
11997       GetParam());
11998   ASSERT_OK(file_proto);
11999 
12000   DescriptorPool pool;
12001   pool.EnforceExtensionDeclarations(true);
12002   MockErrorCollector error_collector;
12003   EXPECT_EQ(pool.BuildFileCollectingErrors(*file_proto, &error_collector),
12004             nullptr);
12005   EXPECT_EQ(error_collector.text_,
12006             "foo.proto: Foo: NAME: \".b#az\" contains invalid identifiers.\n");
12007 }
12008 
TEST_P(ExtensionDeclarationsTest,MultipleDeclarationsInARangeCompile)12009 TEST_P(ExtensionDeclarationsTest, MultipleDeclarationsInARangeCompile) {
12010   absl::StatusOr<FileDescriptorProto> file_proto = ParameterizeFileProto(
12011       R"pb(
12012         name: "foo.proto"
12013         package: "ext.test"
12014         message_type {
12015           name: "Foo"
12016           extension_range {
12017             start: 4
12018             end: 99999
12019             options: {
12020               declaration: {
12021                 number: 10
12022                 full_name: ".ext.test.foo"
12023                 type: ".ext.test.Bar"
12024               }
12025               declaration: {
12026                 number: 99998
12027                 full_name: ".ext.test.bar"
12028                 type: ".ext.test.Bar"
12029               }
12030               declaration: {
12031                 number: 12345
12032                 full_name: ".ext.test.baz"
12033                 type: ".ext.test.Bar"
12034               }
12035             }
12036           }
12037         }
12038         message_type { name: "Bar" }
12039         extension { extendee: "Foo" name: "foo" number: 10 type_name: "Bar" }
12040         extension { extendee: "Foo" name: "bar" number: 99998 type_name: "Bar" }
12041         extension { extendee: "Foo" name: "baz" number: 12345 type_name: "Bar" }
12042       )pb",
12043       GetParam());
12044   ASSERT_OK(file_proto);
12045 
12046   DescriptorPool pool;
12047   pool.EnforceExtensionDeclarations(true);
12048   EXPECT_NE(pool.BuildFile(*file_proto), nullptr);
12049 }
12050 
12051 INSTANTIATE_TEST_SUITE_P(
12052     ExtensionDeclarationTests, ExtensionDeclarationsTest,
12053     testing::ValuesIn<ExtensionDeclarationsTestParams>({
12054         {"Declaration"},
12055     }),
12056     [](const testing::TestParamInfo<ExtensionDeclarationsTest::ParamType>&
__anon064ad7990802(const testing::TestParamInfo<ExtensionDeclarationsTest::ParamType>& info) 12057            info) { return info.param.test_name; });
12058 
12059 
TEST_F(ValidationErrorTest,PackageTooLong)12060 TEST_F(ValidationErrorTest, PackageTooLong) {
12061   BuildFileWithErrors(
12062       "name: \"foo.proto\" "
12063       "syntax: \"proto3\" "
12064       "package: "
12065       "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12066       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12067       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12068       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12069       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12070       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12071       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12072       "aaaaaaaaaa\"",
12073       "foo.proto: "
12074       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12075       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12076       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12077       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12078       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12079       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12080       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
12081       "aaaaaaaa: NAME: Package name is too long\n");
12082 }
12083 
12084 
12085 // ===================================================================
12086 // DescriptorDatabase
12087 
AddToDatabase(SimpleDescriptorDatabase * database,absl::string_view file_text)12088 static void AddToDatabase(SimpleDescriptorDatabase* database,
12089                           absl::string_view file_text) {
12090   FileDescriptorProto file_proto;
12091   EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
12092   database->Add(file_proto);
12093 }
12094 
12095 class DatabaseBackedPoolTest : public testing::Test {
12096  protected:
12097   DatabaseBackedPoolTest() = default;
12098 
12099   SimpleDescriptorDatabase database_;
12100 
SetUp()12101   void SetUp() override {
12102     AddToDatabase(
12103         &database_,
12104         "name: 'foo.proto' "
12105         "message_type { name:'Foo' extension_range { start: 1 end: 100 } } "
12106         "enum_type { name:'TestEnum' value { name:'DUMMY' number:0 } } "
12107         "service { name:'TestService' } ");
12108     AddToDatabase(&database_,
12109                   "name: 'bar.proto' "
12110                   "dependency: 'foo.proto' "
12111                   "message_type { name:'Bar' } "
12112                   "extension { name:'foo_ext' extendee: '.Foo' number:5 "
12113                   "            label:LABEL_OPTIONAL type:TYPE_INT32 } ");
12114     // Baz has an undeclared dependency on Foo.
12115     AddToDatabase(
12116         &database_,
12117         "name: 'baz.proto' "
12118         "message_type { "
12119         "  name:'Baz' "
12120         "  field { name:'foo' number:1 label:LABEL_OPTIONAL type_name:'Foo' } "
12121         "}");
12122   }
12123 
12124   // We can't inject a file containing errors into a DescriptorPool, so we
12125   // need an actual mock DescriptorDatabase to test errors.
12126   class ErrorDescriptorDatabase : public DescriptorDatabase {
12127    public:
12128     ErrorDescriptorDatabase() = default;
12129     ~ErrorDescriptorDatabase() override = default;
12130 
12131     // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)12132     bool FindFileByName(const std::string& filename,
12133                         FileDescriptorProto* output) override {
12134       // error.proto and error2.proto cyclically import each other.
12135       if (filename == "error.proto") {
12136         output->Clear();
12137         output->set_name("error.proto");
12138         output->add_dependency("error2.proto");
12139         return true;
12140       } else if (filename == "error2.proto") {
12141         output->Clear();
12142         output->set_name("error2.proto");
12143         output->add_dependency("error.proto");
12144         return true;
12145       } else {
12146         return false;
12147       }
12148     }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)12149     bool FindFileContainingSymbol(const std::string& symbol_name,
12150                                   FileDescriptorProto* output) override {
12151       return false;
12152     }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)12153     bool FindFileContainingExtension(const std::string& containing_type,
12154                                      int field_number,
12155                                      FileDescriptorProto* output) override {
12156       return false;
12157     }
12158   };
12159 
12160   // A DescriptorDatabase that counts how many times each method has been
12161   // called and forwards to some other DescriptorDatabase.
12162   class CallCountingDatabase : public DescriptorDatabase {
12163    public:
CallCountingDatabase(DescriptorDatabase * wrapped_db)12164     explicit CallCountingDatabase(DescriptorDatabase* wrapped_db)
12165         : wrapped_db_(wrapped_db) {
12166       Clear();
12167     }
12168     ~CallCountingDatabase() override = default;
12169 
12170     DescriptorDatabase* wrapped_db_;
12171 
12172     int call_count_;
12173 
Clear()12174     void Clear() { call_count_ = 0; }
12175 
12176     // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)12177     bool FindFileByName(const std::string& filename,
12178                         FileDescriptorProto* output) override {
12179       ++call_count_;
12180       return wrapped_db_->FindFileByName(filename, output);
12181     }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)12182     bool FindFileContainingSymbol(const std::string& symbol_name,
12183                                   FileDescriptorProto* output) override {
12184       ++call_count_;
12185       return wrapped_db_->FindFileContainingSymbol(symbol_name, output);
12186     }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)12187     bool FindFileContainingExtension(const std::string& containing_type,
12188                                      int field_number,
12189                                      FileDescriptorProto* output) override {
12190       ++call_count_;
12191       return wrapped_db_->FindFileContainingExtension(containing_type,
12192                                                       field_number, output);
12193     }
12194   };
12195 
12196   // A DescriptorDatabase which falsely always returns foo.proto when searching
12197   // for any symbol or extension number.  This shouldn't cause the
12198   // DescriptorPool to reload foo.proto if it is already loaded.
12199   class FalsePositiveDatabase : public DescriptorDatabase {
12200    public:
FalsePositiveDatabase(DescriptorDatabase * wrapped_db)12201     explicit FalsePositiveDatabase(DescriptorDatabase* wrapped_db)
12202         : wrapped_db_(wrapped_db) {}
12203     ~FalsePositiveDatabase() override = default;
12204 
12205     DescriptorDatabase* wrapped_db_;
12206 
12207     // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)12208     bool FindFileByName(const std::string& filename,
12209                         FileDescriptorProto* output) override {
12210       return wrapped_db_->FindFileByName(filename, output);
12211     }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)12212     bool FindFileContainingSymbol(const std::string& symbol_name,
12213                                   FileDescriptorProto* output) override {
12214       return FindFileByName("foo.proto", output);
12215     }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)12216     bool FindFileContainingExtension(const std::string& containing_type,
12217                                      int field_number,
12218                                      FileDescriptorProto* output) override {
12219       return FindFileByName("foo.proto", output);
12220     }
12221   };
12222 };
12223 
TEST_F(DatabaseBackedPoolTest,FindFileByName)12224 TEST_F(DatabaseBackedPoolTest, FindFileByName) {
12225   DescriptorPool pool(&database_);
12226 
12227   const FileDescriptor* foo = pool.FindFileByName("foo.proto");
12228   ASSERT_TRUE(foo != nullptr);
12229   EXPECT_EQ("foo.proto", foo->name());
12230   ASSERT_EQ(1, foo->message_type_count());
12231   EXPECT_EQ("Foo", foo->message_type(0)->name());
12232 
12233   EXPECT_EQ(foo, pool.FindFileByName("foo.proto"));
12234 
12235   EXPECT_TRUE(pool.FindFileByName("no_such_file.proto") == nullptr);
12236 }
12237 
TEST_F(DatabaseBackedPoolTest,FindDependencyBeforeDependent)12238 TEST_F(DatabaseBackedPoolTest, FindDependencyBeforeDependent) {
12239   DescriptorPool pool(&database_);
12240 
12241   const FileDescriptor* foo = pool.FindFileByName("foo.proto");
12242   ASSERT_TRUE(foo != nullptr);
12243   EXPECT_EQ("foo.proto", foo->name());
12244   ASSERT_EQ(1, foo->message_type_count());
12245   EXPECT_EQ("Foo", foo->message_type(0)->name());
12246 
12247   const FileDescriptor* bar = pool.FindFileByName("bar.proto");
12248   ASSERT_TRUE(bar != nullptr);
12249   EXPECT_EQ("bar.proto", bar->name());
12250   ASSERT_EQ(1, bar->message_type_count());
12251   EXPECT_EQ("Bar", bar->message_type(0)->name());
12252 
12253   ASSERT_EQ(1, bar->dependency_count());
12254   EXPECT_EQ(foo, bar->dependency(0));
12255 }
12256 
TEST_F(DatabaseBackedPoolTest,FindDependentBeforeDependency)12257 TEST_F(DatabaseBackedPoolTest, FindDependentBeforeDependency) {
12258   DescriptorPool pool(&database_);
12259 
12260   const FileDescriptor* bar = pool.FindFileByName("bar.proto");
12261   ASSERT_TRUE(bar != nullptr);
12262   EXPECT_EQ("bar.proto", bar->name());
12263   ASSERT_EQ(1, bar->message_type_count());
12264   ASSERT_EQ("Bar", bar->message_type(0)->name());
12265 
12266   const FileDescriptor* foo = pool.FindFileByName("foo.proto");
12267   ASSERT_TRUE(foo != nullptr);
12268   EXPECT_EQ("foo.proto", foo->name());
12269   ASSERT_EQ(1, foo->message_type_count());
12270   ASSERT_EQ("Foo", foo->message_type(0)->name());
12271 
12272   ASSERT_EQ(1, bar->dependency_count());
12273   EXPECT_EQ(foo, bar->dependency(0));
12274 }
12275 
TEST_F(DatabaseBackedPoolTest,FindFileContainingSymbol)12276 TEST_F(DatabaseBackedPoolTest, FindFileContainingSymbol) {
12277   DescriptorPool pool(&database_);
12278 
12279   const FileDescriptor* file = pool.FindFileContainingSymbol("Foo");
12280   ASSERT_TRUE(file != nullptr);
12281   EXPECT_EQ("foo.proto", file->name());
12282   EXPECT_EQ(file, pool.FindFileByName("foo.proto"));
12283 
12284   EXPECT_TRUE(pool.FindFileContainingSymbol("NoSuchSymbol") == nullptr);
12285 }
12286 
TEST_F(DatabaseBackedPoolTest,FindMessageTypeByName)12287 TEST_F(DatabaseBackedPoolTest, FindMessageTypeByName) {
12288   DescriptorPool pool(&database_);
12289 
12290   const Descriptor* type = pool.FindMessageTypeByName("Foo");
12291   ASSERT_TRUE(type != nullptr);
12292   EXPECT_EQ("Foo", type->name());
12293   EXPECT_EQ(type->file(), pool.FindFileByName("foo.proto"));
12294 
12295   EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchType") == nullptr);
12296 }
12297 
TEST_F(DatabaseBackedPoolTest,FindExtensionByNumber)12298 TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) {
12299   DescriptorPool pool(&database_);
12300 
12301   const Descriptor* foo = pool.FindMessageTypeByName("Foo");
12302   ASSERT_TRUE(foo != nullptr);
12303 
12304   const FieldDescriptor* extension = pool.FindExtensionByNumber(foo, 5);
12305   ASSERT_TRUE(extension != nullptr);
12306   EXPECT_EQ("foo_ext", extension->name());
12307   EXPECT_EQ(extension->file(), pool.FindFileByName("bar.proto"));
12308 
12309   EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == nullptr);
12310 }
12311 
TEST_F(DatabaseBackedPoolTest,FindAllExtensions)12312 TEST_F(DatabaseBackedPoolTest, FindAllExtensions) {
12313   DescriptorPool pool(&database_);
12314 
12315   const Descriptor* foo = pool.FindMessageTypeByName("Foo");
12316 
12317   for (int i = 0; i < 2; ++i) {
12318     // Repeat the lookup twice, to check that we get consistent
12319     // results despite the fallback database lookup mutating the pool.
12320     std::vector<const FieldDescriptor*> extensions;
12321     pool.FindAllExtensions(foo, &extensions);
12322     ASSERT_EQ(1, extensions.size());
12323     EXPECT_EQ(5, extensions[0]->number());
12324   }
12325 }
12326 
TEST_F(DatabaseBackedPoolTest,ErrorWithoutErrorCollector)12327 TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) {
12328   ErrorDescriptorDatabase error_database;
12329   DescriptorPool pool(&error_database);
12330 
12331   {
12332     absl::ScopedMockLog log;
12333     EXPECT_CALL(log, Log(absl::LogSeverity::kError, testing::_, testing::_))
12334         .Times(testing::AtLeast(1));
12335     log.StartCapturingLogs();
12336     EXPECT_TRUE(pool.FindFileByName("error.proto") == nullptr);
12337   }
12338 }
12339 
TEST_F(DatabaseBackedPoolTest,ErrorWithErrorCollector)12340 TEST_F(DatabaseBackedPoolTest, ErrorWithErrorCollector) {
12341   ErrorDescriptorDatabase error_database;
12342   MockErrorCollector error_collector;
12343   DescriptorPool pool(&error_database, &error_collector);
12344 
12345   EXPECT_TRUE(pool.FindFileByName("error.proto") == nullptr);
12346   EXPECT_EQ(
12347       "error.proto: error2.proto: IMPORT: File recursively imports itself: "
12348       "error.proto -> error2.proto -> error.proto\n"
12349       "error2.proto: error.proto: IMPORT: Import \"error.proto\" was not "
12350       "found or had errors.\n"
12351       "error.proto: error2.proto: IMPORT: Import \"error2.proto\" was not "
12352       "found or had errors.\n",
12353       error_collector.text_);
12354 }
12355 
TEST_F(DatabaseBackedPoolTest,UndeclaredDependencyOnUnbuiltType)12356 TEST_F(DatabaseBackedPoolTest, UndeclaredDependencyOnUnbuiltType) {
12357   // Check that we find and report undeclared dependencies on types that exist
12358   // in the descriptor database but that have not been built yet.
12359   MockErrorCollector error_collector;
12360   DescriptorPool pool(&database_, &error_collector);
12361   EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
12362   EXPECT_EQ(
12363       "baz.proto: Baz.foo: TYPE: \"Foo\" seems to be defined in \"foo.proto\", "
12364       "which is not imported by \"baz.proto\".  To use it here, please add "
12365       "the necessary import.\n",
12366       error_collector.text_);
12367 }
12368 
TEST_F(DatabaseBackedPoolTest,RollbackAfterError)12369 TEST_F(DatabaseBackedPoolTest, RollbackAfterError) {
12370   // Make sure that all traces of bad types are removed from the pool. This used
12371   // to be b/4529436, due to the fact that a symbol resolution failure could
12372   // potentially cause another file to be recursively built, which would trigger
12373   // a checkpoint _past_ possibly invalid symbols.
12374   // Baz is defined in the database, but the file is invalid because it is
12375   // missing a necessary import.
12376   DescriptorPool pool(&database_);
12377   EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
12378   // Make sure that searching again for the file or the type fails.
12379   EXPECT_TRUE(pool.FindFileByName("baz.proto") == nullptr);
12380   EXPECT_TRUE(pool.FindMessageTypeByName("Baz") == nullptr);
12381 }
12382 
TEST_F(DatabaseBackedPoolTest,UnittestProto)12383 TEST_F(DatabaseBackedPoolTest, UnittestProto) {
12384   // Try to load all of unittest.proto from a DescriptorDatabase.  This should
12385   // thoroughly test all paths through DescriptorBuilder to insure that there
12386   // are no deadlocking problems when pool_->mutex_ is non-null.
12387   const FileDescriptor* original_file =
12388       protobuf_unittest::TestAllTypes::descriptor()->file();
12389 
12390   DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
12391   DescriptorPool pool(&database);
12392   const FileDescriptor* file_from_database =
12393       pool.FindFileByName(original_file->name());
12394 
12395   ASSERT_TRUE(file_from_database != nullptr);
12396 
12397   FileDescriptorProto original_file_proto;
12398   original_file->CopyTo(&original_file_proto);
12399 
12400   FileDescriptorProto file_from_database_proto;
12401   file_from_database->CopyTo(&file_from_database_proto);
12402 
12403   EXPECT_EQ(original_file_proto.DebugString(),
12404             file_from_database_proto.DebugString());
12405 
12406   // Also verify that CopyTo() did not omit any information.
12407   EXPECT_EQ(original_file->DebugString(), file_from_database->DebugString());
12408 }
12409 
TEST_F(DatabaseBackedPoolTest,FeatureResolution)12410 TEST_F(DatabaseBackedPoolTest, FeatureResolution) {
12411   {
12412     FileDescriptorProto proto;
12413     FileDescriptorProto::descriptor()->file()->CopyTo(&proto);
12414     std::string text_proto;
12415     google::protobuf::TextFormat::PrintToString(proto, &text_proto);
12416     AddToDatabase(&database_, text_proto);
12417   }
12418   {
12419     FileDescriptorProto proto;
12420     pb::TestFeatures::descriptor()->file()->CopyTo(&proto);
12421     std::string text_proto;
12422     google::protobuf::TextFormat::PrintToString(proto, &text_proto);
12423     AddToDatabase(&database_, text_proto);
12424   }
12425   AddToDatabase(&database_, R"pb(
12426     name: "features.proto"
12427     syntax: "editions"
12428     edition: EDITION_2023
12429     dependency: "google/protobuf/unittest_features.proto"
12430     options {
12431       features {
12432         enum_type: CLOSED
12433         [pb.test] { file_feature: VALUE9 multiple_feature: VALUE9 }
12434       }
12435     }
12436     message_type {
12437       name: "FooFeatures"
12438       options {
12439         features {
12440           [pb.test] { message_feature: VALUE8 multiple_feature: VALUE8 }
12441         }
12442       }
12443     }
12444   )pb");
12445   MockErrorCollector error_collector;
12446   DescriptorPool pool(&database_, &error_collector);
12447 
12448   auto default_spec = FeatureResolver::CompileDefaults(
12449       FeatureSet::descriptor(),
12450       {GetExtensionReflection(pb::cpp), GetExtensionReflection(pb::test)},
12451       EDITION_PROTO2, EDITION_99999_TEST_ONLY);
12452   ASSERT_OK(default_spec);
12453   ASSERT_OK(pool.SetFeatureSetDefaults(std::move(default_spec).value()));
12454 
12455   const Descriptor* foo = pool.FindMessageTypeByName("FooFeatures");
12456   ASSERT_TRUE(foo != nullptr);
12457   EXPECT_EQ(GetFeatures(foo).enum_type(), FeatureSet::CLOSED);
12458   EXPECT_EQ(GetFeatures(foo).repeated_field_encoding(), FeatureSet::PACKED);
12459   EXPECT_EQ(GetFeatures(foo).GetExtension(pb::test).enum_feature(), pb::VALUE1);
12460   EXPECT_EQ(GetFeatures(foo).GetExtension(pb::test).file_feature(), pb::VALUE9);
12461   EXPECT_EQ(GetFeatures(foo).GetExtension(pb::test).message_feature(),
12462             pb::VALUE8);
12463   EXPECT_EQ(GetFeatures(foo).GetExtension(pb::test).multiple_feature(),
12464             pb::VALUE8);
12465 }
12466 
TEST_F(DatabaseBackedPoolTest,FeatureLifetimeError)12467 TEST_F(DatabaseBackedPoolTest, FeatureLifetimeError) {
12468   {
12469     FileDescriptorProto proto;
12470     FileDescriptorProto::descriptor()->file()->CopyTo(&proto);
12471     std::string text_proto;
12472     google::protobuf::TextFormat::PrintToString(proto, &text_proto);
12473     AddToDatabase(&database_, text_proto);
12474   }
12475   {
12476     FileDescriptorProto proto;
12477     pb::TestFeatures::descriptor()->file()->CopyTo(&proto);
12478     std::string text_proto;
12479     google::protobuf::TextFormat::PrintToString(proto, &text_proto);
12480     AddToDatabase(&database_, text_proto);
12481   }
12482   AddToDatabase(&database_, R"pb(
12483     name: "features.proto"
12484     syntax: "editions"
12485     edition: EDITION_2023
12486     dependency: "google/protobuf/unittest_features.proto"
12487     message_type {
12488       name: "FooFeatures"
12489       options {
12490         features {
12491           [pb.test] { future_feature: VALUE9 }
12492         }
12493       }
12494     }
12495   )pb");
12496   MockErrorCollector error_collector;
12497   DescriptorPool pool(&database_, &error_collector);
12498 
12499   EXPECT_TRUE(pool.FindMessageTypeByName("FooFeatures") == nullptr);
12500   EXPECT_EQ(error_collector.text_,
12501             "features.proto: FooFeatures: NAME: Feature "
12502             "pb.TestFeatures.future_feature wasn't introduced until edition "
12503             "2024 and can't be used in edition 2023\n");
12504 }
12505 
TEST_F(DatabaseBackedPoolTest,FeatureLifetimeErrorUnknownDependencies)12506 TEST_F(DatabaseBackedPoolTest, FeatureLifetimeErrorUnknownDependencies) {
12507   {
12508     FileDescriptorProto proto;
12509     FileDescriptorProto::descriptor()->file()->CopyTo(&proto);
12510     std::string text_proto;
12511     google::protobuf::TextFormat::PrintToString(proto, &text_proto);
12512     AddToDatabase(&database_, text_proto);
12513   }
12514   {
12515     FileDescriptorProto proto;
12516     pb::TestFeatures::descriptor()->file()->CopyTo(&proto);
12517     std::string text_proto;
12518     google::protobuf::TextFormat::PrintToString(proto, &text_proto);
12519     AddToDatabase(&database_, text_proto);
12520   }
12521   AddToDatabase(&database_, R"pb(
12522     name: "option.proto"
12523     syntax: "editions"
12524     edition: EDITION_2023
12525     dependency: "google/protobuf/descriptor.proto"
12526     dependency: "google/protobuf/unittest_features.proto"
12527     extension {
12528       name: "foo_extension"
12529       number: 1000
12530       type: TYPE_STRING
12531       extendee: ".google.protobuf.MessageOptions"
12532       options {
12533         features {
12534           [pb.test] { legacy_feature: VALUE9 }
12535         }
12536       }
12537     }
12538   )pb");
12539 
12540   // Note, we very carefully don't put a dependency here, otherwise option.proto
12541   // will be built eagerly beforehand.  This triggers a rare condition where
12542   // DeferredValidation is filled with descriptors that are then rolled back.
12543   AddToDatabase(&database_, R"pb(
12544     name: "use_option.proto"
12545     syntax: "editions"
12546     edition: EDITION_2023
12547     message_type {
12548       name: "FooMessage"
12549       options {
12550         uninterpreted_option {
12551           name { name_part: "foo_extension" is_extension: true }
12552           string_value: "test"
12553         }
12554       }
12555       field { name: "bar" number: 1 type: TYPE_INT64 }
12556     }
12557   )pb");
12558   MockErrorCollector error_collector;
12559   DescriptorPool pool(&database_, &error_collector);
12560 
12561   ASSERT_EQ(pool.FindMessageTypeByName("FooMessage"), nullptr);
12562   EXPECT_EQ(error_collector.text_,
12563             "use_option.proto: FooMessage: OPTION_NAME: Option "
12564             "\"(foo_extension)\" unknown. Ensure that your proto definition "
12565             "file imports the proto which defines the option.\n");
12566 
12567   // Verify that the extension does trigger a lifetime error.
12568   error_collector.text_.clear();
12569   ASSERT_EQ(pool.FindExtensionByName("foo_extension"), nullptr);
12570   EXPECT_EQ(error_collector.text_,
12571             "option.proto: foo_extension: NAME: Feature "
12572             "pb.TestFeatures.legacy_feature has been removed in edition 2023 "
12573             "and can't be used in edition 2023\n");
12574 }
12575 
TEST_F(DatabaseBackedPoolTest,DoesntRetryDbUnnecessarily)12576 TEST_F(DatabaseBackedPoolTest, DoesntRetryDbUnnecessarily) {
12577   // Searching for a child of an existing descriptor should never fall back
12578   // to the DescriptorDatabase even if it isn't found, because we know all
12579   // children are already loaded.
12580   CallCountingDatabase call_counter(&database_);
12581   DescriptorPool pool(&call_counter);
12582 
12583   const FileDescriptor* file = pool.FindFileByName("foo.proto");
12584   ASSERT_TRUE(file != nullptr);
12585   const Descriptor* foo = pool.FindMessageTypeByName("Foo");
12586   ASSERT_TRUE(foo != nullptr);
12587   const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
12588   ASSERT_TRUE(test_enum != nullptr);
12589   const ServiceDescriptor* test_service = pool.FindServiceByName("TestService");
12590   ASSERT_TRUE(test_service != nullptr);
12591 
12592   EXPECT_NE(0, call_counter.call_count_);
12593   call_counter.Clear();
12594 
12595   EXPECT_TRUE(foo->FindFieldByName("no_such_field") == nullptr);
12596   EXPECT_TRUE(foo->FindExtensionByName("no_such_extension") == nullptr);
12597   EXPECT_TRUE(foo->FindNestedTypeByName("NoSuchMessageType") == nullptr);
12598   EXPECT_TRUE(foo->FindEnumTypeByName("NoSuchEnumType") == nullptr);
12599   EXPECT_TRUE(foo->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
12600   EXPECT_TRUE(test_enum->FindValueByName("NO_SUCH_VALUE") == nullptr);
12601   EXPECT_TRUE(test_service->FindMethodByName("NoSuchMethod") == nullptr);
12602 
12603   EXPECT_TRUE(file->FindMessageTypeByName("NoSuchMessageType") == nullptr);
12604   EXPECT_TRUE(file->FindEnumTypeByName("NoSuchEnumType") == nullptr);
12605   EXPECT_TRUE(file->FindEnumValueByName("NO_SUCH_VALUE") == nullptr);
12606   EXPECT_TRUE(file->FindServiceByName("NO_SUCH_VALUE") == nullptr);
12607   EXPECT_TRUE(file->FindExtensionByName("no_such_extension") == nullptr);
12608 
12609   EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no.such.field") == nullptr);
12610   EXPECT_TRUE(pool.FindFileContainingSymbol("Foo.no_such_field") == nullptr);
12611   EXPECT_TRUE(pool.FindMessageTypeByName("Foo.NoSuchMessageType") == nullptr);
12612   EXPECT_TRUE(pool.FindFieldByName("Foo.no_such_field") == nullptr);
12613   EXPECT_TRUE(pool.FindExtensionByName("Foo.no_such_extension") == nullptr);
12614   EXPECT_TRUE(pool.FindEnumTypeByName("Foo.NoSuchEnumType") == nullptr);
12615   EXPECT_TRUE(pool.FindEnumValueByName("Foo.NO_SUCH_VALUE") == nullptr);
12616   EXPECT_TRUE(pool.FindMethodByName("TestService.NoSuchMethod") == nullptr);
12617 
12618   EXPECT_EQ(0, call_counter.call_count_);
12619 }
12620 
TEST_F(DatabaseBackedPoolTest,DoesntReloadFilesUncesessarily)12621 TEST_F(DatabaseBackedPoolTest, DoesntReloadFilesUncesessarily) {
12622   // If FindFileContainingSymbol() or FindFileContainingExtension() return a
12623   // file that is already in the DescriptorPool, it should not attempt to
12624   // reload the file.
12625   FalsePositiveDatabase false_positive_database(&database_);
12626   MockErrorCollector error_collector;
12627   DescriptorPool pool(&false_positive_database, &error_collector);
12628 
12629   // First make sure foo.proto is loaded.
12630   const Descriptor* foo = pool.FindMessageTypeByName("Foo");
12631   ASSERT_TRUE(foo != nullptr);
12632 
12633   // Try inducing false positives.
12634   EXPECT_TRUE(pool.FindMessageTypeByName("NoSuchSymbol") == nullptr);
12635   EXPECT_TRUE(pool.FindExtensionByNumber(foo, 22) == nullptr);
12636 
12637   // No errors should have been reported.  (If foo.proto was incorrectly
12638   // loaded multiple times, errors would have been reported.)
12639   EXPECT_EQ("", error_collector.text_);
12640 }
12641 
12642 // DescriptorDatabase that attempts to induce exponentially-bad performance
12643 // in DescriptorPool. For every positive N, the database contains a file
12644 // fileN.proto, which defines a message MessageN, which contains fields of
12645 // type MessageK for all K in [0,N). Message0 is not defined anywhere
12646 // (file0.proto exists, but is empty), so every other file and message type
12647 // will fail to build.
12648 //
12649 // If the DescriptorPool is not careful to memoize errors, an attempt to
12650 // build a descriptor for MessageN can require O(2^N) time.
12651 class ExponentialErrorDatabase : public DescriptorDatabase {
12652  public:
12653   ExponentialErrorDatabase() = default;
12654   ~ExponentialErrorDatabase() override = default;
12655 
12656   // implements DescriptorDatabase ---------------------------------
FindFileByName(const std::string & filename,FileDescriptorProto * output)12657   bool FindFileByName(const std::string& filename,
12658                       FileDescriptorProto* output) override {
12659     int file_num = -1;
12660     FullMatch(filename, "file", ".proto", &file_num);
12661     if (file_num > -1) {
12662       return PopulateFile(file_num, output);
12663     } else {
12664       return false;
12665     }
12666   }
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)12667   bool FindFileContainingSymbol(const std::string& symbol_name,
12668                                 FileDescriptorProto* output) override {
12669     int file_num = -1;
12670     FullMatch(symbol_name, "Message", "", &file_num);
12671     if (file_num > 0) {
12672       return PopulateFile(file_num, output);
12673     } else {
12674       return false;
12675     }
12676   }
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)12677   bool FindFileContainingExtension(const std::string& containing_type,
12678                                    int field_number,
12679                                    FileDescriptorProto* output) override {
12680     return false;
12681   }
12682 
12683  private:
FullMatch(absl::string_view name,absl::string_view begin_with,absl::string_view end_with,int32_t * file_num)12684   void FullMatch(absl::string_view name, absl::string_view begin_with,
12685                  absl::string_view end_with, int32_t* file_num) {
12686     if (!absl::ConsumePrefix(&name, begin_with)) return;
12687     if (!absl::ConsumeSuffix(&name, end_with)) return;
12688     ABSL_CHECK(absl::SimpleAtoi(name, file_num));
12689   }
12690 
PopulateFile(int file_num,FileDescriptorProto * output)12691   bool PopulateFile(int file_num, FileDescriptorProto* output) {
12692     ABSL_CHECK_GE(file_num, 0);
12693     output->Clear();
12694     output->set_name(absl::Substitute("file$0.proto", file_num));
12695     // file0.proto doesn't define Message0
12696     if (file_num > 0) {
12697       DescriptorProto* message = output->add_message_type();
12698       message->set_name(absl::Substitute("Message$0", file_num));
12699       for (int i = 0; i < file_num; ++i) {
12700         output->add_dependency(absl::Substitute("file$0.proto", i));
12701         FieldDescriptorProto* field = message->add_field();
12702         field->set_name(absl::Substitute("field$0", i));
12703         field->set_number(i);
12704         field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
12705         field->set_type(FieldDescriptorProto::TYPE_MESSAGE);
12706         field->set_type_name(absl::Substitute("Message$0", i));
12707       }
12708     }
12709     return true;
12710   }
12711 };
12712 
TEST_F(DatabaseBackedPoolTest,DoesntReloadKnownBadFiles)12713 TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
12714   ExponentialErrorDatabase error_database;
12715   DescriptorPool pool(&error_database);
12716 
12717   ABSL_LOG(INFO) << "A timeout in this test probably indicates a real bug.";
12718 
12719   EXPECT_TRUE(pool.FindFileByName("file40.proto") == nullptr);
12720   EXPECT_TRUE(pool.FindMessageTypeByName("Message40") == nullptr);
12721 }
12722 
TEST_F(DatabaseBackedPoolTest,DoesntFallbackOnWrongType)12723 TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
12724   // If a lookup finds a symbol of the wrong type (e.g. we pass a type name
12725   // to FindFieldByName()), we should fail fast, without checking the fallback
12726   // database.
12727   CallCountingDatabase call_counter(&database_);
12728   DescriptorPool pool(&call_counter);
12729 
12730   const FileDescriptor* file = pool.FindFileByName("foo.proto");
12731   ASSERT_TRUE(file != nullptr);
12732   const Descriptor* foo = pool.FindMessageTypeByName("Foo");
12733   ASSERT_TRUE(foo != nullptr);
12734   const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
12735   ASSERT_TRUE(test_enum != nullptr);
12736 
12737   EXPECT_NE(0, call_counter.call_count_);
12738   call_counter.Clear();
12739 
12740   EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == nullptr);
12741   EXPECT_TRUE(pool.FindFieldByName("Foo") == nullptr);
12742   EXPECT_TRUE(pool.FindExtensionByName("Foo") == nullptr);
12743   EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == nullptr);
12744   EXPECT_TRUE(pool.FindEnumValueByName("Foo") == nullptr);
12745   EXPECT_TRUE(pool.FindServiceByName("Foo") == nullptr);
12746   EXPECT_TRUE(pool.FindMethodByName("Foo") == nullptr);
12747 
12748   EXPECT_EQ(0, call_counter.call_count_);
12749 }
12750 
12751 // ===================================================================
12752 
12753 class AbortingErrorCollector : public DescriptorPool::ErrorCollector {
12754  public:
12755   AbortingErrorCollector() = default;
12756   AbortingErrorCollector(const AbortingErrorCollector&) = delete;
12757   AbortingErrorCollector& operator=(const AbortingErrorCollector&) = delete;
12758 
RecordError(absl::string_view filename,absl::string_view element_name,const Message * message,ErrorLocation location,absl::string_view error_message)12759   void RecordError(absl::string_view filename, absl::string_view element_name,
12760                    const Message* message, ErrorLocation location,
12761                    absl::string_view error_message) override {
12762     ABSL_LOG(FATAL) << "AddError() called unexpectedly: " << filename << " ["
12763                     << element_name << "]: " << error_message;
12764   }
12765 };
12766 
12767 // A source tree containing only one file.
12768 class SingletonSourceTree : public compiler::SourceTree {
12769  public:
SingletonSourceTree(const std::string & filename,const std::string & contents)12770   SingletonSourceTree(const std::string& filename, const std::string& contents)
12771       : filename_(filename), contents_(contents) {}
12772   SingletonSourceTree(const SingletonSourceTree&) = delete;
12773   SingletonSourceTree& operator=(const SingletonSourceTree&) = delete;
12774 
Open(absl::string_view filename)12775   io::ZeroCopyInputStream* Open(absl::string_view filename) override {
12776     return filename == filename_
12777                ? new io::ArrayInputStream(contents_.data(), contents_.size())
12778                : nullptr;
12779   }
12780 
12781  private:
12782   const std::string filename_;
12783   const std::string contents_;
12784 };
12785 
12786 const char* const kSourceLocationTestInput =
12787     "syntax = \"proto2\";\n"
12788     "option java_package = \"com.foo.bar\";\n"
12789     "option (test_file_opt) = \"foobar\";\n"
12790     "message A {\n"
12791     "  option (test_msg_opt) = \"foobar\";\n"
12792     "  optional int32 a = 1 [deprecated = true];\n"
12793     "  message B {\n"
12794     "    required double b = 1 [(test_field_opt) = \"foobar\"];\n"
12795     "  }\n"
12796     "  oneof c {\n"
12797     "    option (test_oneof_opt) = \"foobar\";\n"
12798     "    string d = 2;\n"
12799     "    string e = 3;\n"
12800     "    string f = 4;\n"
12801     "  }\n"
12802     "}\n"
12803     "enum Indecision {\n"
12804     "  option (test_enum_opt) = 21;\n"
12805     "  option (test_enum_opt) = 42;\n"
12806     "  option (test_enum_opt) = 63;\n"
12807     "  YES   = 1 [(test_enumval_opt).a = 100];\n"
12808     "  NO    = 2 [(test_enumval_opt) = {a:200}];\n"
12809     "  MAYBE = 3;\n"
12810     "}\n"
12811     "service S {\n"
12812     "  option (test_svc_opt) = {a:100};\n"
12813     "  option (test_svc_opt) = {a:200};\n"
12814     "  option (test_svc_opt) = {a:300};\n"
12815     "  rpc Method(A) returns (A.B);\n"
12816     // Put an empty line here to make the source location range match.
12817     "\n"
12818     "  rpc OtherMethod(A) returns (A) {\n"
12819     "    option deprecated = true;\n"
12820     "    option (test_method_opt) = \"foobar\";\n"
12821     "  }\n"
12822     "}\n"
12823     "message MessageWithExtensions {\n"
12824     "  extensions 1000 to 2000, 2001 to max [(test_ext_opt) = \"foobar\"];\n"
12825     "}\n"
12826     "extend MessageWithExtensions {\n"
12827     "  repeated int32 int32_extension = 1001 [packed=true];\n"
12828     "}\n"
12829     "message C {\n"
12830     "  extend MessageWithExtensions {\n"
12831     "    optional C message_extension = 1002;\n"
12832     "  }\n"
12833     "}\n"
12834     "import \"google/protobuf/descriptor.proto\";\n"
12835     "extend google.protobuf.FileOptions {\n"
12836     "  optional string test_file_opt = 10101;\n"
12837     "}\n"
12838     "extend google.protobuf.MessageOptions {\n"
12839     "  optional string test_msg_opt = 10101;\n"
12840     "}\n"
12841     "extend google.protobuf.FieldOptions {\n"
12842     "  optional string test_field_opt = 10101;\n"
12843     "}\n"
12844     "extend google.protobuf.EnumOptions {\n"
12845     "  repeated int32 test_enum_opt = 10101;\n"
12846     "}\n"
12847     "extend google.protobuf.EnumValueOptions {\n"
12848     "  optional A test_enumval_opt = 10101;\n"
12849     "}\n"
12850     "extend google.protobuf.ServiceOptions {\n"
12851     "  repeated A test_svc_opt = 10101;\n"
12852     "}\n"
12853     "extend google.protobuf.MethodOptions {\n"
12854     "  optional string test_method_opt = 10101;\n"
12855     "}\n"
12856     "extend google.protobuf.OneofOptions {\n"
12857     "  optional string test_oneof_opt = 10101;\n"
12858     "}\n"
12859     "extend google.protobuf.ExtensionRangeOptions {\n"
12860     "  optional string test_ext_opt = 10101;\n"
12861     "}\n";
12862 
12863 class SourceLocationTest : public testing::Test {
12864  public:
SourceLocationTest()12865   SourceLocationTest()
12866       : source_tree_("/test/test.proto", kSourceLocationTestInput),
12867         simple_db_(),
12868         source_tree_db_(&source_tree_),
12869         merged_db_(&simple_db_, &source_tree_db_),
12870         pool_(&merged_db_, &collector_) {
12871     // we need descriptor.proto to be accessible by the pool
12872     // since our test file imports it
12873     FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto_);
12874     simple_db_.Add(file_proto_);
12875   }
12876 
PrintSourceLocation(const SourceLocation & loc)12877   static std::string PrintSourceLocation(const SourceLocation& loc) {
12878     return absl::Substitute("$0:$1-$2:$3", 1 + loc.start_line,
12879                             1 + loc.start_column, 1 + loc.end_line,
12880                             1 + loc.end_column);
12881   }
12882 
12883  private:
12884   FileDescriptorProto file_proto_;
12885   AbortingErrorCollector collector_;
12886   SingletonSourceTree source_tree_;
12887   SimpleDescriptorDatabase simple_db_;  // contains descriptor.proto
12888   compiler::SourceTreeDescriptorDatabase source_tree_db_;  // loads test.proto
12889   MergedDescriptorDatabase merged_db_;  // combines above two dbs
12890 
12891  protected:
12892   DescriptorPool pool_;
12893 
12894   // tag number of all custom options in above test file
12895   static constexpr int kCustomOptionFieldNumber = 10101;
12896   // tag number of field "a" in message type "A" in above test file
12897   static constexpr int kAFieldNumber = 1;
12898 };
12899 
12900 // TODO: implement support for option fields and for
12901 // subparts of declarations.
12902 
TEST_F(SourceLocationTest,GetSourceLocation)12903 TEST_F(SourceLocationTest, GetSourceLocation) {
12904   SourceLocation loc;
12905 
12906   const FileDescriptor* file_desc =
12907       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
12908 
12909   const Descriptor* a_desc = file_desc->FindMessageTypeByName("A");
12910   EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
12911   EXPECT_EQ("4:1-16:2", PrintSourceLocation(loc));
12912 
12913   const Descriptor* a_b_desc = a_desc->FindNestedTypeByName("B");
12914   EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
12915   EXPECT_EQ("7:3-9:4", PrintSourceLocation(loc));
12916 
12917   const EnumDescriptor* e_desc = file_desc->FindEnumTypeByName("Indecision");
12918   EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
12919   EXPECT_EQ("17:1-24:2", PrintSourceLocation(loc));
12920 
12921   const EnumValueDescriptor* yes_desc = e_desc->FindValueByName("YES");
12922   EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
12923   EXPECT_EQ("21:3-21:42", PrintSourceLocation(loc));
12924 
12925   const ServiceDescriptor* s_desc = file_desc->FindServiceByName("S");
12926   EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
12927   EXPECT_EQ("25:1-35:2", PrintSourceLocation(loc));
12928 
12929   const MethodDescriptor* m_desc = s_desc->FindMethodByName("Method");
12930   EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
12931   EXPECT_EQ("29:3-29:31", PrintSourceLocation(loc));
12932 }
12933 
TEST_F(SourceLocationTest,ExtensionSourceLocation)12934 TEST_F(SourceLocationTest, ExtensionSourceLocation) {
12935   SourceLocation loc;
12936 
12937   const FileDescriptor* file_desc =
12938       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
12939 
12940   const FieldDescriptor* int32_extension_desc =
12941       file_desc->FindExtensionByName("int32_extension");
12942   EXPECT_TRUE(int32_extension_desc->GetSourceLocation(&loc));
12943   EXPECT_EQ("40:3-40:55", PrintSourceLocation(loc));
12944 
12945   const Descriptor* c_desc = file_desc->FindMessageTypeByName("C");
12946   EXPECT_TRUE(c_desc->GetSourceLocation(&loc));
12947   EXPECT_EQ("42:1-46:2", PrintSourceLocation(loc));
12948 
12949   const FieldDescriptor* message_extension_desc =
12950       c_desc->FindExtensionByName("message_extension");
12951   EXPECT_TRUE(message_extension_desc->GetSourceLocation(&loc));
12952   EXPECT_EQ("44:5-44:41", PrintSourceLocation(loc));
12953 }
12954 
TEST_F(SourceLocationTest,InterpretedOptionSourceLocation)12955 TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
12956   // This one's a doozy. It checks every kind of option, including
12957   // extension range options.
12958 
12959   // We are verifying that the file's source info contains correct
12960   // info for interpreted options and that it does *not* contain
12961   // any info for corresponding uninterpreted option path.
12962 
12963   SourceLocation loc;
12964 
12965   const FileDescriptor* file_desc =
12966       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
12967 
12968   // File options
12969   {
12970     int path[] = {FileDescriptorProto::kOptionsFieldNumber,
12971                   FileOptions::kJavaPackageFieldNumber};
12972     int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
12973                    FileOptions::kUninterpretedOptionFieldNumber, 0};
12974 
12975     std::vector<int> vpath(path, path + 2);
12976     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
12977     EXPECT_EQ("2:1-2:37", PrintSourceLocation(loc));
12978 
12979     std::vector<int> vunint(unint, unint + 3);
12980     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
12981   }
12982   {
12983     int path[] = {FileDescriptorProto::kOptionsFieldNumber,
12984                   kCustomOptionFieldNumber};
12985     int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
12986                    FileOptions::kUninterpretedOptionFieldNumber, 1};
12987     std::vector<int> vpath(path, path + 2);
12988     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
12989     EXPECT_EQ("3:1-3:35", PrintSourceLocation(loc));
12990 
12991     std::vector<int> vunint(unint, unint + 3);
12992     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
12993   }
12994 
12995   // Message option
12996   {
12997     int path[] = {FileDescriptorProto::kMessageTypeFieldNumber, 0,
12998                   DescriptorProto::kOptionsFieldNumber,
12999                   kCustomOptionFieldNumber};
13000     int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber, 0,
13001                    DescriptorProto::kOptionsFieldNumber,
13002                    MessageOptions::kUninterpretedOptionFieldNumber, 0};
13003     std::vector<int> vpath(path, path + 4);
13004     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13005     EXPECT_EQ("5:3-5:36", PrintSourceLocation(loc));
13006 
13007     std::vector<int> vunint(unint, unint + 5);
13008     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13009   }
13010 
13011   // Field option
13012   {
13013     int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13014                   0,
13015                   DescriptorProto::kFieldFieldNumber,
13016                   0,
13017                   FieldDescriptorProto::kOptionsFieldNumber,
13018                   FieldOptions::kDeprecatedFieldNumber};
13019     int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13020                    0,
13021                    DescriptorProto::kFieldFieldNumber,
13022                    0,
13023                    FieldDescriptorProto::kOptionsFieldNumber,
13024                    FieldOptions::kUninterpretedOptionFieldNumber,
13025                    0};
13026     std::vector<int> vpath(path, path + 6);
13027     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13028     EXPECT_EQ("6:25-6:42", PrintSourceLocation(loc));
13029 
13030     std::vector<int> vunint(unint, unint + 7);
13031     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13032   }
13033 
13034   // Nested message option
13035   {
13036     int path[] = {
13037         FileDescriptorProto::kMessageTypeFieldNumber, 0,
13038         DescriptorProto::kNestedTypeFieldNumber,      0,
13039         DescriptorProto::kFieldFieldNumber,           0,
13040         FieldDescriptorProto::kOptionsFieldNumber,    kCustomOptionFieldNumber};
13041     int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13042                    0,
13043                    DescriptorProto::kNestedTypeFieldNumber,
13044                    0,
13045                    DescriptorProto::kFieldFieldNumber,
13046                    0,
13047                    FieldDescriptorProto::kOptionsFieldNumber,
13048                    FieldOptions::kUninterpretedOptionFieldNumber,
13049                    0};
13050     std::vector<int> vpath(path, path + 8);
13051     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13052     EXPECT_EQ("8:28-8:55", PrintSourceLocation(loc));
13053 
13054     std::vector<int> vunint(unint, unint + 9);
13055     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13056   }
13057 
13058   // One-of option
13059   {
13060     int path[] = {
13061         FileDescriptorProto::kMessageTypeFieldNumber, 0,
13062         DescriptorProto::kOneofDeclFieldNumber,       0,
13063         OneofDescriptorProto::kOptionsFieldNumber,    kCustomOptionFieldNumber};
13064     int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13065                    0,
13066                    DescriptorProto::kOneofDeclFieldNumber,
13067                    0,
13068                    OneofDescriptorProto::kOptionsFieldNumber,
13069                    OneofOptions::kUninterpretedOptionFieldNumber,
13070                    0};
13071     std::vector<int> vpath(path, path + 6);
13072     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13073     EXPECT_EQ("11:5-11:40", PrintSourceLocation(loc));
13074 
13075     std::vector<int> vunint(unint, unint + 7);
13076     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13077   }
13078 
13079   // Enum option, repeated options
13080   {
13081     int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
13082                   EnumDescriptorProto::kOptionsFieldNumber,
13083                   kCustomOptionFieldNumber, 0};
13084     int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
13085                    EnumDescriptorProto::kOptionsFieldNumber,
13086                    EnumOptions::kUninterpretedOptionFieldNumber, 0};
13087     std::vector<int> vpath(path, path + 5);
13088     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13089     EXPECT_EQ("18:3-18:31", PrintSourceLocation(loc));
13090 
13091     std::vector<int> vunint(unint, unint + 5);
13092     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13093   }
13094   {
13095     int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
13096                   EnumDescriptorProto::kOptionsFieldNumber,
13097                   kCustomOptionFieldNumber, 1};
13098     int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
13099                    EnumDescriptorProto::kOptionsFieldNumber,
13100                    EnumOptions::kUninterpretedOptionFieldNumber, 1};
13101     std::vector<int> vpath(path, path + 5);
13102     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13103     EXPECT_EQ("19:3-19:31", PrintSourceLocation(loc));
13104 
13105     std::vector<int> vunint(unint, unint + 5);
13106     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13107   }
13108   {
13109     int path[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
13110                   EnumDescriptorProto::kOptionsFieldNumber,
13111                   kCustomOptionFieldNumber, 2};
13112     int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber, 0,
13113                    EnumDescriptorProto::kOptionsFieldNumber,
13114                    OneofOptions::kUninterpretedOptionFieldNumber, 2};
13115     std::vector<int> vpath(path, path + 5);
13116     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13117     EXPECT_EQ("20:3-20:31", PrintSourceLocation(loc));
13118 
13119     std::vector<int> vunint(unint, unint + 5);
13120     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13121   }
13122 
13123   // Enum value options
13124   {
13125     // option w/ message type that directly sets field
13126     int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
13127                   0,
13128                   EnumDescriptorProto::kValueFieldNumber,
13129                   0,
13130                   EnumValueDescriptorProto::kOptionsFieldNumber,
13131                   kCustomOptionFieldNumber,
13132                   kAFieldNumber};
13133     int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
13134                    0,
13135                    EnumDescriptorProto::kValueFieldNumber,
13136                    0,
13137                    EnumValueDescriptorProto::kOptionsFieldNumber,
13138                    EnumValueOptions::kUninterpretedOptionFieldNumber,
13139                    0};
13140     std::vector<int> vpath(path, path + 7);
13141     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13142     EXPECT_EQ("21:14-21:40", PrintSourceLocation(loc));
13143 
13144     std::vector<int> vunint(unint, unint + 7);
13145     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13146   }
13147   {
13148     int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
13149                   0,
13150                   EnumDescriptorProto::kValueFieldNumber,
13151                   1,
13152                   EnumValueDescriptorProto::kOptionsFieldNumber,
13153                   kCustomOptionFieldNumber};
13154     int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
13155                    0,
13156                    EnumDescriptorProto::kValueFieldNumber,
13157                    1,
13158                    EnumValueDescriptorProto::kOptionsFieldNumber,
13159                    EnumValueOptions::kUninterpretedOptionFieldNumber,
13160                    0};
13161     std::vector<int> vpath(path, path + 6);
13162     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13163     EXPECT_EQ("22:14-22:42", PrintSourceLocation(loc));
13164 
13165     std::vector<int> vunint(unint, unint + 7);
13166     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13167   }
13168 
13169   // Service option, repeated options
13170   {
13171     int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
13172                   ServiceDescriptorProto::kOptionsFieldNumber,
13173                   kCustomOptionFieldNumber, 0};
13174     int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
13175                    ServiceDescriptorProto::kOptionsFieldNumber,
13176                    ServiceOptions::kUninterpretedOptionFieldNumber, 0};
13177     std::vector<int> vpath(path, path + 5);
13178     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13179     EXPECT_EQ("26:3-26:35", PrintSourceLocation(loc));
13180 
13181     std::vector<int> vunint(unint, unint + 5);
13182     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13183   }
13184   {
13185     int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
13186                   ServiceDescriptorProto::kOptionsFieldNumber,
13187                   kCustomOptionFieldNumber, 1};
13188     int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
13189                    ServiceDescriptorProto::kOptionsFieldNumber,
13190                    ServiceOptions::kUninterpretedOptionFieldNumber, 1};
13191     std::vector<int> vpath(path, path + 5);
13192     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13193     EXPECT_EQ("27:3-27:35", PrintSourceLocation(loc));
13194 
13195     std::vector<int> vunint(unint, unint + 5);
13196     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13197   }
13198   {
13199     int path[] = {FileDescriptorProto::kServiceFieldNumber, 0,
13200                   ServiceDescriptorProto::kOptionsFieldNumber,
13201                   kCustomOptionFieldNumber, 2};
13202     int unint[] = {FileDescriptorProto::kServiceFieldNumber, 0,
13203                    ServiceDescriptorProto::kOptionsFieldNumber,
13204                    ServiceOptions::kUninterpretedOptionFieldNumber, 2};
13205     std::vector<int> vpath(path, path + 5);
13206     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13207     EXPECT_EQ("28:3-28:35", PrintSourceLocation(loc));
13208 
13209     std::vector<int> vunint(unint, unint + 5);
13210     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13211   }
13212 
13213   // Method options
13214   {
13215     int path[] = {FileDescriptorProto::kServiceFieldNumber,
13216                   0,
13217                   ServiceDescriptorProto::kMethodFieldNumber,
13218                   1,
13219                   MethodDescriptorProto::kOptionsFieldNumber,
13220                   MethodOptions::kDeprecatedFieldNumber};
13221     int unint[] = {FileDescriptorProto::kServiceFieldNumber,
13222                    0,
13223                    ServiceDescriptorProto::kMethodFieldNumber,
13224                    1,
13225                    MethodDescriptorProto::kOptionsFieldNumber,
13226                    MethodOptions::kUninterpretedOptionFieldNumber,
13227                    0};
13228     std::vector<int> vpath(path, path + 6);
13229     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13230     EXPECT_EQ("32:5-32:30", PrintSourceLocation(loc));
13231 
13232     std::vector<int> vunint(unint, unint + 7);
13233     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13234   }
13235   {
13236     int path[] = {
13237         FileDescriptorProto::kServiceFieldNumber,   0,
13238         ServiceDescriptorProto::kMethodFieldNumber, 1,
13239         MethodDescriptorProto::kOptionsFieldNumber, kCustomOptionFieldNumber};
13240     int unint[] = {FileDescriptorProto::kServiceFieldNumber,
13241                    0,
13242                    ServiceDescriptorProto::kMethodFieldNumber,
13243                    1,
13244                    MethodDescriptorProto::kOptionsFieldNumber,
13245                    MethodOptions::kUninterpretedOptionFieldNumber,
13246                    1};
13247     std::vector<int> vpath(path, path + 6);
13248     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13249     EXPECT_EQ("33:5-33:41", PrintSourceLocation(loc));
13250 
13251     std::vector<int> vunint(unint, unint + 7);
13252     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13253   }
13254 
13255   // Extension range options
13256   {
13257     int path[] = {FileDescriptorProto::kMessageTypeFieldNumber, 1,
13258                   DescriptorProto::kExtensionRangeFieldNumber, 0,
13259                   DescriptorProto_ExtensionRange::kOptionsFieldNumber};
13260     std::vector<int> vpath(path, path + 5);
13261     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13262     EXPECT_EQ("37:40-37:67", PrintSourceLocation(loc));
13263   }
13264   {
13265     int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13266                   1,
13267                   DescriptorProto::kExtensionRangeFieldNumber,
13268                   0,
13269                   DescriptorProto_ExtensionRange::kOptionsFieldNumber,
13270                   kCustomOptionFieldNumber};
13271     int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13272                    1,
13273                    DescriptorProto::kExtensionRangeFieldNumber,
13274                    0,
13275                    DescriptorProto_ExtensionRange::kOptionsFieldNumber,
13276                    ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
13277                    0};
13278     std::vector<int> vpath(path, path + 6);
13279     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13280     EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
13281 
13282     std::vector<int> vunint(unint, unint + 7);
13283     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13284   }
13285   {
13286     int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13287                   1,
13288                   DescriptorProto::kExtensionRangeFieldNumber,
13289                   1,
13290                   DescriptorProto_ExtensionRange::kOptionsFieldNumber,
13291                   kCustomOptionFieldNumber};
13292     int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
13293                    1,
13294                    DescriptorProto::kExtensionRangeFieldNumber,
13295                    1,
13296                    DescriptorProto_ExtensionRange::kOptionsFieldNumber,
13297                    ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
13298                    0};
13299     std::vector<int> vpath(path, path + 6);
13300     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13301     EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
13302 
13303     std::vector<int> vunint(unint, unint + 7);
13304     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13305   }
13306 
13307   // Field option on extension
13308   {
13309     int path[] = {FileDescriptorProto::kExtensionFieldNumber, 0,
13310                   FieldDescriptorProto::kOptionsFieldNumber,
13311                   FieldOptions::kPackedFieldNumber};
13312     int unint[] = {FileDescriptorProto::kExtensionFieldNumber, 0,
13313                    FieldDescriptorProto::kOptionsFieldNumber,
13314                    FieldOptions::kUninterpretedOptionFieldNumber, 0};
13315     std::vector<int> vpath(path, path + 4);
13316     EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
13317     EXPECT_EQ("40:42-40:53", PrintSourceLocation(loc));
13318 
13319     std::vector<int> vunint(unint, unint + 5);
13320     EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
13321   }
13322 }
13323 
13324 // Missing SourceCodeInfo doesn't cause crash:
TEST_F(SourceLocationTest,GetSourceLocation_MissingSourceCodeInfo)13325 TEST_F(SourceLocationTest, GetSourceLocation_MissingSourceCodeInfo) {
13326   SourceLocation loc;
13327 
13328   const FileDescriptor* file_desc =
13329       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
13330 
13331   FileDescriptorProto proto;
13332   file_desc->CopyTo(&proto);  // Note, this discards the SourceCodeInfo.
13333   EXPECT_FALSE(proto.has_source_code_info());
13334 
13335   DescriptorPool bad1_pool(&pool_);
13336   const FileDescriptor* bad1_file_desc =
13337       ABSL_DIE_IF_NULL(bad1_pool.BuildFile(proto));
13338   const Descriptor* bad1_a_desc = bad1_file_desc->FindMessageTypeByName("A");
13339   EXPECT_FALSE(bad1_a_desc->GetSourceLocation(&loc));
13340 }
13341 
13342 // Corrupt SourceCodeInfo doesn't cause crash:
TEST_F(SourceLocationTest,GetSourceLocation_BogusSourceCodeInfo)13343 TEST_F(SourceLocationTest, GetSourceLocation_BogusSourceCodeInfo) {
13344   SourceLocation loc;
13345 
13346   const FileDescriptor* file_desc =
13347       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
13348 
13349   FileDescriptorProto proto;
13350   file_desc->CopyTo(&proto);  // Note, this discards the SourceCodeInfo.
13351   EXPECT_FALSE(proto.has_source_code_info());
13352   SourceCodeInfo_Location* loc_msg =
13353       proto.mutable_source_code_info()->add_location();
13354   loc_msg->add_path(1);
13355   loc_msg->add_path(2);
13356   loc_msg->add_path(3);
13357   loc_msg->add_span(4);
13358   loc_msg->add_span(5);
13359   loc_msg->add_span(6);
13360 
13361   DescriptorPool bad2_pool(&pool_);
13362   const FileDescriptor* bad2_file_desc =
13363       ABSL_DIE_IF_NULL(bad2_pool.BuildFile(proto));
13364   const Descriptor* bad2_a_desc = bad2_file_desc->FindMessageTypeByName("A");
13365   EXPECT_FALSE(bad2_a_desc->GetSourceLocation(&loc));
13366 }
13367 
13368 // ===================================================================
13369 
13370 const char* const kCopySourceCodeInfoToTestInput =
13371     "syntax = \"proto2\";\n"
13372     "message Foo {}\n";
13373 
13374 // Required since source code information is not preserved by
13375 // FileDescriptorTest.
13376 class CopySourceCodeInfoToTest : public testing::Test {
13377  public:
CopySourceCodeInfoToTest()13378   CopySourceCodeInfoToTest()
13379       : source_tree_("/test/test.proto", kCopySourceCodeInfoToTestInput),
13380         db_(&source_tree_),
13381         pool_(&db_, &collector_) {}
13382 
13383  private:
13384   AbortingErrorCollector collector_;
13385   SingletonSourceTree source_tree_;
13386   compiler::SourceTreeDescriptorDatabase db_;
13387 
13388  protected:
13389   DescriptorPool pool_;
13390 };
13391 
TEST_F(CopySourceCodeInfoToTest,CopyTo_DoesNotCopySourceCodeInfo)13392 TEST_F(CopySourceCodeInfoToTest, CopyTo_DoesNotCopySourceCodeInfo) {
13393   const FileDescriptor* file_desc =
13394       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
13395   FileDescriptorProto file_desc_proto;
13396   ASSERT_FALSE(file_desc_proto.has_source_code_info());
13397 
13398   file_desc->CopyTo(&file_desc_proto);
13399   EXPECT_FALSE(file_desc_proto.has_source_code_info());
13400 }
13401 
TEST_F(CopySourceCodeInfoToTest,CopySourceCodeInfoTo)13402 TEST_F(CopySourceCodeInfoToTest, CopySourceCodeInfoTo) {
13403   const FileDescriptor* file_desc =
13404       ABSL_DIE_IF_NULL(pool_.FindFileByName("/test/test.proto"));
13405   FileDescriptorProto file_desc_proto;
13406   ASSERT_FALSE(file_desc_proto.has_source_code_info());
13407 
13408   file_desc->CopySourceCodeInfoTo(&file_desc_proto);
13409   const SourceCodeInfo& info = file_desc_proto.source_code_info();
13410   ASSERT_EQ(4, info.location_size());
13411   // Get the Foo message location
13412   const SourceCodeInfo_Location& foo_location = info.location(2);
13413   ASSERT_EQ(2, foo_location.path_size());
13414   EXPECT_EQ(FileDescriptorProto::kMessageTypeFieldNumber, foo_location.path(0));
13415   EXPECT_EQ(0, foo_location.path(1));      // Foo is the first message defined
13416   ASSERT_EQ(3, foo_location.span_size());  // Foo spans one line
13417   EXPECT_EQ(1, foo_location.span(0));      // Foo is declared on line 1
13418   EXPECT_EQ(0, foo_location.span(1));      // Foo starts at column 0
13419   EXPECT_EQ(14, foo_location.span(2));     // Foo ends on column 14
13420 }
13421 
13422 // ===================================================================
13423 
13424 class LazilyBuildDependenciesTest : public testing::Test {
13425  public:
LazilyBuildDependenciesTest()13426   LazilyBuildDependenciesTest() : pool_(&db_, nullptr) {
13427     pool_.InternalSetLazilyBuildDependencies();
13428   }
13429 
ParseProtoAndAddToDb(absl::string_view proto)13430   void ParseProtoAndAddToDb(absl::string_view proto) {
13431     FileDescriptorProto tmp;
13432     ASSERT_TRUE(TextFormat::ParseFromString(proto, &tmp));
13433     db_.Add(tmp);
13434   }
13435 
AddSimpleMessageProtoFileToDb(absl::string_view file_name,absl::string_view message_name)13436   void AddSimpleMessageProtoFileToDb(absl::string_view file_name,
13437                                      absl::string_view message_name) {
13438     ParseProtoAndAddToDb(absl::StrFormat(
13439         R"pb(
13440           name: '%s.proto'
13441           package: "protobuf_unittest"
13442           message_type {
13443             name: '%s'
13444             field { name: 'a' number: 1 label: LABEL_OPTIONAL type: TYPE_INT32 }
13445           })pb",
13446         file_name, message_name));
13447   }
13448 
AddSimpleEnumProtoFileToDb(absl::string_view file_name,absl::string_view enum_name,absl::string_view enum_value_name)13449   void AddSimpleEnumProtoFileToDb(absl::string_view file_name,
13450                                   absl::string_view enum_name,
13451                                   absl::string_view enum_value_name) {
13452     ParseProtoAndAddToDb(absl::StrCat("name: '", file_name,
13453                                       ".proto' "
13454                                       "package: 'protobuf_unittest' "
13455                                       "enum_type { "
13456                                       "  name:'",
13457                                       enum_name,
13458                                       "' "
13459                                       "  value { name:'",
13460                                       enum_value_name,
13461                                       "' number:1 } "
13462                                       "}"));
13463   }
13464 
13465  protected:
13466   SimpleDescriptorDatabase db_;
13467   DescriptorPool pool_;
13468 };
13469 
TEST_F(LazilyBuildDependenciesTest,Message)13470 TEST_F(LazilyBuildDependenciesTest, Message) {
13471   ParseProtoAndAddToDb(R"pb(
13472     name: 'foo.proto'
13473     package: 'protobuf_unittest'
13474     dependency: 'bar.proto'
13475     message_type {
13476       name: 'Foo'
13477       field {
13478         name: 'bar'
13479         number: 1
13480         label: LABEL_OPTIONAL
13481         type: TYPE_MESSAGE
13482         type_name: '.protobuf_unittest.Bar'
13483       }
13484     })pb");
13485   AddSimpleMessageProtoFileToDb("bar", "Bar");
13486 
13487   // Verify neither has been built yet.
13488   EXPECT_FALSE(pool_.InternalIsFileLoaded("foo.proto"));
13489   EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
13490 
13491   const FileDescriptor* file = pool_.FindFileByName("foo.proto");
13492 
13493   // Verify only foo gets built when asking for foo.proto
13494   EXPECT_TRUE(file != nullptr);
13495   EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
13496   EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
13497 
13498   // Verify calling FindFieldBy* works when the type of the field was
13499   // not built at cross link time. Verify this doesn't build the file
13500   // the field's type is defined in, as well.
13501   const Descriptor* desc = file->FindMessageTypeByName("Foo");
13502   const FieldDescriptor* field = desc->FindFieldByName("bar");
13503   EXPECT_TRUE(field != nullptr);
13504   EXPECT_EQ(field, desc->FindFieldByNumber(1));
13505   EXPECT_EQ(field, desc->FindFieldByLowercaseName("bar"));
13506   EXPECT_EQ(field, desc->FindFieldByCamelcaseName("bar"));
13507   EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
13508 
13509   // Finally, verify that if we call message_type() on the field, we will
13510   // build the file where the message is defined, and get a valid descriptor
13511   EXPECT_TRUE(field->message_type() != nullptr);
13512   EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
13513 }
13514 
TEST_F(LazilyBuildDependenciesTest,Enum)13515 TEST_F(LazilyBuildDependenciesTest, Enum) {
13516   ParseProtoAndAddToDb(
13517       R"pb(
13518         name: 'foo.proto'
13519         package: 'protobuf_unittest'
13520         dependency: 'enum1.proto'
13521         dependency: 'enum2.proto'
13522         message_type {
13523           name: 'Lazy'
13524           field {
13525             name: 'enum1'
13526             number: 1
13527             label: LABEL_OPTIONAL
13528             type: TYPE_ENUM
13529             type_name: '.protobuf_unittest.Enum1'
13530           }
13531           field {
13532             name: 'enum2'
13533             number: 1
13534             label: LABEL_OPTIONAL
13535             type: TYPE_ENUM
13536             type_name: '.protobuf_unittest.Enum2'
13537           }
13538         })pb");
13539   AddSimpleEnumProtoFileToDb("enum1", "Enum1", "ENUM1");
13540   AddSimpleEnumProtoFileToDb("enum2", "Enum2", "ENUM2");
13541 
13542   const FileDescriptor* file = pool_.FindFileByName("foo.proto");
13543 
13544   // Verify calling enum_type() on a field whose definition is not
13545   // yet built will build the file and return a descriptor.
13546   EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
13547   const Descriptor* desc = file->FindMessageTypeByName("Lazy");
13548   EXPECT_TRUE(desc != nullptr);
13549   const FieldDescriptor* field = desc->FindFieldByName("enum1");
13550   EXPECT_TRUE(field != nullptr);
13551   EXPECT_TRUE(field->enum_type() != nullptr);
13552   EXPECT_TRUE(pool_.InternalIsFileLoaded("enum1.proto"));
13553 
13554   // Verify calling default_value_enum() on a field whose definition is not
13555   // yet built will build the file and return a descriptor to the value.
13556   EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
13557   field = desc->FindFieldByName("enum2");
13558   EXPECT_TRUE(field != nullptr);
13559   EXPECT_TRUE(field->default_value_enum() != nullptr);
13560   EXPECT_TRUE(pool_.InternalIsFileLoaded("enum2.proto"));
13561 }
13562 
TEST_F(LazilyBuildDependenciesTest,Type)13563 TEST_F(LazilyBuildDependenciesTest, Type) {
13564   ParseProtoAndAddToDb(
13565       R"pb(
13566         name: 'foo.proto'
13567         package: 'protobuf_unittest'
13568         dependency: 'message1.proto'
13569         dependency: 'message2.proto'
13570         dependency: 'enum1.proto'
13571         dependency: 'enum2.proto'
13572         message_type {
13573           name: 'Lazy'
13574           field {
13575             name: 'message1'
13576             number: 1
13577             label: LABEL_OPTIONAL
13578             type: TYPE_MESSAGE
13579             type_name: '.protobuf_unittest.Message1'
13580           }
13581           field {
13582             name: 'message2'
13583             number: 1
13584             label: LABEL_OPTIONAL
13585             type: TYPE_MESSAGE
13586             type_name: '.protobuf_unittest.Message2'
13587           }
13588           field {
13589             name: 'enum1'
13590             number: 1
13591             label: LABEL_OPTIONAL
13592             type: TYPE_ENUM
13593             type_name: '.protobuf_unittest.Enum1'
13594           }
13595           field {
13596             name: 'enum2'
13597             number: 1
13598             label: LABEL_OPTIONAL
13599             type: TYPE_ENUM
13600             type_name: '.protobuf_unittest.Enum2'
13601           }
13602         })pb");
13603   AddSimpleMessageProtoFileToDb("message1", "Message1");
13604   AddSimpleMessageProtoFileToDb("message2", "Message2");
13605   AddSimpleEnumProtoFileToDb("enum1", "Enum1", "ENUM1");
13606   AddSimpleEnumProtoFileToDb("enum2", "Enum2", "ENUM2");
13607 
13608   const FileDescriptor* file = pool_.FindFileByName("foo.proto");
13609 
13610   // Verify calling type() on a field that is a message type will _not_
13611   // build the type defined in another file.
13612   EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
13613   const Descriptor* desc = file->FindMessageTypeByName("Lazy");
13614   EXPECT_TRUE(desc != nullptr);
13615   const FieldDescriptor* field = desc->FindFieldByName("message1");
13616   EXPECT_TRUE(field != nullptr);
13617   EXPECT_EQ(field->type(), FieldDescriptor::TYPE_MESSAGE);
13618   EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
13619 
13620   // Verify calling cpp_type() on a field that is a message type will _not_
13621   // build the type defined in another file.
13622   EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
13623   field = desc->FindFieldByName("message2");
13624   EXPECT_TRUE(field != nullptr);
13625   EXPECT_EQ(field->cpp_type(), FieldDescriptor::CPPTYPE_MESSAGE);
13626   EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
13627 
13628   // Verify calling type() on a field that is an enum type will _not_
13629   // build the type defined in another file.
13630   EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
13631   field = desc->FindFieldByName("enum1");
13632   EXPECT_TRUE(field != nullptr);
13633   EXPECT_EQ(field->type(), FieldDescriptor::TYPE_ENUM);
13634   EXPECT_FALSE(pool_.InternalIsFileLoaded("enum1.proto"));
13635 
13636   // Verify calling cpp_type() on a field that is an enum type will _not_
13637   // build the type defined in another file.
13638   EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
13639   field = desc->FindFieldByName("enum2");
13640   EXPECT_TRUE(field != nullptr);
13641   EXPECT_EQ(field->cpp_type(), FieldDescriptor::CPPTYPE_ENUM);
13642   EXPECT_FALSE(pool_.InternalIsFileLoaded("enum2.proto"));
13643 }
13644 
TEST_F(LazilyBuildDependenciesTest,Extension)13645 TEST_F(LazilyBuildDependenciesTest, Extension) {
13646   ParseProtoAndAddToDb(
13647       R"pb(
13648         name: 'foo.proto'
13649         package: 'protobuf_unittest'
13650         dependency: 'bar.proto'
13651         dependency: 'baz.proto'
13652         extension {
13653           extendee: '.protobuf_unittest.Bar'
13654           name: 'bar'
13655           number: 11
13656           label: LABEL_OPTIONAL
13657           type: TYPE_MESSAGE
13658           type_name: '.protobuf_unittest.Baz'
13659         }
13660       )pb");
13661   ParseProtoAndAddToDb(
13662       R"pb(
13663         name: 'bar.proto'
13664         package: 'protobuf_unittest'
13665         message_type {
13666           name: 'Bar'
13667           extension_range { start: 10 end: 20 }
13668         }
13669       )pb");
13670   AddSimpleMessageProtoFileToDb("baz", "Baz");
13671 
13672   // Verify none have been built yet.
13673   EXPECT_FALSE(pool_.InternalIsFileLoaded("foo.proto"));
13674   EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
13675   EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
13676 
13677   const FileDescriptor* file = pool_.FindFileByName("foo.proto");
13678 
13679   // Verify foo.bar gets loaded, and bar.proto gets loaded
13680   // to register the extension. baz.proto should not get loaded.
13681   EXPECT_TRUE(file != nullptr);
13682   EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
13683   EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
13684   EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
13685 }
13686 
TEST_F(LazilyBuildDependenciesTest,Service)13687 TEST_F(LazilyBuildDependenciesTest, Service) {
13688   ParseProtoAndAddToDb(R"pb(
13689     name: 'foo.proto'
13690     package: 'protobuf_unittest'
13691     dependency: 'message1.proto'
13692     dependency: 'message2.proto'
13693     dependency: 'message3.proto'
13694     dependency: 'message4.proto'
13695     service {
13696       name: 'LazyService'
13697       method {
13698         name: 'A'
13699         input_type: '.protobuf_unittest.Message1'
13700         output_type: '.protobuf_unittest.Message2'
13701       }
13702     })pb");
13703   AddSimpleMessageProtoFileToDb("message1", "Message1");
13704   AddSimpleMessageProtoFileToDb("message2", "Message2");
13705   AddSimpleMessageProtoFileToDb("message3", "Message3");
13706   AddSimpleMessageProtoFileToDb("message4", "Message4");
13707 
13708   const FileDescriptor* file = pool_.FindFileByName("foo.proto");
13709 
13710   // Verify calling FindServiceByName or FindMethodByName doesn't build the
13711   // files defining the input and output type, and input_type() and
13712   // output_type() does indeed build the appropriate files.
13713   const ServiceDescriptor* service = file->FindServiceByName("LazyService");
13714   EXPECT_TRUE(service != nullptr);
13715   const MethodDescriptor* method = service->FindMethodByName("A");
13716   EXPECT_FALSE(pool_.InternalIsFileLoaded("message1.proto"));
13717   EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
13718   EXPECT_TRUE(method != nullptr);
13719   EXPECT_TRUE(method->input_type() != nullptr);
13720   EXPECT_TRUE(pool_.InternalIsFileLoaded("message1.proto"));
13721   EXPECT_FALSE(pool_.InternalIsFileLoaded("message2.proto"));
13722   EXPECT_TRUE(method->output_type() != nullptr);
13723   EXPECT_TRUE(pool_.InternalIsFileLoaded("message2.proto"));
13724 }
13725 
13726 
TEST_F(LazilyBuildDependenciesTest,GeneratedFile)13727 TEST_F(LazilyBuildDependenciesTest, GeneratedFile) {
13728   // Most testing is done with custom pools with lazy dependencies forced on,
13729   // do some sanity checking that lazy imports is on by default for the
13730   // generated pool, and do custom options testing with generated to
13731   // be able to use the GetExtension ids for the custom options.
13732 
13733   // Verify none of the files are loaded yet.
13734   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13735       "google/protobuf/unittest_lazy_dependencies.proto"));
13736   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13737       "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
13738   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13739       "google/protobuf/unittest_lazy_dependencies_enum.proto"));
13740 
13741   // Verify calling autogenerated function to get a descriptor in the base
13742   // file will build that file but none of its imports. This verifies that
13743   // lazily_build_dependencies_ is set on the generated pool, and also that
13744   // the generated function "descriptor()" doesn't somehow subvert the laziness
13745   // by manually loading the dependencies or something.
13746   EXPECT_TRUE(protobuf_unittest::lazy_imports::ImportedMessage::descriptor() !=
13747               nullptr);
13748   EXPECT_TRUE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13749       "google/protobuf/unittest_lazy_dependencies.proto"));
13750   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13751       "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
13752   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13753       "google/protobuf/unittest_lazy_dependencies_enum.proto"));
13754 
13755   // Verify custom options work when defined in an import that isn't loaded,
13756   // and that a non-default value of a custom option doesn't load the file
13757   // where that enum is defined.
13758   const MessageOptions& options =
13759       protobuf_unittest::lazy_imports::MessageCustomOption::descriptor()
13760           ->options();
13761   protobuf_unittest::lazy_imports::LazyEnum custom_option_value =
13762       options.GetExtension(protobuf_unittest::lazy_imports::lazy_enum_option);
13763 
13764   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13765       "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
13766   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13767       "google/protobuf/unittest_lazy_dependencies_enum.proto"));
13768   EXPECT_EQ(custom_option_value, protobuf_unittest::lazy_imports::LAZY_ENUM_1);
13769 
13770   const MessageOptions& options2 =
13771       protobuf_unittest::lazy_imports::MessageCustomOption2::descriptor()
13772           ->options();
13773   custom_option_value =
13774       options2.GetExtension(protobuf_unittest::lazy_imports::lazy_enum_option);
13775 
13776   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13777       "google/protobuf/unittest_lazy_dependencies_custom_option.proto"));
13778   EXPECT_FALSE(DescriptorPool::generated_pool()->InternalIsFileLoaded(
13779       "google/protobuf/unittest_lazy_dependencies_enum.proto"));
13780   EXPECT_EQ(custom_option_value, protobuf_unittest::lazy_imports::LAZY_ENUM_0);
13781 }
13782 
TEST_F(LazilyBuildDependenciesTest,Dependency)13783 TEST_F(LazilyBuildDependenciesTest, Dependency) {
13784   ParseProtoAndAddToDb(
13785       R"pb(
13786         name: 'foo.proto'
13787         package: 'protobuf_unittest'
13788         dependency: 'bar.proto'
13789         message_type {
13790           name: 'Foo'
13791           field {
13792             name: 'bar'
13793             number: 1
13794             label: LABEL_OPTIONAL
13795             type: TYPE_MESSAGE
13796             type_name: '.protobuf_unittest.Bar'
13797           }
13798         }
13799       )pb");
13800   ParseProtoAndAddToDb(
13801       R"pb(
13802         name: 'bar.proto'
13803         package: 'protobuf_unittest'
13804         dependency: 'baz.proto'
13805         message_type {
13806           name: 'Bar'
13807           field {
13808             name: 'baz'
13809             number: 1
13810             label: LABEL_OPTIONAL
13811             type: TYPE_MESSAGE
13812             type_name: '.protobuf_unittest.Baz'
13813           }
13814         }
13815       )pb");
13816   AddSimpleMessageProtoFileToDb("baz", "Baz");
13817 
13818   const FileDescriptor* foo_file = pool_.FindFileByName("foo.proto");
13819   EXPECT_TRUE(foo_file != nullptr);
13820   // As expected, requesting foo.proto shouldn't build its dependencies
13821   EXPECT_TRUE(pool_.InternalIsFileLoaded("foo.proto"));
13822   EXPECT_FALSE(pool_.InternalIsFileLoaded("bar.proto"));
13823   EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
13824 
13825   // Verify calling dependency(N) will build the dependency, but
13826   // not that file's dependencies.
13827   const FileDescriptor* bar_file = foo_file->dependency(0);
13828   EXPECT_TRUE(bar_file != nullptr);
13829   EXPECT_TRUE(pool_.InternalIsFileLoaded("bar.proto"));
13830   EXPECT_FALSE(pool_.InternalIsFileLoaded("baz.proto"));
13831 }
13832 
13833 // ===================================================================
13834 
13835 
13836 }  // namespace descriptor_unittest
13837 }  // namespace protobuf
13838 }  // namespace google
13839 
13840 #include "google/protobuf/port_undef.inc"
13841