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 #include "google/protobuf/compiler/parser.h"
13
14 #include <algorithm>
15 #include <cmath>
16 #include <memory>
17 #include <string>
18 #include <utility>
19 #include <vector>
20
21 #include "google/protobuf/any.pb.h"
22 #include "google/protobuf/descriptor.pb.h"
23 #include <gmock/gmock.h>
24 #include "google/protobuf/testing/googletest.h"
25 #include <gtest/gtest.h>
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/log/absl_check.h"
28 #include "absl/memory/memory.h"
29 #include "absl/strings/str_cat.h"
30 #include "absl/strings/str_join.h"
31 #include "absl/strings/substitute.h"
32 #include "google/protobuf/compiler/retention.h"
33 #include "google/protobuf/test_util2.h"
34 #include "google/protobuf/text_format.h"
35 #include "google/protobuf/unittest.pb.h"
36 #include "google/protobuf/unittest_custom_options.pb.h"
37 #include "google/protobuf/unittest_import.pb.h"
38 #include "google/protobuf/unittest_import_public.pb.h"
39 #include "google/protobuf/wire_format.h"
40
41
42 // Must be included last.
43 #include "google/protobuf/port_def.inc"
44
45 namespace google {
46 namespace protobuf {
47 namespace compiler {
48
49 namespace {
50
51 class MockErrorCollector : public io::ErrorCollector {
52 public:
53 MockErrorCollector() = default;
54 ~MockErrorCollector() override = default;
55
56 std::string warning_;
57 std::string text_;
58
59 // implements ErrorCollector ---------------------------------------
RecordWarning(int line,int column,absl::string_view message)60 void RecordWarning(int line, int column, absl::string_view message) override {
61 absl::SubstituteAndAppend(&warning_, "$0:$1: $2\n", line, column, message);
62 }
63
RecordError(int line,int column,absl::string_view message)64 void RecordError(int line, int column, absl::string_view message) override {
65 absl::SubstituteAndAppend(&text_, "$0:$1: $2\n", line, column, message);
66 }
67 };
68
69 class MockValidationErrorCollector : public DescriptorPool::ErrorCollector {
70 public:
MockValidationErrorCollector(const SourceLocationTable & source_locations,io::ErrorCollector * wrapped_collector)71 MockValidationErrorCollector(const SourceLocationTable& source_locations,
72 io::ErrorCollector* wrapped_collector)
73 : source_locations_(source_locations),
74 wrapped_collector_(wrapped_collector) {}
75 ~MockValidationErrorCollector() override = default;
76
77 // implements ErrorCollector ---------------------------------------
RecordError(absl::string_view filename,absl::string_view element_name,const Message * descriptor,ErrorLocation location,absl::string_view message)78 void RecordError(absl::string_view filename, absl::string_view element_name,
79 const Message* descriptor, ErrorLocation location,
80 absl::string_view message) override {
81 int line, column;
82 if (location == DescriptorPool::ErrorCollector::IMPORT) {
83 source_locations_.FindImport(descriptor, element_name, &line, &column);
84 } else {
85 source_locations_.Find(descriptor, location, &line, &column);
86 }
87 wrapped_collector_->RecordError(line, column, message);
88 }
89
90 private:
91 const SourceLocationTable& source_locations_;
92 io::ErrorCollector* wrapped_collector_;
93 };
94
95 class ParserTest : public testing::Test {
96 protected:
ParserTest()97 ParserTest() : require_syntax_identifier_(false) {}
98
99 // Set up the parser to parse the given text.
SetupParser(absl::string_view text)100 void SetupParser(absl::string_view text) {
101 raw_input_ =
102 absl::make_unique<io::ArrayInputStream>(text.data(), text.size());
103 input_ =
104 absl::make_unique<io::Tokenizer>(raw_input_.get(), &error_collector_);
105 parser_ = absl::make_unique<Parser>();
106 parser_->RecordErrorsTo(&error_collector_);
107 parser_->SetRequireSyntaxIdentifier(require_syntax_identifier_);
108 }
109
110 // Parse the input and expect that the resulting FileDescriptorProto matches
111 // the given output. The output is a FileDescriptorProto in protocol buffer
112 // text format.
ExpectParsesTo(const char * input,const char * output)113 void ExpectParsesTo(const char* input, const char* output) {
114 SetupParser(input);
115 FileDescriptorProto actual, expected;
116
117 EXPECT_TRUE(parser_->Parse(input_.get(), &actual));
118 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
119 ASSERT_EQ("", error_collector_.text_);
120
121 // We don't cover SourceCodeInfo in these tests.
122 actual.clear_source_code_info();
123
124
125 // Parse the ASCII representation in order to canonicalize it. We could
126 // just compare directly to actual.DebugString(), but that would require
127 // that the caller precisely match the formatting that DebugString()
128 // produces.
129 ASSERT_TRUE(TextFormat::ParseFromString(output, &expected));
130
131 // Compare by comparing debug strings.
132 // TODO: Use differencer, once it is available.
133 EXPECT_EQ(expected.DebugString(), actual.DebugString());
134 }
135
136 // Parse the text and expect that the given errors are reported.
ExpectHasErrors(absl::string_view text,const testing::Matcher<std::string> & expected_errors)137 void ExpectHasErrors(absl::string_view text,
138 const testing::Matcher<std::string>& expected_errors) {
139 ExpectHasEarlyExitErrors(text, expected_errors);
140 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
141 }
142
143 // Parse the text and expect that the given warnings are reported.
ExpectHasWarnings(const char * text,const char * expected_warnings)144 void ExpectHasWarnings(const char* text, const char* expected_warnings) {
145 SetupParser(text);
146 FileDescriptorProto file;
147 ASSERT_TRUE(parser_->Parse(input_.get(), &file));
148 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
149 ASSERT_EQ("", error_collector_.text_);
150 EXPECT_EQ(expected_warnings, error_collector_.warning_);
151 }
152
153 // Same as above but does not expect that the parser parses the complete
154 // input.
ExpectHasEarlyExitErrors(absl::string_view text,const testing::Matcher<std::string> & expected_errors)155 void ExpectHasEarlyExitErrors(
156 absl::string_view text,
157 const testing::Matcher<std::string>& expected_errors) {
158 SetupParser(text);
159 SourceLocationTable source_locations;
160 parser_->RecordSourceLocationsTo(&source_locations);
161 FileDescriptorProto file;
162 EXPECT_FALSE(parser_->Parse(input_.get(), &file));
163 EXPECT_THAT(error_collector_.text_, expected_errors);
164 }
165
166 // Parse the text as a file and validate it (with a DescriptorPool), and
167 // expect that the validation step reports the given errors.
ExpectHasValidationErrors(absl::string_view text,const testing::Matcher<std::string> & expected_errors)168 void ExpectHasValidationErrors(
169 absl::string_view text,
170 const testing::Matcher<std::string>& expected_errors) {
171 SetupParser(text);
172 SourceLocationTable source_locations;
173 parser_->RecordSourceLocationsTo(&source_locations);
174
175 FileDescriptorProto file;
176 file.set_name("foo.proto");
177 parser_->Parse(input_.get(), &file);
178 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
179 ASSERT_EQ("", error_collector_.text_);
180
181 MockValidationErrorCollector validation_error_collector(source_locations,
182 &error_collector_);
183 EXPECT_TRUE(pool_.BuildFileCollectingErrors(
184 file, &validation_error_collector) == nullptr);
185 EXPECT_THAT(error_collector_.text_, expected_errors);
186 }
187
188 MockErrorCollector error_collector_;
189 DescriptorPool pool_;
190
191 std::unique_ptr<io::ZeroCopyInputStream> raw_input_;
192 std::unique_ptr<io::Tokenizer> input_;
193 std::unique_ptr<Parser> parser_;
194 bool require_syntax_identifier_;
195 };
196
197 // ===================================================================
198
TEST_F(ParserTest,StopAfterSyntaxIdentifier)199 TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
200 SetupParser(
201 "// blah\n"
202 "syntax = \"foobar\";\n"
203 "this line will not be parsed\n");
204 parser_->SetStopAfterSyntaxIdentifier(true);
205 EXPECT_TRUE(parser_->Parse(input_.get(), nullptr));
206 EXPECT_EQ("", error_collector_.text_);
207 EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
208 }
209
TEST_F(ParserTest,StopAfterOmittedSyntaxIdentifier)210 TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
211 SetupParser(
212 "// blah\n"
213 "this line will not be parsed\n");
214 parser_->SetStopAfterSyntaxIdentifier(true);
215 EXPECT_TRUE(parser_->Parse(input_.get(), nullptr));
216 EXPECT_EQ("", error_collector_.text_);
217 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
218 }
219
TEST_F(ParserTest,StopAfterSyntaxIdentifierWithErrors)220 TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
221 SetupParser(
222 "// blah\n"
223 "syntax = error;\n");
224 parser_->SetStopAfterSyntaxIdentifier(true);
225 EXPECT_FALSE(parser_->Parse(input_.get(), nullptr));
226 EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
227 }
228
TEST_F(ParserTest,WarnIfSyntaxIdentifierOmitted)229 TEST_F(ParserTest, WarnIfSyntaxIdentifierOmitted) {
230 SetupParser("message A {}");
231 FileDescriptorProto file;
232 CaptureTestStderr();
233 EXPECT_TRUE(parser_->Parse(input_.get(), &file));
234 EXPECT_TRUE(GetCapturedTestStderr().find("No syntax specified") !=
235 std::string::npos);
236 }
237
TEST_F(ParserTest,WarnIfFieldNameIsNotUpperCamel)238 TEST_F(ParserTest, WarnIfFieldNameIsNotUpperCamel) {
239 SetupParser(
240 "syntax = \"proto2\";"
241 "message abc {}");
242 FileDescriptorProto file;
243 EXPECT_TRUE(parser_->Parse(input_.get(), &file));
244 EXPECT_TRUE(error_collector_.warning_.find(
245 "Message name should be in UpperCamelCase. Found: abc.") !=
246 std::string::npos);
247 }
248
TEST_F(ParserTest,WarnIfFieldNameIsNotLowerUnderscore)249 TEST_F(ParserTest, WarnIfFieldNameIsNotLowerUnderscore) {
250 SetupParser(
251 "syntax = \"proto2\";"
252 "message A {"
253 " optional string SongName = 1;"
254 "}");
255 FileDescriptorProto file;
256 EXPECT_TRUE(parser_->Parse(input_.get(), &file));
257 EXPECT_TRUE(error_collector_.warning_.find(
258 "Field name should be lowercase. Found: SongName") !=
259 std::string::npos);
260 }
261
TEST_F(ParserTest,WarnIfFieldNameContainsNumberImmediatelyFollowUnderscore)262 TEST_F(ParserTest, WarnIfFieldNameContainsNumberImmediatelyFollowUnderscore) {
263 SetupParser(
264 "syntax = \"proto2\";"
265 "message A {"
266 " optional string song_name_1 = 1;"
267 "}");
268 FileDescriptorProto file;
269 EXPECT_TRUE(parser_->Parse(input_.get(), &file));
270 EXPECT_TRUE(error_collector_.warning_.find(
271 "Number should not come right after an underscore. Found: "
272 "song_name_1.") != std::string::npos);
273 }
274
TEST_F(ParserTest,RegressionNestedOpenBraceDoNotStackOverflow)275 TEST_F(ParserTest, RegressionNestedOpenBraceDoNotStackOverflow) {
276 std::string input("edition=\"a\000;", 12);
277 input += std::string(100000, '{');
278 ExpectHasEarlyExitErrors(
279 input,
280 "0:10: Unexpected end of string.\n"
281 "0:10: Invalid control characters encountered in text.\n"
282 "0:8: Unknown edition \"a\".\n");
283 }
284
285 // ===================================================================
286
287 typedef ParserTest ParseMessageTest;
288
TEST_F(ParseMessageTest,IgnoreBOM)289 TEST_F(ParseMessageTest, IgnoreBOM) {
290 char input[] =
291 " message TestMessage {\n"
292 " required int32 foo = 1;\n"
293 "}\n";
294 // Set UTF-8 BOM.
295 input[0] = (char)0xEF;
296 input[1] = (char)0xBB;
297 input[2] = (char)0xBF;
298 ExpectParsesTo(
299 input,
300 "message_type {"
301 " name: \"TestMessage\""
302 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
303 "}");
304 }
305
TEST_F(ParseMessageTest,BOMError)306 TEST_F(ParseMessageTest, BOMError) {
307 char input[] =
308 " message TestMessage {\n"
309 " required int32 foo = 1;\n"
310 "}\n";
311 input[0] = (char)0xEF;
312 ExpectHasErrors(input,
313 "0:1: Proto file starts with 0xEF but not UTF-8 BOM. "
314 "Only UTF-8 is accepted for proto file.\n"
315 "0:0: Expected top-level statement (e.g. \"message\").\n");
316 }
317
TEST_F(ParseMessageTest,SimpleMessage)318 TEST_F(ParseMessageTest, SimpleMessage) {
319 ExpectParsesTo(
320 "message TestMessage {\n"
321 " required int32 foo = 1;\n"
322 "}\n",
323
324 "message_type {"
325 " name: \"TestMessage\""
326 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
327 "}");
328 }
329
TEST_F(ParseMessageTest,ImplicitSyntaxIdentifier)330 TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
331 require_syntax_identifier_ = false;
332 ExpectParsesTo(
333 "message TestMessage {\n"
334 " required int32 foo = 1;\n"
335 "}\n",
336
337 "message_type {"
338 " name: \"TestMessage\""
339 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
340 "}");
341 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
342 }
343
TEST_F(ParseMessageTest,ExplicitSyntaxIdentifier)344 TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
345 ExpectParsesTo(
346 "syntax = \"proto2\";\n"
347 "message TestMessage {\n"
348 " required int32 foo = 1;\n"
349 "}\n",
350
351 "syntax: 'proto2' "
352 "message_type {"
353 " name: \"TestMessage\""
354 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
355 "}");
356 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
357 }
358
TEST_F(ParseMessageTest,ExplicitRequiredSyntaxIdentifier)359 TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
360 require_syntax_identifier_ = true;
361 ExpectParsesTo(
362 "syntax = \"proto2\";\n"
363 "message TestMessage {\n"
364 " required int32 foo = 1;\n"
365 "}\n",
366
367 "syntax: 'proto2' "
368 "message_type {"
369 " name: \"TestMessage\""
370 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
371 "}");
372 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
373 }
374
TEST_F(ParseMessageTest,SimpleFields)375 TEST_F(ParseMessageTest, SimpleFields) {
376 ExpectParsesTo(
377 "message TestMessage {\n"
378 " required int32 foo = 15;\n"
379 " optional int32 bar = 34;\n"
380 " repeated int32 baz = 3;\n"
381 "}\n",
382
383 "message_type {"
384 " name: \"TestMessage\""
385 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:15 }"
386 " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:34 }"
387 " field { name:\"baz\" label:LABEL_REPEATED type:TYPE_INT32 number:3 }"
388 "}");
389 }
390
TEST_F(ParseMessageTest,PrimitiveFieldTypes)391 TEST_F(ParseMessageTest, PrimitiveFieldTypes) {
392 ExpectParsesTo(
393 "message TestMessage {\n"
394 " required int32 foo = 1;\n"
395 " required int64 foo = 1;\n"
396 " required uint32 foo = 1;\n"
397 " required uint64 foo = 1;\n"
398 " required sint32 foo = 1;\n"
399 " required sint64 foo = 1;\n"
400 " required fixed32 foo = 1;\n"
401 " required fixed64 foo = 1;\n"
402 " required sfixed32 foo = 1;\n"
403 " required sfixed64 foo = 1;\n"
404 " required float foo = 1;\n"
405 " required double foo = 1;\n"
406 " required string foo = 1;\n"
407 " required bytes foo = 1;\n"
408 " required bool foo = 1;\n"
409 "}\n",
410
411 "message_type {"
412 " name: \"TestMessage\""
413 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 "
414 "}"
415 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT64 number:1 "
416 "}"
417 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT32 number:1 "
418 "}"
419 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_UINT64 number:1 "
420 "}"
421 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT32 number:1 "
422 "}"
423 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SINT64 number:1 "
424 "}"
425 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED32 number:1 "
426 "}"
427 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FIXED64 number:1 "
428 "}"
429 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED32 number:1 "
430 "}"
431 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_SFIXED64 number:1 "
432 "}"
433 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_FLOAT number:1 "
434 "}"
435 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_DOUBLE number:1 "
436 "}"
437 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_STRING number:1 "
438 "}"
439 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BYTES number:1 "
440 "}"
441 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_BOOL number:1 "
442 "}"
443 "}");
444 }
445
TEST_F(ParseMessageTest,FieldDefaults)446 TEST_F(ParseMessageTest, FieldDefaults) {
447 ExpectParsesTo(
448 "message TestMessage {\n"
449 " required int32 foo = 1 [default= 1 ];\n"
450 " required int32 foo = 1 [default= -2 ];\n"
451 " required int64 foo = 1 [default= 3 ];\n"
452 " required int64 foo = 1 [default= -4 ];\n"
453 " required uint32 foo = 1 [default= 5 ];\n"
454 " required uint64 foo = 1 [default= 6 ];\n"
455 " required float foo = 1 [default= 7.5];\n"
456 " required float foo = 1 [default= -8.5];\n"
457 " required float foo = 1 [default= 9 ];\n"
458 " required double foo = 1 [default= 10.5];\n"
459 " required double foo = 1 [default=-11.5];\n"
460 " required double foo = 1 [default= 12 ];\n"
461 " required double foo = 1 [default= inf ];\n"
462 " required double foo = 1 [default=-inf ];\n"
463 " required double foo = 1 [default= nan ];\n"
464 " required double foo = 1 [default= -nan ];\n"
465 " required string foo = 1 [default='13\\001'];\n"
466 " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
467 " required bytes foo = 1 [default='14\\002'];\n"
468 " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
469 " required bool foo = 1 [default=true ];\n"
470 " required Foo foo = 1 [default=FOO ];\n"
471
472 " required int32 foo = 1 [default= 0x7FFFFFFF];\n"
473 " required int32 foo = 1 [default=-0x80000000];\n"
474 " required uint32 foo = 1 [default= 0xFFFFFFFF];\n"
475 " required int64 foo = 1 [default= 0x7FFFFFFFFFFFFFFF];\n"
476 " required int64 foo = 1 [default=-0x8000000000000000];\n"
477 " required uint64 foo = 1 [default= 0xFFFFFFFFFFFFFFFF];\n"
478 " required double foo = 1 [default= 0xabcd];\n"
479 "}\n",
480
481 #define ETC "name:\"foo\" label:LABEL_REQUIRED number:1"
482 "message_type {"
483 " name: \"TestMessage\""
484 " field { type:TYPE_INT32 default_value:\"1\" " ETC
485 " }"
486 " field { type:TYPE_INT32 default_value:\"-2\" " ETC
487 " }"
488 " field { type:TYPE_INT64 default_value:\"3\" " ETC
489 " }"
490 " field { type:TYPE_INT64 default_value:\"-4\" " ETC
491 " }"
492 " field { type:TYPE_UINT32 default_value:\"5\" " ETC
493 " }"
494 " field { type:TYPE_UINT64 default_value:\"6\" " ETC
495 " }"
496 " field { type:TYPE_FLOAT default_value:\"7.5\" " ETC
497 " }"
498 " field { type:TYPE_FLOAT default_value:\"-8.5\" " ETC
499 " }"
500 " field { type:TYPE_FLOAT default_value:\"9\" " ETC
501 " }"
502 " field { type:TYPE_DOUBLE default_value:\"10.5\" " ETC
503 " }"
504 " field { type:TYPE_DOUBLE default_value:\"-11.5\" " ETC
505 " }"
506 " field { type:TYPE_DOUBLE default_value:\"12\" " ETC
507 " }"
508 " field { type:TYPE_DOUBLE default_value:\"inf\" " ETC
509 " }"
510 " field { type:TYPE_DOUBLE default_value:\"-inf\" " ETC
511 " }"
512 " field { type:TYPE_DOUBLE default_value:\"nan\" " ETC
513 " }"
514 " field { type:TYPE_DOUBLE default_value:\"-nan\" " ETC
515 " }"
516 " field { type:TYPE_STRING default_value:\"13\\001\" " ETC
517 " }"
518 " field { type:TYPE_STRING default_value:\"abc\" " ETC
519 " }"
520 " field { type:TYPE_BYTES default_value:\"14\\\\002\" " ETC
521 " }"
522 " field { type:TYPE_BYTES default_value:\"abc\" " ETC
523 " }"
524 " field { type:TYPE_BOOL default_value:\"true\" " ETC
525 " }"
526 " field { type_name:\"Foo\" default_value:\"FOO\" " ETC
527 " }"
528
529 " field {"
530 " type:TYPE_INT32 default_value:\"2147483647\" " ETC
531 " }"
532 " field {"
533 " type:TYPE_INT32 default_value:\"-2147483648\" " ETC
534 " }"
535 " field {"
536 " type:TYPE_UINT32 default_value:\"4294967295\" " ETC
537 " }"
538 " field {"
539 " type:TYPE_INT64 default_value:\"9223372036854775807\" " ETC
540 " }"
541 " field {"
542 " type:TYPE_INT64 default_value:\"-9223372036854775808\" " ETC
543 " }"
544 " field {"
545 " type:TYPE_UINT64 default_value:\"18446744073709551615\" " ETC
546 " }"
547 " field {"
548 " type:TYPE_DOUBLE default_value:\"43981\" " ETC
549 " }"
550 "}");
551 #undef ETC
552 }
553
TEST_F(ParseMessageTest,FieldJsonName)554 TEST_F(ParseMessageTest, FieldJsonName) {
555 ExpectParsesTo(
556 "message TestMessage {\n"
557 " optional string foo = 1 [json_name = \"@type\"];\n"
558 "}\n",
559 "message_type {"
560 " name: \"TestMessage\""
561 " field {\n"
562 " name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
563 " json_name: \"@type\"\n"
564 " }\n"
565 "}\n");
566 }
567
TEST_F(ParseMessageTest,FieldOptions)568 TEST_F(ParseMessageTest, FieldOptions) {
569 ExpectParsesTo(
570 "message TestMessage {\n"
571 " optional string foo = 1\n"
572 " [ctype=CORD, (foo)=7, foo.(.bar.baz).qux.quux.(corge)=-33, \n"
573 " (quux)=\"x\040y\", (baz.qux)=hey];\n"
574 "}\n",
575
576 "message_type {"
577 " name: \"TestMessage\""
578 " field { name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: "
579 "1"
580 " options { uninterpreted_option: { name { name_part: \"ctype\" "
581 " is_extension: false "
582 "} "
583 " identifier_value: \"CORD\" "
584 "}"
585 " uninterpreted_option: { name { name_part: \"foo\" "
586 " is_extension: true } "
587 " positive_int_value: 7 }"
588 " uninterpreted_option: { name { name_part: \"foo\" "
589 " is_extension: false "
590 "} "
591 " name { name_part: "
592 "\".bar.baz\""
593 " is_extension: true } "
594 " name { name_part: \"qux\" "
595 " is_extension: false "
596 "} "
597 " name { name_part: \"quux\" "
598 " is_extension: false "
599 "} "
600 " name { name_part: \"corge\" "
601 " is_extension: true } "
602 " negative_int_value: -33 }"
603 " uninterpreted_option: { name { name_part: \"quux\" "
604 " is_extension: true } "
605 " string_value: \"x y\" }"
606 " uninterpreted_option: { name { name_part: "
607 "\"baz.qux\" "
608 " is_extension: true } "
609 " identifier_value: \"hey\" }"
610 " }"
611 " }"
612 "}");
613 }
614
TEST_F(ParseMessageTest,FieldOptionsSupportLargeDecimalLiteral)615 TEST_F(ParseMessageTest, FieldOptionsSupportLargeDecimalLiteral) {
616 // decimal integer literal > uint64 max
617 ExpectParsesTo(
618 "import \"google/protobuf/descriptor.proto\";\n"
619 "extend google.protobuf.FieldOptions {\n"
620 " optional double f = 10101;\n"
621 "}\n"
622 "message TestMessage {\n"
623 " optional double a = 1 [default = 18446744073709551616];\n"
624 " optional double b = 2 [default = -18446744073709551616];\n"
625 " optional double c = 3 [(f) = 18446744073709551616];\n"
626 " optional double d = 4 [(f) = -18446744073709551616];\n"
627 "}\n",
628
629 "dependency: \"google/protobuf/descriptor.proto\""
630 "extension {"
631 " name: \"f\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 10101"
632 " extendee: \"google.protobuf.FieldOptions\""
633 "}"
634 "message_type {"
635 " name: \"TestMessage\""
636 " field {"
637 " name: \"a\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 1"
638 " default_value: \"1.8446744073709552e+19\""
639 " }"
640 " field {"
641 " name: \"b\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 2"
642 " default_value: \"-1.8446744073709552e+19\""
643 " }"
644 " field {"
645 " name: \"c\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 3"
646 " options{"
647 " uninterpreted_option{"
648 " name{ name_part: \"f\" is_extension: true }"
649 " double_value: 1.8446744073709552e+19"
650 " }"
651 " }"
652 " }"
653 " field {"
654 " name: \"d\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 4"
655 " options{"
656 " uninterpreted_option{"
657 " name{ name_part: \"f\" is_extension: true }"
658 " double_value: -1.8446744073709552e+19"
659 " }"
660 " }"
661 " }"
662 "}");
663 }
664
TEST_F(ParseMessageTest,FieldOptionsSupportInfAndNan)665 TEST_F(ParseMessageTest, FieldOptionsSupportInfAndNan) {
666 ExpectParsesTo(
667 "import \"google/protobuf/descriptor.proto\";\n"
668 "extend google.protobuf.FieldOptions {\n"
669 " optional double f = 10101;\n"
670 "}\n"
671 "message TestMessage {\n"
672 " optional double a = 1 [(f) = inf];\n"
673 " optional double b = 2 [(f) = -inf];\n"
674 " optional double c = 3 [(f) = nan];\n"
675 " optional double d = 4 [(f) = -nan];\n"
676 "}\n",
677
678 "dependency: \"google/protobuf/descriptor.proto\""
679 "extension {"
680 " name: \"f\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 10101"
681 " extendee: \"google.protobuf.FieldOptions\""
682 "}"
683 "message_type {"
684 " name: \"TestMessage\""
685 " field {"
686 " name: \"a\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 1"
687 " options{"
688 " uninterpreted_option{"
689 " name{ name_part: \"f\" is_extension: true }"
690 " identifier_value: \"inf\""
691 " }"
692 " }"
693 " }"
694 " field {"
695 " name: \"b\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 2"
696 " options{"
697 " uninterpreted_option{"
698 " name{ name_part: \"f\" is_extension: true }"
699 " double_value: -infinity"
700 " }"
701 " }"
702 " }"
703 " field {"
704 " name: \"c\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 3"
705 " options{"
706 " uninterpreted_option{"
707 " name{ name_part: \"f\" is_extension: true }"
708 " identifier_value: \"nan\""
709 " }"
710 " }"
711 " }"
712 " field {"
713 " name: \"d\" label: LABEL_OPTIONAL type: TYPE_DOUBLE number: 4"
714 " options{"
715 " uninterpreted_option{"
716 " name{ name_part: \"f\" is_extension: true }"
717 " double_value: nan"
718 " }"
719 " }"
720 " }"
721 "}");
722 }
723
TEST_F(ParseMessageTest,Oneof)724 TEST_F(ParseMessageTest, Oneof) {
725 ExpectParsesTo(
726 "message TestMessage {\n"
727 " oneof foo {\n"
728 " int32 a = 1;\n"
729 " string b = 2;\n"
730 " TestMessage c = 3;\n"
731 " group D = 4 { optional int32 i = 5; }\n"
732 " }\n"
733 "}\n",
734
735 "message_type {"
736 " name: \"TestMessage\""
737 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
738 " oneof_index:0 }"
739 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
740 " oneof_index:0 }"
741 " field { name:\"c\" label:LABEL_OPTIONAL type_name:\"TestMessage\" "
742 " number:3 oneof_index:0 }"
743 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_GROUP "
744 " type_name:\"D\" number:4 oneof_index:0 }"
745 " oneof_decl {"
746 " name: \"foo\""
747 " }"
748 " nested_type {"
749 " name: \"D\""
750 " field { name:\"i\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 }"
751 " }"
752 "}");
753 }
754
TEST_F(ParseMessageTest,MultipleOneofs)755 TEST_F(ParseMessageTest, MultipleOneofs) {
756 ExpectParsesTo(
757 "message TestMessage {\n"
758 " oneof foo {\n"
759 " int32 a = 1;\n"
760 " string b = 2;\n"
761 " }\n"
762 " oneof bar {\n"
763 " int32 c = 3;\n"
764 " string d = 4;\n"
765 " }\n"
766 "}\n",
767
768 "message_type {"
769 " name: \"TestMessage\""
770 " field { name:\"a\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
771 " oneof_index:0 }"
772 " field { name:\"b\" label:LABEL_OPTIONAL type:TYPE_STRING number:2 "
773 " oneof_index:0 }"
774 " field { name:\"c\" label:LABEL_OPTIONAL type:TYPE_INT32 number:3 "
775 " oneof_index:1 }"
776 " field { name:\"d\" label:LABEL_OPTIONAL type:TYPE_STRING number:4 "
777 " oneof_index:1 }"
778 " oneof_decl {"
779 " name: \"foo\""
780 " }"
781 " oneof_decl {"
782 " name: \"bar\""
783 " }"
784 "}");
785 }
786
TEST_F(ParseMessageTest,Maps)787 TEST_F(ParseMessageTest, Maps) {
788 ExpectParsesTo(
789 "message TestMessage {\n"
790 " map<int32, string> primitive_type_map = 1;\n"
791 " map<KeyType, ValueType> composite_type_map = 2;\n"
792 "}\n",
793
794 "message_type {"
795 " name: \"TestMessage\""
796 " nested_type {"
797 " name: \"PrimitiveTypeMapEntry\""
798 " field { "
799 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
800 " type:TYPE_INT32"
801 " }"
802 " field { "
803 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
804 " type:TYPE_STRING"
805 " }"
806 " options { map_entry: true }"
807 " }"
808 " nested_type {"
809 " name: \"CompositeTypeMapEntry\""
810 " field { "
811 " name: \"key\" number: 1 label:LABEL_OPTIONAL"
812 " type_name: \"KeyType\""
813 " }"
814 " field { "
815 " name: \"value\" number: 2 label:LABEL_OPTIONAL"
816 " type_name: \"ValueType\""
817 " }"
818 " options { map_entry: true }"
819 " }"
820 " field {"
821 " name: \"primitive_type_map\""
822 " label: LABEL_REPEATED"
823 " type_name: \"PrimitiveTypeMapEntry\""
824 " number: 1"
825 " }"
826 " field {"
827 " name: \"composite_type_map\""
828 " label: LABEL_REPEATED"
829 " type_name: \"CompositeTypeMapEntry\""
830 " number: 2"
831 " }"
832 "}");
833 }
834
TEST_F(ParseMessageTest,Group)835 TEST_F(ParseMessageTest, Group) {
836 ExpectParsesTo(
837 "message TestMessage {\n"
838 " optional group TestGroup = 1 {};\n"
839 "}\n",
840
841 "message_type {"
842 " name: \"TestMessage\""
843 " nested_type { name: \"TestGroup\" }"
844 " field { name:\"testgroup\" label:LABEL_OPTIONAL number:1"
845 " type:TYPE_GROUP type_name: \"TestGroup\" }"
846 "}");
847 }
848
TEST_F(ParseMessageTest,NestedMessage)849 TEST_F(ParseMessageTest, NestedMessage) {
850 ExpectParsesTo(
851 "message TestMessage {\n"
852 " message Nested {}\n"
853 " optional Nested test_nested = 1;\n"
854 "}\n",
855
856 "message_type {"
857 " name: \"TestMessage\""
858 " nested_type { name: \"Nested\" }"
859 " field { name:\"test_nested\" label:LABEL_OPTIONAL number:1"
860 " type_name: \"Nested\" }"
861 "}");
862 }
863
TEST_F(ParseMessageTest,NestedEnum)864 TEST_F(ParseMessageTest, NestedEnum) {
865 ExpectParsesTo(
866 "message TestMessage {\n"
867 " enum NestedEnum {}\n"
868 " optional NestedEnum test_enum = 1;\n"
869 "}\n",
870
871 "message_type {"
872 " name: \"TestMessage\""
873 " enum_type { name: \"NestedEnum\" }"
874 " field { name:\"test_enum\" label:LABEL_OPTIONAL number:1"
875 " type_name: \"NestedEnum\" }"
876 "}");
877 }
878
TEST_F(ParseMessageTest,ReservedRange)879 TEST_F(ParseMessageTest, ReservedRange) {
880 ExpectParsesTo(
881 "message TestMessage {\n"
882 " required int32 foo = 1;\n"
883 " reserved 2, 15, 9 to 11, 3, 20 to max;\n"
884 "}\n",
885
886 "message_type {"
887 " name: \"TestMessage\""
888 " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
889 " reserved_range { start:2 end:3 }"
890 " reserved_range { start:15 end:16 }"
891 " reserved_range { start:9 end:12 }"
892 " reserved_range { start:3 end:4 }"
893 " reserved_range { start:20 end:536870912 }"
894 "}");
895 }
896
TEST_F(ParseMessageTest,ReservedRangeOnMessageSet)897 TEST_F(ParseMessageTest, ReservedRangeOnMessageSet) {
898 ExpectParsesTo(
899 "message TestMessage {\n"
900 " option message_set_wire_format = true;\n"
901 " reserved 20 to max;\n"
902 "}\n",
903
904 "message_type {"
905 " name: \"TestMessage\""
906 " options {"
907 " uninterpreted_option {"
908 " name {"
909 " name_part: \"message_set_wire_format\""
910 " is_extension: false"
911 " }"
912 " identifier_value: \"true\""
913 " }"
914 " }"
915 " reserved_range { start:20 end:2147483647 }"
916 "}");
917 }
918
TEST_F(ParseMessageTest,ReservedNames)919 TEST_F(ParseMessageTest, ReservedNames) {
920 ExpectParsesTo(
921 "message TestMessage {\n"
922 " reserved \"foo\", \"bar\";\n"
923 "}\n",
924
925 "message_type {"
926 " name: \"TestMessage\""
927 " reserved_name: \"foo\""
928 " reserved_name: \"bar\""
929 "}");
930 }
931
TEST_F(ParseMessageTest,ReservedIdentifiers)932 TEST_F(ParseMessageTest, ReservedIdentifiers) {
933 ExpectParsesTo(
934 "edition = \"2023\";\n"
935 "message TestMessage {\n"
936 " reserved foo, bar;\n"
937 "}\n",
938
939 "syntax: \"editions\" "
940 "edition: EDITION_2023 "
941 "message_type {"
942 " name: \"TestMessage\""
943 " reserved_name: \"foo\""
944 " reserved_name: \"bar\""
945 "}");
946 }
947
TEST_F(ParseMessageTest,ExtensionRange)948 TEST_F(ParseMessageTest, ExtensionRange) {
949 ExpectParsesTo(
950 "message TestMessage {\n"
951 " extensions 10 to 19;\n"
952 " extensions 30 to max;\n"
953 "}\n",
954
955 "message_type {"
956 " name: \"TestMessage\""
957 " extension_range { start:10 end:20 }"
958 " extension_range { start:30 end:536870912 }"
959 "}");
960 }
961
TEST_F(ParseMessageTest,ExtensionRangeWithOptions)962 TEST_F(ParseMessageTest, ExtensionRangeWithOptions) {
963 ExpectParsesTo(
964 "message TestMessage {\n"
965 " extensions 10 to 19 [(i) = 5];\n"
966 "}\n",
967
968 "message_type {"
969 " name: \"TestMessage\""
970 " extension_range {"
971 " start:10"
972 " end:20"
973 " options {"
974 " uninterpreted_option {"
975 " name {"
976 " name_part: \"i\""
977 " is_extension: true"
978 " }"
979 " positive_int_value: 5"
980 " }"
981 " }"
982 " }"
983 "}");
984 }
985
TEST_F(ParseMessageTest,CompoundExtensionRange)986 TEST_F(ParseMessageTest, CompoundExtensionRange) {
987 ExpectParsesTo(
988 "message TestMessage {\n"
989 " extensions 2, 15, 9 to 11, 100 to max, 3;\n"
990 "}\n",
991
992 "message_type {"
993 " name: \"TestMessage\""
994 " extension_range { start:2 end:3 }"
995 " extension_range { start:15 end:16 }"
996 " extension_range { start:9 end:12 }"
997 " extension_range { start:100 end:536870912 }"
998 " extension_range { start:3 end:4 }"
999 "}");
1000 }
1001
TEST_F(ParseMessageTest,MaxIntExtensionDoesNotOverflow)1002 TEST_F(ParseMessageTest, MaxIntExtensionDoesNotOverflow) {
1003 ExpectHasErrors(
1004 R"(
1005 syntax = "proto2";
1006 message TestMessage {
1007 extensions 2147483647;
1008 }
1009 )",
1010 "3:31: Field number out of bounds.\n");
1011 error_collector_.text_.clear();
1012 ExpectHasErrors(
1013 R"(
1014 syntax = "proto2";
1015 message TestMessage {
1016 extensions 1 to 2147483647;
1017 }
1018 )",
1019 "3:36: Field number out of bounds.\n");
1020 error_collector_.text_.clear();
1021 ExpectHasErrors(
1022 R"(
1023 syntax = "proto2";
1024 message TestMessage {
1025 extensions 2147483647 to 2147483647;
1026 }
1027 )",
1028 "3:32: Field number out of bounds.\n");
1029 }
1030
TEST_F(ParseMessageTest,CompoundExtensionRangeWithOptions)1031 TEST_F(ParseMessageTest, CompoundExtensionRangeWithOptions) {
1032 ExpectParsesTo(
1033 "message TestMessage {\n"
1034 " extensions 2, 15, 9 to 11, 100 to max, 3 [(i) = 5];\n"
1035 "}\n",
1036
1037 "message_type {"
1038 " name: \"TestMessage\""
1039 " extension_range {"
1040 " start:2"
1041 " end:3"
1042 " options {"
1043 " uninterpreted_option {"
1044 " name {"
1045 " name_part: \"i\""
1046 " is_extension: true"
1047 " }"
1048 " positive_int_value: 5"
1049 " }"
1050 " }"
1051 " }"
1052 " extension_range {"
1053 " start:15"
1054 " end:16"
1055 " options {"
1056 " uninterpreted_option {"
1057 " name {"
1058 " name_part: \"i\""
1059 " is_extension: true"
1060 " }"
1061 " positive_int_value: 5"
1062 " }"
1063 " }"
1064 " }"
1065 " extension_range {"
1066 " start:9"
1067 " end:12"
1068 " options {"
1069 " uninterpreted_option {"
1070 " name {"
1071 " name_part: \"i\""
1072 " is_extension: true"
1073 " }"
1074 " positive_int_value: 5"
1075 " }"
1076 " }"
1077 " }"
1078 " extension_range {"
1079 " start:100"
1080 " end:536870912"
1081 " options {"
1082 " uninterpreted_option {"
1083 " name {"
1084 " name_part: \"i\""
1085 " is_extension: true"
1086 " }"
1087 " positive_int_value: 5"
1088 " }"
1089 " }"
1090 " }"
1091 " extension_range {"
1092 " start:3"
1093 " end:4"
1094 " options {"
1095 " uninterpreted_option {"
1096 " name {"
1097 " name_part: \"i\""
1098 " is_extension: true"
1099 " }"
1100 " positive_int_value: 5"
1101 " }"
1102 " }"
1103 " }"
1104 "}");
1105 }
1106
TEST_F(ParseMessageTest,LargerMaxForMessageSetWireFormatMessages)1107 TEST_F(ParseMessageTest, LargerMaxForMessageSetWireFormatMessages) {
1108 // Messages using the message_set_wire_format option can accept larger
1109 // extension numbers, as the numbers are not encoded as int32 field values
1110 // rather than tags.
1111 ExpectParsesTo(
1112 "message TestMessage {\n"
1113 " extensions 4 to max;\n"
1114 " option message_set_wire_format = true;\n"
1115 "}\n",
1116
1117 "message_type {"
1118 " name: \"TestMessage\""
1119 " extension_range { start:4 end: 0x7fffffff }"
1120 " options {\n"
1121 " uninterpreted_option { \n"
1122 " name {\n"
1123 " name_part: \"message_set_wire_format\"\n"
1124 " is_extension: false\n"
1125 " }\n"
1126 " identifier_value: \"true\"\n"
1127 " }\n"
1128 " }\n"
1129 "}");
1130 }
1131
TEST_F(ParseMessageTest,Extensions)1132 TEST_F(ParseMessageTest, Extensions) {
1133 ExpectParsesTo(
1134 "extend Extendee1 { optional int32 foo = 12; }\n"
1135 "extend Extendee2 { repeated TestMessage bar = 22; }\n",
1136
1137 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
1138 " extendee: \"Extendee1\" } "
1139 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
1140 " type_name:\"TestMessage\" extendee: \"Extendee2\" }");
1141 }
1142
TEST_F(ParseMessageTest,ExtensionsInMessageScope)1143 TEST_F(ParseMessageTest, ExtensionsInMessageScope) {
1144 ExpectParsesTo(
1145 "message TestMessage {\n"
1146 " extend Extendee1 { optional int32 foo = 12; }\n"
1147 " extend Extendee2 { repeated TestMessage bar = 22; }\n"
1148 "}\n",
1149
1150 "message_type {"
1151 " name: \"TestMessage\""
1152 " extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 "
1153 "number:12"
1154 " extendee: \"Extendee1\" }"
1155 " extension { name:\"bar\" label:LABEL_REPEATED number:22"
1156 " type_name:\"TestMessage\" extendee: \"Extendee2\" }"
1157 "}");
1158 }
1159
TEST_F(ParseMessageTest,MultipleExtensionsOneExtendee)1160 TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) {
1161 ExpectParsesTo(
1162 "extend Extendee1 {\n"
1163 " optional int32 foo = 12;\n"
1164 " repeated TestMessage bar = 22;\n"
1165 "}\n",
1166
1167 "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:12"
1168 " extendee: \"Extendee1\" } "
1169 "extension { name:\"bar\" label:LABEL_REPEATED number:22"
1170 " type_name:\"TestMessage\" extendee: \"Extendee1\" }");
1171 }
1172
TEST_F(ParseMessageTest,OptionalLabelProto3)1173 TEST_F(ParseMessageTest, OptionalLabelProto3) {
1174 ExpectParsesTo(
1175 "syntax = \"proto3\";\n"
1176 "message TestMessage {\n"
1177 " int32 foo = 1;\n"
1178 "}\n",
1179
1180 "syntax: \"proto3\" "
1181 "message_type {"
1182 " name: \"TestMessage\""
1183 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } "
1184 "}");
1185 }
1186
TEST_F(ParseMessageTest,ExplicitOptionalLabelProto3)1187 TEST_F(ParseMessageTest, ExplicitOptionalLabelProto3) {
1188 ExpectParsesTo(
1189 "syntax = 'proto3';\n"
1190 "message TestMessage {\n"
1191 " optional int32 foo = 1;\n"
1192 "}\n",
1193
1194 "syntax: \"proto3\" "
1195 "message_type {"
1196 " name: \"TestMessage\""
1197 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
1198 " proto3_optional: true oneof_index: 0 } "
1199 " oneof_decl { name:\"_foo\" } "
1200 "}");
1201
1202 // Handle collisions in the synthetic oneof name.
1203 ExpectParsesTo(
1204 "syntax = 'proto3';\n"
1205 "message TestMessage {\n"
1206 " optional int32 foo = 1;\n"
1207 " oneof _foo {\n"
1208 " int32 __foo = 2;\n"
1209 " }\n"
1210 "}\n",
1211
1212 "syntax: \"proto3\" "
1213 "message_type {"
1214 " name: \"TestMessage\""
1215 " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 "
1216 " proto3_optional: true oneof_index: 1 } "
1217 " field { name:\"__foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 "
1218 " oneof_index: 0 } "
1219 " oneof_decl { name:\"_foo\" } "
1220 " oneof_decl { name:\"X_foo\" } "
1221 "}");
1222 }
1223
TEST_F(ParseMessageTest,CanHandleErrorOnFirstToken)1224 TEST_F(ParseMessageTest, CanHandleErrorOnFirstToken) {
1225 require_syntax_identifier_ = false;
1226 ExpectHasEarlyExitErrors(
1227 "/", "0:0: Expected top-level statement (e.g. \"message\").\n");
1228
1229 require_syntax_identifier_ = true;
1230 ExpectHasEarlyExitErrors(
1231 "/",
1232 "0:0: Expected top-level statement (e.g. \"message\").\n"
1233 "0:0: File must begin with a syntax statement, e.g. 'syntax = "
1234 "\"proto2\";'.\n");
1235 }
1236
1237 // ===================================================================
1238
1239 typedef ParserTest ParseEnumTest;
1240
TEST_F(ParseEnumTest,SimpleEnum)1241 TEST_F(ParseEnumTest, SimpleEnum) {
1242 ExpectParsesTo(
1243 "enum TestEnum {\n"
1244 " FOO = 0;\n"
1245 "}\n",
1246
1247 "enum_type {"
1248 " name: \"TestEnum\""
1249 " value { name:\"FOO\" number:0 }"
1250 "}");
1251 }
1252
TEST_F(ParseEnumTest,Values)1253 TEST_F(ParseEnumTest, Values) {
1254 ExpectParsesTo(
1255 "enum TestEnum {\n"
1256 " FOO = 13;\n"
1257 " BAR = -10;\n"
1258 " BAZ = 500;\n"
1259 " HEX_MAX = 0x7FFFFFFF;\n"
1260 " HEX_MIN = -0x80000000;\n"
1261 " INT_MAX = 2147483647;\n"
1262 " INT_MIN = -2147483648;\n"
1263 "}\n",
1264
1265 "enum_type {"
1266 " name: \"TestEnum\""
1267 " value { name:\"FOO\" number:13 }"
1268 " value { name:\"BAR\" number:-10 }"
1269 " value { name:\"BAZ\" number:500 }"
1270 " value { name:\"HEX_MAX\" number:2147483647 }"
1271 " value { name:\"HEX_MIN\" number:-2147483648 }"
1272 " value { name:\"INT_MAX\" number:2147483647 }"
1273 " value { name:\"INT_MIN\" number:-2147483648 }"
1274 "}");
1275 }
1276
TEST_F(ParseEnumTest,ValueOptions)1277 TEST_F(ParseEnumTest, ValueOptions) {
1278 ExpectParsesTo(
1279 "enum TestEnum {\n"
1280 " FOO = 13;\n"
1281 " BAR = -10 [ (something.text) = 'abc' ];\n"
1282 " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
1283 "}\n",
1284
1285 "enum_type {"
1286 " name: \"TestEnum\""
1287 " value { name: \"FOO\" number: 13 }"
1288 " value { name: \"BAR\" number: -10 "
1289 " options { "
1290 " uninterpreted_option { "
1291 " name { name_part: \"something.text\" is_extension: true } "
1292 " string_value: \"abc\" "
1293 " } "
1294 " } "
1295 " } "
1296 " value { name: \"BAZ\" number: 500 "
1297 " options { "
1298 " uninterpreted_option { "
1299 " name { name_part: \"something.text\" is_extension: true } "
1300 " string_value: \"def\" "
1301 " } "
1302 " uninterpreted_option { "
1303 " name { name_part: \"other\" is_extension: false } "
1304 " positive_int_value: 1 "
1305 " } "
1306 " } "
1307 " } "
1308 "}");
1309 }
1310
TEST_F(ParseEnumTest,ReservedRange)1311 TEST_F(ParseEnumTest, ReservedRange) {
1312 ExpectParsesTo(
1313 "enum TestEnum {\n"
1314 " FOO = 0;\n"
1315 " reserved -2147483648, -6 to -4, -1 to 1, 2, 15, 9 to 11, 3, 20 to "
1316 "max;\n"
1317 "}\n",
1318
1319 "enum_type {"
1320 " name: \"TestEnum\""
1321 " value { name:\"FOO\" number:0 }"
1322 " reserved_range { start:-2147483648 end:-2147483648 }"
1323 " reserved_range { start:-6 end:-4 }"
1324 " reserved_range { start:-1 end:1 }"
1325 " reserved_range { start:2 end:2 }"
1326 " reserved_range { start:15 end:15 }"
1327 " reserved_range { start:9 end:11 }"
1328 " reserved_range { start:3 end:3 }"
1329 " reserved_range { start:20 end:2147483647 }"
1330 "}");
1331 }
1332
TEST_F(ParseEnumTest,ReservedNames)1333 TEST_F(ParseEnumTest, ReservedNames) {
1334 ExpectParsesTo(
1335 "enum TestEnum {\n"
1336 " FOO = 0;\n"
1337 " reserved \"foo\", \"bar\";\n"
1338 "}\n",
1339
1340 "enum_type {"
1341 " name: \"TestEnum\""
1342 " value { name:\"FOO\" number:0 }"
1343 " reserved_name: \"foo\""
1344 " reserved_name: \"bar\""
1345 "}");
1346 }
1347
TEST_F(ParseEnumTest,ReservedIdentifiers)1348 TEST_F(ParseEnumTest, ReservedIdentifiers) {
1349 ExpectParsesTo(
1350 "edition = \"2023\";\n"
1351 "enum TestEnum {\n"
1352 " FOO = 0;\n"
1353 " reserved foo, bar;\n"
1354 "}\n",
1355
1356 "syntax: \"editions\" "
1357 "edition: EDITION_2023 "
1358 "enum_type {"
1359 " name: \"TestEnum\""
1360 " value { name:\"FOO\" number:0 }"
1361 " reserved_name: \"foo\""
1362 " reserved_name: \"bar\""
1363 "}");
1364 }
1365
1366 // ===================================================================
1367
1368 typedef ParserTest ParseServiceTest;
1369
TEST_F(ParseServiceTest,SimpleService)1370 TEST_F(ParseServiceTest, SimpleService) {
1371 ExpectParsesTo(
1372 "service TestService {\n"
1373 " rpc Foo(In) returns (Out);\n"
1374 "}\n",
1375
1376 "service {"
1377 " name: \"TestService\""
1378 " method { name:\"Foo\" input_type:\"In\" output_type:\"Out\" }"
1379 "}");
1380 }
1381
TEST_F(ParseServiceTest,MethodsAndStreams)1382 TEST_F(ParseServiceTest, MethodsAndStreams) {
1383 ExpectParsesTo(
1384 "service TestService {\n"
1385 " rpc Foo(In1) returns (Out1);\n"
1386 " rpc Bar(In2) returns (Out2);\n"
1387 " rpc Baz(In3) returns (Out3);\n"
1388 "}\n",
1389
1390 "service {"
1391 " name: \"TestService\""
1392 " method { name:\"Foo\" input_type:\"In1\" output_type:\"Out1\" }"
1393 " method { name:\"Bar\" input_type:\"In2\" output_type:\"Out2\" }"
1394 " method { name:\"Baz\" input_type:\"In3\" output_type:\"Out3\" }"
1395 "}");
1396 }
1397
1398
1399 // ===================================================================
1400 // imports and packages
1401
1402 typedef ParserTest ParseMiscTest;
1403
TEST_F(ParseMiscTest,ParseImport)1404 TEST_F(ParseMiscTest, ParseImport) {
1405 ExpectParsesTo("import \"foo/bar/baz.proto\";\n",
1406 "dependency: \"foo/bar/baz.proto\"");
1407 }
1408
TEST_F(ParseMiscTest,ParseMultipleImports)1409 TEST_F(ParseMiscTest, ParseMultipleImports) {
1410 ExpectParsesTo(
1411 "import \"foo.proto\";\n"
1412 "import \"bar.proto\";\n"
1413 "import \"baz.proto\";\n",
1414 "dependency: \"foo.proto\""
1415 "dependency: \"bar.proto\""
1416 "dependency: \"baz.proto\"");
1417 }
1418
TEST_F(ParseMiscTest,ParsePublicImports)1419 TEST_F(ParseMiscTest, ParsePublicImports) {
1420 ExpectParsesTo(
1421 "import \"foo.proto\";\n"
1422 "import public \"bar.proto\";\n"
1423 "import \"baz.proto\";\n"
1424 "import public \"qux.proto\";\n",
1425 "dependency: \"foo.proto\""
1426 "dependency: \"bar.proto\""
1427 "dependency: \"baz.proto\""
1428 "dependency: \"qux.proto\""
1429 "public_dependency: 1 "
1430 "public_dependency: 3 ");
1431 }
1432
TEST_F(ParseMiscTest,ParsePackage)1433 TEST_F(ParseMiscTest, ParsePackage) {
1434 ExpectParsesTo("package foo.bar.baz;\n", "package: \"foo.bar.baz\"");
1435 }
1436
TEST_F(ParseMiscTest,ParsePackageWithSpaces)1437 TEST_F(ParseMiscTest, ParsePackageWithSpaces) {
1438 ExpectParsesTo(
1439 "package foo . bar. \n"
1440 " baz;\n",
1441 "package: \"foo.bar.baz\"");
1442 }
1443
1444 // ===================================================================
1445 // options
1446
TEST_F(ParseMiscTest,ParseFileOptions)1447 TEST_F(ParseMiscTest, ParseFileOptions) {
1448 ExpectParsesTo(
1449 "option java_package = \"com.google.foo\";\n"
1450 "option optimize_for = CODE_SIZE;",
1451
1452 "options {"
1453 "uninterpreted_option { name { name_part: \"java_package\" "
1454 " is_extension: false }"
1455 " string_value: \"com.google.foo\"} "
1456 "uninterpreted_option { name { name_part: \"optimize_for\" "
1457 " is_extension: false }"
1458 " identifier_value: \"CODE_SIZE\" } "
1459 "}");
1460 }
1461
TEST_F(ParseMiscTest,InterpretedOptions)1462 TEST_F(ParseMiscTest, InterpretedOptions) {
1463 // Since we're importing the generated code from parsing/compiling
1464 // unittest_custom_options.proto, we can just look at the option
1465 // values from that file's descriptor in the generated code.
1466 {
1467 const MessageOptions& options =
1468 protobuf_unittest::SettingRealsFromInf ::descriptor()->options();
1469 float float_val = options.GetExtension(protobuf_unittest::float_opt);
1470 ASSERT_TRUE(std::isinf(float_val));
1471 ASSERT_GT(float_val, 0);
1472 double double_val = options.GetExtension(protobuf_unittest::double_opt);
1473 ASSERT_TRUE(std::isinf(double_val));
1474 ASSERT_GT(double_val, 0);
1475 }
1476 {
1477 const MessageOptions& options =
1478 protobuf_unittest::SettingRealsFromNegativeInf ::descriptor()->options();
1479 float float_val = options.GetExtension(protobuf_unittest::float_opt);
1480 ASSERT_TRUE(std::isinf(float_val));
1481 ASSERT_LT(float_val, 0);
1482 double double_val = options.GetExtension(protobuf_unittest::double_opt);
1483 ASSERT_TRUE(std::isinf(double_val));
1484 ASSERT_LT(double_val, 0);
1485 }
1486 {
1487 const MessageOptions& options =
1488 protobuf_unittest::SettingRealsFromNan ::descriptor()->options();
1489 float float_val = options.GetExtension(protobuf_unittest::float_opt);
1490 ASSERT_TRUE(std::isnan(float_val));
1491 double double_val = options.GetExtension(protobuf_unittest::double_opt);
1492 ASSERT_TRUE(std::isnan(double_val));
1493 }
1494 {
1495 const MessageOptions& options =
1496 protobuf_unittest::SettingRealsFromNegativeNan ::descriptor()->options();
1497 float float_val = options.GetExtension(protobuf_unittest::float_opt);
1498 ASSERT_TRUE(std::isnan(float_val));
1499 double double_val = options.GetExtension(protobuf_unittest::double_opt);
1500 ASSERT_TRUE(std::isnan(double_val));
1501 }
1502 }
1503
1504 // ===================================================================
1505 // Error tests
1506 //
1507 // There are a very large number of possible errors that the parser could
1508 // report, so it's infeasible to test every single one of them. Instead,
1509 // we test each unique call to AddError() in parser.h. This does not mean
1510 // we are testing every possible error that Parser can generate because
1511 // each variant of the Consume() helper only counts as one unique call to
1512 // AddError().
1513
1514 typedef ParserTest ParseErrorTest;
1515
TEST_F(ParseErrorTest,MissingSyntaxIdentifier)1516 TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
1517 require_syntax_identifier_ = true;
1518 ExpectHasEarlyExitErrors("message TestMessage {}",
1519 "0:0: File must begin with a syntax statement, e.g. "
1520 "'syntax = \"proto2\";'.\n");
1521 EXPECT_EQ("", parser_->GetSyntaxIdentifier());
1522 }
1523
TEST_F(ParseErrorTest,UnknownSyntaxIdentifier)1524 TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
1525 ExpectHasEarlyExitErrors(
1526 "syntax = \"no_such_syntax\";",
1527 "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
1528 "only recognizes \"proto2\" and \"proto3\".\n");
1529 EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
1530 }
1531
TEST_F(ParseErrorTest,SimpleSyntaxError)1532 TEST_F(ParseErrorTest, SimpleSyntaxError) {
1533 ExpectHasErrors("message TestMessage @#$ { blah }",
1534 "0:20: Expected \"{\".\n");
1535 EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
1536 }
1537
TEST_F(ParseErrorTest,ExpectedTopLevel)1538 TEST_F(ParseErrorTest, ExpectedTopLevel) {
1539 ExpectHasErrors("blah;",
1540 "0:0: Expected top-level statement (e.g. \"message\").\n");
1541 }
1542
TEST_F(ParseErrorTest,UnmatchedCloseBrace)1543 TEST_F(ParseErrorTest, UnmatchedCloseBrace) {
1544 // This used to cause an infinite loop. Doh.
1545 ExpectHasErrors("}",
1546 "0:0: Expected top-level statement (e.g. \"message\").\n"
1547 "0:0: Unmatched \"}\".\n");
1548 }
1549
1550 // -------------------------------------------------------------------
1551 // Message errors
1552
TEST_F(ParseErrorTest,MessageMissingName)1553 TEST_F(ParseErrorTest, MessageMissingName) {
1554 ExpectHasErrors("message {}", "0:8: Expected message name.\n");
1555 }
1556
TEST_F(ParseErrorTest,MessageMissingBody)1557 TEST_F(ParseErrorTest, MessageMissingBody) {
1558 ExpectHasErrors("message TestMessage;", "0:19: Expected \"{\".\n");
1559 }
1560
TEST_F(ParseErrorTest,EofInMessage)1561 TEST_F(ParseErrorTest, EofInMessage) {
1562 ExpectHasErrors(
1563 "message TestMessage {",
1564 "0:21: Reached end of input in message definition (missing '}').\n");
1565 }
1566
TEST_F(ParseErrorTest,NestingIsLimitedWithoutCrashing)1567 TEST_F(ParseErrorTest, NestingIsLimitedWithoutCrashing) {
1568 std::string start = "syntax = \"proto2\";\n";
1569 std::string end;
1570
1571 const auto add = [&] {
1572 absl::StrAppend(&start, "message M {");
1573 absl::StrAppend(&end, "}");
1574 };
1575 const auto input = [&] { return absl::StrCat(start, end); };
1576
1577 // The first ones work correctly.
1578 for (int i = 1; i < internal::cpp::MaxMessageDeclarationNestingDepth(); ++i) {
1579 add();
1580 const std::string str = input();
1581 SetupParser(str);
1582 FileDescriptorProto proto;
1583 proto.set_name("foo.proto");
1584 EXPECT_TRUE(parser_->Parse(input_.get(), &proto)) << input();
1585 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
1586 ASSERT_EQ("", error_collector_.text_);
1587 DescriptorPool pool;
1588 ASSERT_TRUE(pool.BuildFile(proto));
1589 }
1590 // The rest have parsing errors but they don't crash no matter how deep we
1591 // make them.
1592 const auto error = testing::HasSubstr(
1593 "Reached maximum recursion limit for nested messages.");
1594 add();
1595 ExpectHasErrors(input(), error);
1596 for (int i = 0; i < 100000; ++i) {
1597 add();
1598 }
1599 ExpectHasErrors(input(), error);
1600 }
1601
TEST_F(ParseErrorTest,MissingFieldNumber)1602 TEST_F(ParseErrorTest, MissingFieldNumber) {
1603 ExpectHasErrors(
1604 "message TestMessage {\n"
1605 " optional int32 foo;\n"
1606 "}\n",
1607 "1:20: Missing field number.\n");
1608 }
1609
TEST_F(ParseErrorTest,ExpectedFieldNumber)1610 TEST_F(ParseErrorTest, ExpectedFieldNumber) {
1611 ExpectHasErrors(
1612 "message TestMessage {\n"
1613 " optional int32 foo = ;\n"
1614 "}\n",
1615 "1:23: Expected field number.\n");
1616 }
1617
TEST_F(ParseErrorTest,FieldNumberOutOfRange)1618 TEST_F(ParseErrorTest, FieldNumberOutOfRange) {
1619 ExpectHasErrors(
1620 "message TestMessage {\n"
1621 " optional int32 foo = 0x100000000;\n"
1622 "}\n",
1623 "1:23: Integer out of range.\n");
1624 }
1625
TEST_F(ParseErrorTest,MissingLabel)1626 TEST_F(ParseErrorTest, MissingLabel) {
1627 ExpectHasErrors(
1628 "message TestMessage {\n"
1629 " int32 foo = 1;\n"
1630 "}\n",
1631 "1:2: Expected \"required\", \"optional\", or \"repeated\".\n");
1632 }
1633
TEST_F(ParseErrorTest,ExpectedOptionName)1634 TEST_F(ParseErrorTest, ExpectedOptionName) {
1635 ExpectHasErrors(
1636 "message TestMessage {\n"
1637 " optional uint32 foo = 1 [];\n"
1638 "}\n",
1639 "1:27: Expected identifier.\n");
1640 }
1641
TEST_F(ParseErrorTest,NonExtensionOptionNameBeginningWithDot)1642 TEST_F(ParseErrorTest, NonExtensionOptionNameBeginningWithDot) {
1643 ExpectHasErrors(
1644 "message TestMessage {\n"
1645 " optional uint32 foo = 1 [.foo=1];\n"
1646 "}\n",
1647 "1:27: Expected identifier.\n");
1648 }
1649
TEST_F(ParseErrorTest,DefaultValueTypeMismatch)1650 TEST_F(ParseErrorTest, DefaultValueTypeMismatch) {
1651 ExpectHasErrors(
1652 "message TestMessage {\n"
1653 " optional uint32 foo = 1 [default=true];\n"
1654 "}\n",
1655 "1:35: Expected integer for field default value.\n");
1656 }
1657
TEST_F(ParseErrorTest,DefaultValueNotBoolean)1658 TEST_F(ParseErrorTest, DefaultValueNotBoolean) {
1659 ExpectHasErrors(
1660 "message TestMessage {\n"
1661 " optional bool foo = 1 [default=blah];\n"
1662 "}\n",
1663 "1:33: Expected \"true\" or \"false\".\n");
1664 }
1665
TEST_F(ParseErrorTest,DefaultValueNotString)1666 TEST_F(ParseErrorTest, DefaultValueNotString) {
1667 ExpectHasErrors(
1668 "message TestMessage {\n"
1669 " optional string foo = 1 [default=1];\n"
1670 "}\n",
1671 "1:35: Expected string for field default value.\n");
1672 }
1673
TEST_F(ParseErrorTest,DefaultValueUnsignedNegative)1674 TEST_F(ParseErrorTest, DefaultValueUnsignedNegative) {
1675 ExpectHasErrors(
1676 "message TestMessage {\n"
1677 " optional uint32 foo = 1 [default=-1];\n"
1678 "}\n",
1679 "1:36: Unsigned field can't have negative default value.\n");
1680 }
1681
TEST_F(ParseErrorTest,DefaultValueTooLarge)1682 TEST_F(ParseErrorTest, DefaultValueTooLarge) {
1683 ExpectHasErrors(
1684 "message TestMessage {\n"
1685 " optional int32 foo = 1 [default= 0x80000000];\n"
1686 " optional int32 foo = 1 [default=-0x80000001];\n"
1687 " optional uint32 foo = 1 [default= 0x100000000];\n"
1688 " optional int64 foo = 1 [default= 0x80000000000000000];\n"
1689 " optional int64 foo = 1 [default=-0x80000000000000001];\n"
1690 " optional uint64 foo = 1 [default= 0x100000000000000000];\n"
1691 "}\n",
1692 "1:36: Integer out of range.\n"
1693 "2:36: Integer out of range.\n"
1694 "3:36: Integer out of range.\n"
1695 "4:36: Integer out of range.\n"
1696 "5:36: Integer out of range.\n"
1697 "6:36: Integer out of range.\n");
1698 }
1699
TEST_F(ParseErrorTest,JsonNameNotString)1700 TEST_F(ParseErrorTest, JsonNameNotString) {
1701 ExpectHasErrors(
1702 "message TestMessage {\n"
1703 " optional string foo = 1 [json_name=1];\n"
1704 "}\n",
1705 "1:37: Expected string for JSON name.\n");
1706 }
1707
TEST_F(ParseErrorTest,DuplicateJsonName)1708 TEST_F(ParseErrorTest, DuplicateJsonName) {
1709 ExpectHasErrors(
1710 "message TestMessage {\n"
1711 " optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
1712 "}\n",
1713 "1:41: Already set option \"json_name\".\n");
1714 }
1715
TEST_F(ParseErrorTest,MsgReservedIdentifierOnlyInEditions)1716 TEST_F(ParseErrorTest, MsgReservedIdentifierOnlyInEditions) {
1717 ExpectHasErrors(
1718 "message TestMessage {\n"
1719 " reserved foo, bar;\n"
1720 "}\n",
1721 "1:11: Reserved names must be string literals. (Only editions supports "
1722 "identifiers.)\n");
1723 }
TEST_F(ParseErrorTest,MsgReservedNameStringNotInEditions)1724 TEST_F(ParseErrorTest, MsgReservedNameStringNotInEditions) {
1725 ExpectHasErrors(
1726 "edition = \"2023\";\n"
1727 "message TestMessage {\n"
1728 " reserved \"foo\", \"bar\";\n"
1729 "}\n",
1730 "2:11: Reserved names must be identifiers in editions, not string "
1731 "literals.\n");
1732 }
1733
TEST_F(ParseErrorTest,EnumReservedIdentifierOnlyInEditions)1734 TEST_F(ParseErrorTest, EnumReservedIdentifierOnlyInEditions) {
1735 ExpectHasErrors(
1736 "enum TestEnum {\n"
1737 " FOO = 0;\n"
1738 " reserved foo, bar;\n"
1739 "}\n",
1740 "2:11: Reserved names must be string literals. (Only editions supports "
1741 "identifiers.)\n");
1742 }
TEST_F(ParseErrorTest,EnumReservedNameStringNotInEditions)1743 TEST_F(ParseErrorTest, EnumReservedNameStringNotInEditions) {
1744 ExpectHasErrors(
1745 "edition = \"2023\";\n"
1746 "enum TestEnum {\n"
1747 " FOO = 0;\n"
1748 " reserved \"foo\", \"bar\";\n"
1749 "}\n",
1750 "3:11: Reserved names must be identifiers in editions, not string "
1751 "literals.\n");
1752 }
1753
TEST_F(ParseErrorTest,EnumValueOutOfRange)1754 TEST_F(ParseErrorTest, EnumValueOutOfRange) {
1755 ExpectHasErrors(
1756 "enum TestEnum {\n"
1757 " HEX_TOO_BIG = 0x80000000;\n"
1758 " HEX_TOO_SMALL = -0x80000001;\n"
1759 " INT_TOO_BIG = 2147483648;\n"
1760 " INT_TOO_SMALL = -2147483649;\n"
1761 "}\n",
1762 "1:19: Integer out of range.\n"
1763 "2:19: Integer out of range.\n"
1764 "3:19: Integer out of range.\n"
1765 "4:19: Integer out of range.\n");
1766 }
1767
TEST_F(ParseErrorTest,EnumAllowAliasFalse)1768 TEST_F(ParseErrorTest, EnumAllowAliasFalse) {
1769 ExpectHasErrors(
1770 "enum Foo {\n"
1771 " option allow_alias = false;\n"
1772 " BAR = 1;\n"
1773 " BAZ = 2;\n"
1774 "}\n",
1775 "5:0: \"Foo\" declares 'option allow_alias = false;' which has no "
1776 "effect. "
1777 "Please remove the declaration.\n");
1778 }
1779
TEST_F(ParseErrorTest,UnnecessaryEnumAllowAlias)1780 TEST_F(ParseErrorTest, UnnecessaryEnumAllowAlias) {
1781 ExpectHasErrors(
1782 "enum Foo {\n"
1783 " option allow_alias = true;\n"
1784 " BAR = 1;\n"
1785 " BAZ = 2;\n"
1786 "}\n",
1787 "5:0: \"Foo\" declares support for enum aliases but no enum values share "
1788 "field numbers. Please remove the unnecessary 'option allow_alias = "
1789 "true;' "
1790 "declaration.\n");
1791 }
1792
TEST_F(ParseErrorTest,DefaultValueMissing)1793 TEST_F(ParseErrorTest, DefaultValueMissing) {
1794 ExpectHasErrors(
1795 "message TestMessage {\n"
1796 " optional uint32 foo = 1 [default=];\n"
1797 "}\n",
1798 "1:35: Expected integer for field default value.\n");
1799 }
1800
TEST_F(ParseErrorTest,DefaultValueForGroup)1801 TEST_F(ParseErrorTest, DefaultValueForGroup) {
1802 ExpectHasErrors(
1803 "message TestMessage {\n"
1804 " optional group Foo = 1 [default=blah] {}\n"
1805 "}\n",
1806 "1:34: Messages can't have default values.\n");
1807 }
1808
TEST_F(ParseErrorTest,DuplicateDefaultValue)1809 TEST_F(ParseErrorTest, DuplicateDefaultValue) {
1810 ExpectHasErrors(
1811 "message TestMessage {\n"
1812 " optional uint32 foo = 1 [default=1,default=2];\n"
1813 "}\n",
1814 "1:37: Already set option \"default\".\n");
1815 }
1816
TEST_F(ParseErrorTest,MissingOneofName)1817 TEST_F(ParseErrorTest, MissingOneofName) {
1818 ExpectHasErrors(
1819 "message TestMessage {\n"
1820 " oneof {\n"
1821 " int32 bar = 1;\n"
1822 " }\n"
1823 "}\n",
1824 "1:8: Expected oneof name.\n");
1825 }
1826
TEST_F(ParseErrorTest,LabelInOneof)1827 TEST_F(ParseErrorTest, LabelInOneof) {
1828 ExpectHasErrors(
1829 "message TestMessage {\n"
1830 " oneof foo {\n"
1831 " optional int32 bar = 1;\n"
1832 " }\n"
1833 "}\n",
1834 "2:4: Fields in oneofs must not have labels (required / optional "
1835 "/ repeated).\n");
1836 }
1837
TEST_F(ParseErrorTest,MapInOneof)1838 TEST_F(ParseErrorTest, MapInOneof) {
1839 ExpectHasErrors(
1840 "message TestMessage {\n"
1841 " oneof foo {\n"
1842 " map<int32, int32> foo_map = 1;\n"
1843 " map message_field = 2;\n" // a normal message field is OK
1844 " }\n"
1845 "}\n",
1846 "2:7: Map fields are not allowed in oneofs.\n");
1847 }
1848
TEST_F(ParseErrorTest,LabelForMap)1849 TEST_F(ParseErrorTest, LabelForMap) {
1850 ExpectHasErrors(
1851 "message TestMessage {\n"
1852 " optional map<int32, int32> int_map = 1;\n"
1853 " required map<int32, int32> int_map2 = 2;\n"
1854 " repeated map<int32, int32> int_map3 = 3;\n"
1855 " optional map map_message = 4;\n" // a normal message field is OK
1856 "}\n",
1857 "1:14: Field labels (required/optional/repeated) are not allowed on map "
1858 "fields.\n"
1859 "2:14: Field labels (required/optional/repeated) are not allowed on map "
1860 "fields.\n"
1861 "3:14: Field labels (required/optional/repeated) are not allowed on map "
1862 "fields.\n");
1863 }
1864
TEST_F(ParseErrorTest,MalformedMaps)1865 TEST_F(ParseErrorTest, MalformedMaps) {
1866 ExpectHasErrors(
1867 "message TestMessage {\n"
1868 " map map_message = 1;\n" // a normal message field lacking label
1869 " map<string> str_map = 2;\n"
1870 " map<string,> str_map2 = 3;\n"
1871 " map<,string> str_map3 = 4;\n"
1872 " map<> empty_map = 5;\n"
1873 " map<string,string str_map6 = 6;\n"
1874 "}"
1875 "extend SomeMessage {\n"
1876 " map<int32, int32> int_map = 1;\n"
1877 "}",
1878 "1:6: Expected \"required\", \"optional\", or \"repeated\".\n"
1879 "2:12: Expected \",\".\n"
1880 "3:13: Expected type name.\n"
1881 "4:6: Expected type name.\n"
1882 "5:6: Expected type name.\n"
1883 "6:20: Expected \">\".\n"
1884 "8:5: Map fields are not allowed to be extensions.\n");
1885 }
1886
TEST_F(ParseErrorTest,GroupNotCapitalized)1887 TEST_F(ParseErrorTest, GroupNotCapitalized) {
1888 ExpectHasErrors(
1889 "message TestMessage {\n"
1890 " optional group foo = 1 {}\n"
1891 "}\n",
1892 "1:17: Group names must start with a capital letter.\n");
1893 }
1894
TEST_F(ParseErrorTest,GroupMissingBody)1895 TEST_F(ParseErrorTest, GroupMissingBody) {
1896 ExpectHasErrors(
1897 "message TestMessage {\n"
1898 " optional group Foo = 1;\n"
1899 "}\n",
1900 "1:24: Missing group body.\n");
1901 }
1902
TEST_F(ParseErrorTest,ExtendingPrimitive)1903 TEST_F(ParseErrorTest, ExtendingPrimitive) {
1904 ExpectHasErrors("extend int32 { optional string foo = 4; }\n",
1905 "0:7: Expected message type.\n");
1906 }
1907
TEST_F(ParseErrorTest,ErrorInExtension)1908 TEST_F(ParseErrorTest, ErrorInExtension) {
1909 ExpectHasErrors(
1910 "message Foo { extensions 100 to 199; }\n"
1911 "extend Foo { optional string foo; }\n",
1912 "1:32: Missing field number.\n");
1913 }
1914
TEST_F(ParseErrorTest,MultipleParseErrors)1915 TEST_F(ParseErrorTest, MultipleParseErrors) {
1916 // When a statement has a parse error, the parser should be able to continue
1917 // parsing at the next statement.
1918 ExpectHasErrors(
1919 "message TestMessage {\n"
1920 " optional int32 foo;\n"
1921 " !invalid statement ending in a block { blah blah { blah } blah }\n"
1922 " optional int32 bar = 3 {}\n"
1923 "}\n",
1924 "1:20: Missing field number.\n"
1925 "2:2: Expected \"required\", \"optional\", or \"repeated\".\n"
1926 "2:2: Expected type name.\n"
1927 "3:25: Expected \";\".\n");
1928 }
1929
TEST_F(ParseErrorTest,EofInAggregateValue)1930 TEST_F(ParseErrorTest, EofInAggregateValue) {
1931 ExpectHasErrors(
1932 "option (fileopt) = { i:100\n",
1933 "1:0: Unexpected end of stream while parsing aggregate value.\n");
1934 }
1935
1936 // -------------------------------------------------------------------
1937 // Enum errors
1938
TEST_F(ParseErrorTest,EofInEnum)1939 TEST_F(ParseErrorTest, EofInEnum) {
1940 ExpectHasErrors(
1941 "enum TestEnum {",
1942 "0:15: Reached end of input in enum definition (missing '}').\n");
1943 }
1944
TEST_F(ParseErrorTest,EnumValueMissingNumber)1945 TEST_F(ParseErrorTest, EnumValueMissingNumber) {
1946 ExpectHasErrors(
1947 "enum TestEnum {\n"
1948 " FOO;\n"
1949 "}\n",
1950 "1:5: Missing numeric value for enum constant.\n");
1951 }
1952
1953 // NB: with editions, this would be accepted and would reserve a value name of
1954 // "max"
TEST_F(ParseErrorTest,EnumReservedStandaloneMaxNotAllowed)1955 TEST_F(ParseErrorTest, EnumReservedStandaloneMaxNotAllowed) {
1956 ExpectHasErrors(
1957 "enum TestEnum {\n"
1958 " FOO = 1;\n"
1959 " reserved max;\n"
1960 "}\n",
1961 "2:11: Reserved names must be string literals. (Only editions supports "
1962 "identifiers.)\n");
1963 }
1964
TEST_F(ParseErrorTest,EnumReservedMixNameAndNumber)1965 TEST_F(ParseErrorTest, EnumReservedMixNameAndNumber) {
1966 ExpectHasErrors(
1967 "enum TestEnum {\n"
1968 " FOO = 1;\n"
1969 " reserved 10, \"foo\";\n"
1970 "}\n",
1971 "2:15: Expected enum number range.\n");
1972 }
TEST_F(ParseErrorTest,EnumReservedMixNameAndNumberEditions)1973 TEST_F(ParseErrorTest, EnumReservedMixNameAndNumberEditions) {
1974 ExpectHasErrors(
1975 "edition = \"2023\";\n"
1976 "enum TestEnum {\n"
1977 " FOO = 1;\n"
1978 " reserved 10, foo;\n"
1979 "}\n",
1980 "3:15: Expected enum number range.\n");
1981 }
1982
TEST_F(ParseErrorTest,EnumReservedPositiveNumberOutOfRange)1983 TEST_F(ParseErrorTest, EnumReservedPositiveNumberOutOfRange) {
1984 ExpectHasErrors(
1985 "enum TestEnum {\n"
1986 "FOO = 1;\n"
1987 " reserved 2147483648;\n"
1988 "}\n",
1989 "2:11: Integer out of range.\n");
1990 }
1991
TEST_F(ParseErrorTest,EnumReservedNegativeNumberOutOfRange)1992 TEST_F(ParseErrorTest, EnumReservedNegativeNumberOutOfRange) {
1993 ExpectHasErrors(
1994 "enum TestEnum {\n"
1995 "FOO = 1;\n"
1996 " reserved -2147483649;\n"
1997 "}\n",
1998 "2:12: Integer out of range.\n");
1999 }
2000
TEST_F(ParseErrorTest,EnumReservedMissingQuotes)2001 TEST_F(ParseErrorTest, EnumReservedMissingQuotes) {
2002 ExpectHasErrors(
2003 "enum TestEnum {\n"
2004 " FOO = 1;\n"
2005 " reserved foo;\n"
2006 "}\n",
2007 "2:11: Reserved names must be string literals. (Only editions supports "
2008 "identifiers.)\n");
2009 }
2010
TEST_F(ParseErrorTest,EnumReservedInvalidIdentifier)2011 TEST_F(ParseErrorTest, EnumReservedInvalidIdentifier) {
2012 ExpectHasWarnings(
2013 R"schema(
2014 enum TestEnum {
2015 FOO = 1;
2016 reserved "foo bar";
2017 }
2018 )schema",
2019 "3:19: Reserved name \"foo bar\" is not a valid identifier.\n");
2020 }
2021
2022 // -------------------------------------------------------------------
2023 // Reserved field number errors
2024
2025 // NB: with editions, this would be accepted and would reserve a field name of
2026 // "max"
TEST_F(ParseErrorTest,ReservedStandaloneMaxNotAllowed)2027 TEST_F(ParseErrorTest, ReservedStandaloneMaxNotAllowed) {
2028 ExpectHasErrors(
2029 "message Foo {\n"
2030 " reserved max;\n"
2031 "}\n",
2032 "1:11: Reserved names must be string literals. (Only editions supports "
2033 "identifiers.)\n");
2034 }
2035
TEST_F(ParseErrorTest,ReservedMixNameAndNumber)2036 TEST_F(ParseErrorTest, ReservedMixNameAndNumber) {
2037 ExpectHasErrors(
2038 "message Foo {\n"
2039 " reserved 10, \"foo\";\n"
2040 "}\n",
2041 "1:15: Expected field number range.\n");
2042 }
TEST_F(ParseErrorTest,ReservedMixNameAndNumberEditions)2043 TEST_F(ParseErrorTest, ReservedMixNameAndNumberEditions) {
2044 ExpectHasErrors(
2045 "edition = \"2023\";\n"
2046 "message Foo {\n"
2047 " reserved 10, foo;\n"
2048 "}\n",
2049 "2:15: Expected field number range.\n");
2050 }
2051
TEST_F(ParseErrorTest,ReservedMissingQuotes)2052 TEST_F(ParseErrorTest, ReservedMissingQuotes) {
2053 ExpectHasErrors(
2054 "message Foo {\n"
2055 " reserved foo;\n"
2056 "}\n",
2057 "1:11: Reserved names must be string literals. (Only editions supports "
2058 "identifiers.)\n");
2059 }
2060
TEST_F(ParseErrorTest,ReservedInvalidIdentifier)2061 TEST_F(ParseErrorTest, ReservedInvalidIdentifier) {
2062 ExpectHasWarnings(
2063 R"schema(
2064 message Foo {
2065 reserved "foo bar";
2066 }
2067 )schema",
2068 "2:19: Reserved name \"foo bar\" is not a valid identifier.\n");
2069 }
2070
TEST_F(ParseErrorTest,ReservedNegativeNumber)2071 TEST_F(ParseErrorTest, ReservedNegativeNumber) {
2072 ExpectHasErrors(
2073 "message Foo {\n"
2074 " reserved -10;\n"
2075 "}\n",
2076 "1:11: Expected field name or number range.\n");
2077 }
2078
TEST_F(ParseErrorTest,ReservedNumberOutOfRange)2079 TEST_F(ParseErrorTest, ReservedNumberOutOfRange) {
2080 ExpectHasErrors(
2081 "message Foo {\n"
2082 " reserved 2147483648;\n"
2083 "}\n",
2084 "1:11: Integer out of range.\n");
2085 }
2086
2087 // -------------------------------------------------------------------
2088 // Service errors
2089
TEST_F(ParseErrorTest,EofInService)2090 TEST_F(ParseErrorTest, EofInService) {
2091 ExpectHasErrors(
2092 "service TestService {",
2093 "0:21: Reached end of input in service definition (missing '}').\n");
2094 }
2095
TEST_F(ParseErrorTest,ServiceMethodPrimitiveParams)2096 TEST_F(ParseErrorTest, ServiceMethodPrimitiveParams) {
2097 ExpectHasErrors(
2098 "service TestService {\n"
2099 " rpc Foo(int32) returns (string);\n"
2100 "}\n",
2101 "1:10: Expected message type.\n"
2102 "1:26: Expected message type.\n");
2103 }
2104
2105
TEST_F(ParseErrorTest,EofInMethodOptions)2106 TEST_F(ParseErrorTest, EofInMethodOptions) {
2107 ExpectHasErrors(
2108 "service TestService {\n"
2109 " rpc Foo(Bar) returns(Bar) {",
2110 "1:29: Reached end of input in method options (missing '}').\n"
2111 "1:29: Reached end of input in service definition (missing '}').\n");
2112 }
2113
2114
TEST_F(ParseErrorTest,PrimitiveMethodInput)2115 TEST_F(ParseErrorTest, PrimitiveMethodInput) {
2116 ExpectHasErrors(
2117 "service TestService {\n"
2118 " rpc Foo(int32) returns(Bar);\n"
2119 "}\n",
2120 "1:10: Expected message type.\n");
2121 }
2122
2123
TEST_F(ParseErrorTest,MethodOptionTypeError)2124 TEST_F(ParseErrorTest, MethodOptionTypeError) {
2125 // This used to cause an infinite loop.
2126 ExpectHasErrors(
2127 "message Baz {}\n"
2128 "service Foo {\n"
2129 " rpc Bar(Baz) returns(Baz) { option invalid syntax; }\n"
2130 "}\n",
2131 "2:45: Expected \"=\".\n");
2132 }
2133
2134
2135 // -------------------------------------------------------------------
2136 // Import and package errors
2137
TEST_F(ParseErrorTest,ImportNotQuoted)2138 TEST_F(ParseErrorTest, ImportNotQuoted) {
2139 ExpectHasErrors("import foo;\n",
2140 "0:7: Expected a string naming the file to import.\n");
2141 }
2142
TEST_F(ParseErrorTest,MultiplePackagesInFile)2143 TEST_F(ParseErrorTest, MultiplePackagesInFile) {
2144 ExpectHasErrors(
2145 "package foo;\n"
2146 "package bar;\n",
2147 "1:0: Multiple package definitions.\n");
2148 }
2149
2150 // ===================================================================
2151 // Test that errors detected by DescriptorPool correctly report line and
2152 // column numbers. We have one test for every call to RecordLocation() in
2153 // parser.cc.
2154
2155 typedef ParserTest ParserValidationErrorTest;
2156
TEST_F(ParserValidationErrorTest,PackageNameError)2157 TEST_F(ParserValidationErrorTest, PackageNameError) {
2158 // Create another file which defines symbol "foo".
2159 FileDescriptorProto other_file;
2160 other_file.set_name("bar.proto");
2161 other_file.add_message_type()->set_name("foo");
2162 EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
2163
2164 // Now try to define it as a package.
2165 ExpectHasValidationErrors(
2166 "package foo.bar;",
2167 "0:0: \"foo\" is already defined (as something other than a package) "
2168 "in file \"bar.proto\".\n");
2169 }
2170
TEST_F(ParserValidationErrorTest,ImportUnloadedError)2171 TEST_F(ParserValidationErrorTest, ImportUnloadedError) {
2172 ExpectHasValidationErrors(
2173 "package test;\n"
2174 "\n"
2175 "import \"unloaded.proto\";",
2176 "2:0: Import \"unloaded.proto\" has not been loaded.\n");
2177 }
2178
TEST_F(ParserValidationErrorTest,ImportTwice)2179 TEST_F(ParserValidationErrorTest, ImportTwice) {
2180 FileDescriptorProto other_file;
2181 other_file.set_name("bar.proto");
2182 other_file.add_message_type()->set_name("foo");
2183 EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
2184
2185 ExpectHasValidationErrors(
2186 "package test;\n"
2187 "\n"
2188 "import \"bar.proto\";\n"
2189 " import \"bar.proto\";",
2190 "3:2: Import \"bar.proto\" was listed twice.\n");
2191 }
2192
TEST_F(ParserValidationErrorTest,DuplicateFileError)2193 TEST_F(ParserValidationErrorTest, DuplicateFileError) {
2194 FileDescriptorProto other_file;
2195 other_file.set_name("foo.proto");
2196 EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
2197
2198 ExpectHasValidationErrors(
2199 "package test;", "0:0: A file with this name is already in the pool.\n");
2200 }
2201
TEST_F(ParserValidationErrorTest,MessageNameError)2202 TEST_F(ParserValidationErrorTest, MessageNameError) {
2203 ExpectHasValidationErrors(
2204 "message Foo {}\n"
2205 "message Foo {}\n",
2206 "1:8: \"Foo\" is already defined.\n");
2207 }
2208
TEST_F(ParserValidationErrorTest,FieldNameError)2209 TEST_F(ParserValidationErrorTest, FieldNameError) {
2210 ExpectHasValidationErrors(
2211 "message Foo {\n"
2212 " optional int32 bar = 1;\n"
2213 " optional int32 bar = 2;\n"
2214 "}\n",
2215 "2:17: \"bar\" is already defined in \"Foo\".\n");
2216 }
2217
TEST_F(ParserValidationErrorTest,FieldTypeError)2218 TEST_F(ParserValidationErrorTest, FieldTypeError) {
2219 ExpectHasValidationErrors(
2220 "message Foo {\n"
2221 " optional Baz bar = 1;\n"
2222 "}\n",
2223 "1:11: \"Baz\" is not defined.\n");
2224 }
2225
TEST_F(ParserValidationErrorTest,FieldNumberError)2226 TEST_F(ParserValidationErrorTest, FieldNumberError) {
2227 ExpectHasValidationErrors(
2228 "message Foo {\n"
2229 " optional int32 bar = 0;\n"
2230 "}\n",
2231 "1:23: Field numbers must be positive integers.\n"
2232 "1:23: Suggested field numbers for Foo: 1\n");
2233 }
2234
TEST_F(ParserValidationErrorTest,FieldExtendeeError)2235 TEST_F(ParserValidationErrorTest, FieldExtendeeError) {
2236 ExpectHasValidationErrors("extend Baz { optional int32 bar = 1; }\n",
2237 "0:7: \"Baz\" is not defined.\n");
2238 }
2239
TEST_F(ParserValidationErrorTest,ExtensionJsonNameError)2240 TEST_F(ParserValidationErrorTest, ExtensionJsonNameError) {
2241 ExpectHasValidationErrors(
2242 "message TestMessage {\n"
2243 " extensions 1 to 100;\n"
2244 "}\n"
2245 "extend TestMessage {\n"
2246 " optional int32 foo = 12 [json_name = \"bar\"];\n"
2247 "}",
2248 "4:27: option json_name is not allowed on extension fields.\n");
2249 }
2250
TEST_F(ParserValidationErrorTest,FieldDefaultValueError)2251 TEST_F(ParserValidationErrorTest, FieldDefaultValueError) {
2252 ExpectHasValidationErrors(
2253 "enum Baz { QUX = 1; }\n"
2254 "message Foo {\n"
2255 " optional Baz bar = 1 [default=NO_SUCH_VALUE];\n"
2256 "}\n",
2257 "2:32: Enum type \"Baz\" has no value named \"NO_SUCH_VALUE\".\n");
2258 }
2259
TEST_F(ParserValidationErrorTest,FieldDefaultIntegerOutOfRange)2260 TEST_F(ParserValidationErrorTest, FieldDefaultIntegerOutOfRange) {
2261 ExpectHasErrors(
2262 "message Foo {\n"
2263 " optional double bar = 1 [default = 0x10000000000000000];\n"
2264 "}\n",
2265 "1:37: Integer out of range.\n");
2266 }
2267
TEST_F(ParserValidationErrorTest,FieldOptionOutOfRange)2268 TEST_F(ParserValidationErrorTest, FieldOptionOutOfRange) {
2269 ExpectHasErrors(
2270 "message Foo {\n"
2271 " optional double bar = 1 [foo = 0x10000000000000000];\n"
2272 "}\n",
2273 "1:33: Integer out of range.\n");
2274 }
2275
TEST_F(ParserValidationErrorTest,FileOptionNameError)2276 TEST_F(ParserValidationErrorTest, FileOptionNameError) {
2277 ExpectHasValidationErrors(
2278 "option foo = 5;",
2279 "0:7: Option \"foo\" unknown. Ensure that your proto definition file "
2280 "imports the proto which defines the option.\n");
2281 }
2282
TEST_F(ParserValidationErrorTest,FileOptionValueError)2283 TEST_F(ParserValidationErrorTest, FileOptionValueError) {
2284 ExpectHasValidationErrors(
2285 "option java_outer_classname = 5;",
2286 "0:30: Value must be quoted string for string option "
2287 "\"google.protobuf.FileOptions.java_outer_classname\".\n");
2288 }
2289
TEST_F(ParserValidationErrorTest,FieldOptionNameError)2290 TEST_F(ParserValidationErrorTest, FieldOptionNameError) {
2291 ExpectHasValidationErrors(
2292 "message Foo {\n"
2293 " optional bool bar = 1 [foo=1];\n"
2294 "}\n",
2295 "1:25: Option \"foo\" unknown. Ensure that your proto definition file "
2296 "imports the proto which defines the option.\n");
2297 }
2298
TEST_F(ParserValidationErrorTest,FieldOptionValueError)2299 TEST_F(ParserValidationErrorTest, FieldOptionValueError) {
2300 ExpectHasValidationErrors(
2301 "message Foo {\n"
2302 " optional int32 bar = 1 [ctype=1];\n"
2303 "}\n",
2304 "1:32: Value must be identifier for enum-valued option "
2305 "\"google.protobuf.FieldOptions.ctype\".\n");
2306 }
2307
TEST_F(ParserValidationErrorTest,ExtensionRangeNumberError)2308 TEST_F(ParserValidationErrorTest, ExtensionRangeNumberError) {
2309 ExpectHasValidationErrors(
2310 "message Foo {\n"
2311 " extensions 0;\n"
2312 "}\n",
2313 "1:13: Extension numbers must be positive integers.\n"
2314 "1:13: Suggested field numbers for Foo: 1\n");
2315 }
2316
TEST_F(ParserValidationErrorTest,ExtensionRangeNumberOrderError)2317 TEST_F(ParserValidationErrorTest, ExtensionRangeNumberOrderError) {
2318 ExpectHasValidationErrors(
2319 "message Foo {\n"
2320 " extensions 2 to 1;\n"
2321 "}\n",
2322 "1:13: Extension range end number must be greater than start number.\n");
2323 }
2324
TEST_F(ParserValidationErrorTest,ReservedRangeError)2325 TEST_F(ParserValidationErrorTest, ReservedRangeError) {
2326 ExpectHasValidationErrors(
2327 "message Foo {\n"
2328 " reserved 2 to 1;\n"
2329 "}\n",
2330 "1:11: Reserved range end number must be greater than start number.\n");
2331 }
2332
TEST_F(ParserValidationErrorTest,Proto3ExtensionError)2333 TEST_F(ParserValidationErrorTest, Proto3ExtensionError) {
2334 ExpectHasValidationErrors(
2335 "syntax = 'proto3';\n"
2336 "message Foo { \n"
2337 " extensions 100 to 199;\n"
2338 "}\n"
2339 "extend Foo { string foo = 101; }\n",
2340 "4:7: Extensions in proto3 are only allowed for defining options.\n"
2341 "2:13: Extension ranges are not allowed in proto3.\n");
2342 }
2343
TEST_F(ParserValidationErrorTest,Proto3MessageSet)2344 TEST_F(ParserValidationErrorTest, Proto3MessageSet) {
2345 ExpectHasValidationErrors(
2346 "syntax = 'proto3';\n"
2347 "message Foo { \n"
2348 " option message_set_wire_format = true;\n"
2349 "}\n",
2350 "1:8: MessageSet is not supported in proto3.\n");
2351 }
2352
TEST_F(ParserValidationErrorTest,Proto3Required)2353 TEST_F(ParserValidationErrorTest, Proto3Required) {
2354 ExpectHasValidationErrors(
2355 "syntax = 'proto3';\n"
2356 "message Foo { \n"
2357 " required int32 field = 1;"
2358 "}\n",
2359 "2:11: Required fields are not allowed in proto3.\n");
2360 }
2361
TEST_F(ParserValidationErrorTest,Proto3Default)2362 TEST_F(ParserValidationErrorTest, Proto3Default) {
2363 ExpectHasValidationErrors(
2364 "syntax = 'proto3';\n"
2365 "message Foo { \n"
2366 " int32 field = 1 [default = 12];"
2367 "}\n",
2368 "2:29: Explicit default values are not allowed in proto3.\n");
2369 }
2370
TEST_F(ParserValidationErrorTest,Proto3JsonConflictError)2371 TEST_F(ParserValidationErrorTest, Proto3JsonConflictError) {
2372 ExpectHasValidationErrors(
2373 "syntax = 'proto3';\n"
2374 "message TestMessage {\n"
2375 " uint32 _foo = 1;\n"
2376 " uint32 Foo = 2;\n"
2377 "}\n",
2378 "3:9: The default JSON name of field \"Foo\" (\"Foo\") conflicts "
2379 "with the default JSON name of field \"_foo\".\n");
2380 }
2381
TEST_F(ParserValidationErrorTest,Proto2JsonConflictError)2382 TEST_F(ParserValidationErrorTest, Proto2JsonConflictError) {
2383 ExpectParsesTo(
2384 "syntax = 'proto2';\n"
2385 "message TestMessage {\n"
2386 " optional uint32 _foo = 1;\n"
2387 " optional uint32 Foo = 2;\n"
2388 "}\n",
2389 "syntax: 'proto2'\n"
2390 "message_type {\n"
2391 " name: 'TestMessage'\n"
2392 " field {\n"
2393 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: '_foo' number: 1\n"
2394 " }\n"
2395 " field {\n"
2396 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'Foo' number: 2\n"
2397 " }\n"
2398 "}\n");
2399 }
2400
TEST_F(ParserValidationErrorTest,Proto3CustomJsonConflictWithDefaultError)2401 TEST_F(ParserValidationErrorTest, Proto3CustomJsonConflictWithDefaultError) {
2402 ExpectHasValidationErrors(
2403 "syntax = 'proto3';\n"
2404 "message TestMessage {\n"
2405 " uint32 foo = 1 [json_name='bar'];\n"
2406 " uint32 bar = 2;\n"
2407 "}\n",
2408 "3:9: The default JSON name of field \"bar\" (\"bar\") conflicts "
2409 "with the custom JSON name of field \"foo\".\n");
2410 }
2411
TEST_F(ParserValidationErrorTest,Proto2CustomJsonConflictWithDefaultError)2412 TEST_F(ParserValidationErrorTest, Proto2CustomJsonConflictWithDefaultError) {
2413 ExpectParsesTo(
2414 "syntax = 'proto2';\n"
2415 "message TestMessage {\n"
2416 " optional uint32 foo = 1 [json_name='bar'];\n"
2417 " optional uint32 bar = 2;\n"
2418 "}\n",
2419 "syntax: 'proto2'\n"
2420 "message_type {\n"
2421 " name: 'TestMessage'\n"
2422 " field {\n"
2423 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'foo' number: 1 "
2424 "json_name: 'bar'\n"
2425 " }\n"
2426 " field {\n"
2427 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'bar' number: 2\n"
2428 " }\n"
2429 "}\n");
2430 }
2431
TEST_F(ParserValidationErrorTest,Proto3CustomJsonConflictError)2432 TEST_F(ParserValidationErrorTest, Proto3CustomJsonConflictError) {
2433 ExpectHasValidationErrors(
2434 "syntax = 'proto3';\n"
2435 "message TestMessage {\n"
2436 " uint32 foo = 1 [json_name='baz'];\n"
2437 " uint32 bar = 2 [json_name='baz'];\n"
2438 "}\n",
2439 "3:9: The custom JSON name of field \"bar\" (\"baz\") conflicts "
2440 "with the custom JSON name of field \"foo\".\n");
2441 }
2442
TEST_F(ParserValidationErrorTest,Proto2CustomJsonConflictError)2443 TEST_F(ParserValidationErrorTest, Proto2CustomJsonConflictError) {
2444 ExpectHasValidationErrors(
2445 "syntax = 'proto2';\n"
2446 "message TestMessage {\n"
2447 " optional uint32 foo = 1 [json_name='baz'];\n"
2448 " optional uint32 bar = 2 [json_name='baz'];\n"
2449 "}\n",
2450 "3:18: The custom JSON name of field \"bar\" (\"baz\") conflicts "
2451 "with the custom JSON name of field \"foo\".\n");
2452 }
2453
TEST_F(ParserValidationErrorTest,Proto3JsonConflictLegacy)2454 TEST_F(ParserValidationErrorTest, Proto3JsonConflictLegacy) {
2455 ExpectParsesTo(
2456 "syntax = 'proto3';\n"
2457 "message TestMessage {\n"
2458 " option deprecated_legacy_json_field_conflicts = true;\n"
2459 " uint32 fooBar = 1;\n"
2460 " uint32 foo_bar = 2;\n"
2461 "}\n",
2462 "syntax: 'proto3'\n"
2463 "message_type {\n"
2464 " name: 'TestMessage'\n"
2465 " field {\n"
2466 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'fooBar' number: 1\n"
2467 " }\n"
2468 " field {\n"
2469 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'foo_bar' number: 2\n"
2470 " }\n"
2471 " options {\n"
2472 " uninterpreted_option {\n"
2473 " name {\n"
2474 " name_part: 'deprecated_legacy_json_field_conflicts'\n"
2475 " is_extension: false\n"
2476 " }\n"
2477 " identifier_value: 'true'\n"
2478 " }\n"
2479 " }\n"
2480 "}\n");
2481 }
2482
TEST_F(ParserValidationErrorTest,Proto2JsonConflictLegacy)2483 TEST_F(ParserValidationErrorTest, Proto2JsonConflictLegacy) {
2484 ExpectParsesTo(
2485 "syntax = 'proto2';\n"
2486 "message TestMessage {\n"
2487 " option deprecated_legacy_json_field_conflicts = true;\n"
2488 " optional uint32 fooBar = 1;\n"
2489 " optional uint32 foo_bar = 2;\n"
2490 "}\n",
2491 "syntax: 'proto2'\n"
2492 "message_type {\n"
2493 " name: 'TestMessage'\n"
2494 " field {\n"
2495 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'fooBar' number: 1\n"
2496 " }\n"
2497 " field {\n"
2498 " label: LABEL_OPTIONAL type: TYPE_UINT32 name: 'foo_bar' number: 2\n"
2499 " }\n"
2500 " options {\n"
2501 " uninterpreted_option {\n"
2502 " name {\n"
2503 " name_part: 'deprecated_legacy_json_field_conflicts'\n"
2504 " is_extension: false\n"
2505 " }\n"
2506 " identifier_value: 'true'\n"
2507 " }\n"
2508 " }\n"
2509 "}\n");
2510 }
2511
TEST_F(ParserValidationErrorTest,EnumNameError)2512 TEST_F(ParserValidationErrorTest, EnumNameError) {
2513 ExpectHasValidationErrors(
2514 "enum Foo {A = 1;}\n"
2515 "enum Foo {B = 1;}\n",
2516 "1:5: \"Foo\" is already defined.\n");
2517 }
2518
TEST_F(ParserValidationErrorTest,Proto3EnumError)2519 TEST_F(ParserValidationErrorTest, Proto3EnumError) {
2520 ExpectHasValidationErrors(
2521 "syntax = 'proto3';\n"
2522 "enum Foo {A = 1;}\n",
2523 "1:14: The first enum value must be zero for open enums.\n");
2524 }
2525
TEST_F(ParserValidationErrorTest,EnumValueNameError)2526 TEST_F(ParserValidationErrorTest, EnumValueNameError) {
2527 ExpectHasValidationErrors(
2528 "enum Foo {\n"
2529 " BAR = 1;\n"
2530 " BAR = 1;\n"
2531 "}\n",
2532 "2:2: \"BAR\" is already defined.\n");
2533 }
2534
TEST_F(ParserValidationErrorTest,EnumValueAliasError)2535 TEST_F(ParserValidationErrorTest, EnumValueAliasError) {
2536 ExpectHasValidationErrors(
2537 "enum Foo {\n"
2538 " BAR = 1;\n"
2539 " BAZ = 1;\n"
2540 "}\n",
2541 "2:8: \"BAZ\" uses the same enum value as \"BAR\". If this is "
2542 "intended, set 'option allow_alias = true;' to the enum "
2543 "definition. The next available enum value is 2.\n");
2544 }
2545
TEST_F(ParserValidationErrorTest,EnumReservedRangeError)2546 TEST_F(ParserValidationErrorTest, EnumReservedRangeError) {
2547 ExpectHasValidationErrors(
2548 "enum Foo {\n"
2549 " BAR = 1;\n"
2550 " reserved 2 to 1;\n"
2551 "}\n",
2552 "2:11: Reserved range end number must be greater than start number.\n");
2553 }
2554
TEST_F(ParserValidationErrorTest,ExplicitlyMapEntryError)2555 TEST_F(ParserValidationErrorTest, ExplicitlyMapEntryError) {
2556 ExpectHasErrors(
2557 "message Foo {\n"
2558 " message ValueEntry {\n"
2559 " option map_entry = true;\n"
2560 " optional int32 key = 1;\n"
2561 " optional int32 value = 2;\n"
2562 " extensions 99 to 999;\n"
2563 " }\n"
2564 "}",
2565 "2:11: map_entry should not be set explicitly. Use "
2566 "map<KeyType, ValueType> instead.\n");
2567 }
2568
TEST_F(ParserValidationErrorTest,ServiceNameError)2569 TEST_F(ParserValidationErrorTest, ServiceNameError) {
2570 ExpectHasValidationErrors(
2571 "service Foo {}\n"
2572 "service Foo {}\n",
2573 "1:8: \"Foo\" is already defined.\n");
2574 }
2575
TEST_F(ParserValidationErrorTest,MethodNameError)2576 TEST_F(ParserValidationErrorTest, MethodNameError) {
2577 ExpectHasValidationErrors(
2578 "message Baz {}\n"
2579 "service Foo {\n"
2580 " rpc Bar(Baz) returns(Baz);\n"
2581 " rpc Bar(Baz) returns(Baz);\n"
2582 "}\n",
2583 "3:6: \"Bar\" is already defined in \"Foo\".\n");
2584 }
2585
2586
TEST_F(ParserValidationErrorTest,MethodInputTypeError)2587 TEST_F(ParserValidationErrorTest, MethodInputTypeError) {
2588 ExpectHasValidationErrors(
2589 "message Baz {}\n"
2590 "service Foo {\n"
2591 " rpc Bar(Qux) returns(Baz);\n"
2592 "}\n",
2593 "2:10: \"Qux\" is not defined.\n");
2594 }
2595
2596
TEST_F(ParserValidationErrorTest,MethodOutputTypeError)2597 TEST_F(ParserValidationErrorTest, MethodOutputTypeError) {
2598 ExpectHasValidationErrors(
2599 "message Baz {}\n"
2600 "service Foo {\n"
2601 " rpc Bar(Baz) returns(Qux);\n"
2602 "}\n",
2603 "2:23: \"Qux\" is not defined.\n");
2604 }
2605
2606
TEST_F(ParserValidationErrorTest,ResolvedUndefinedError)2607 TEST_F(ParserValidationErrorTest, ResolvedUndefinedError) {
2608 // Create another file which defines symbol ".base.bar".
2609 FileDescriptorProto other_file;
2610 other_file.set_name("base.proto");
2611 other_file.set_package("base");
2612 other_file.add_message_type()->set_name("bar");
2613 EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
2614
2615 // Define "foo.base" and try "base.bar".
2616 // "base.bar" is resolved to "foo.base.bar" which is not defined.
2617 ExpectHasValidationErrors(
2618 "package foo.base;\n"
2619 "import \"base.proto\";\n"
2620 "message qux {\n"
2621 " optional base.bar baz = 1;\n"
2622 " optional .base.bar quz = 2;\n"
2623 "}\n",
2624 "3:11: \"base.bar\" is resolved to \"foo.base.bar\","
2625 " which is not defined. The innermost scope is searched first "
2626 "in name resolution. Consider using a leading '.'(i.e., \".base.bar\")"
2627 " to start from the outermost scope.\n");
2628 }
2629
TEST_F(ParserValidationErrorTest,ResolvedUndefinedOptionError)2630 TEST_F(ParserValidationErrorTest, ResolvedUndefinedOptionError) {
2631 // Build descriptor message in test pool
2632 FileDescriptorProto descriptor_proto;
2633 DescriptorProto::descriptor()->file()->CopyTo(&descriptor_proto);
2634 ASSERT_TRUE(pool_.BuildFile(descriptor_proto) != nullptr);
2635
2636 // base2.proto:
2637 // package baz
2638 // import google/protobuf/descriptor.proto
2639 // message Bar { optional int32 foo = 1; }
2640 // extend FileOptions { optional Bar bar = 7672757; }
2641 FileDescriptorProto other_file;
2642 other_file.set_name("base2.proto");
2643 other_file.set_package("baz");
2644 other_file.add_dependency();
2645 other_file.set_dependency(0, descriptor_proto.name());
2646
2647 DescriptorProto* message(other_file.add_message_type());
2648 message->set_name("Bar");
2649 FieldDescriptorProto* field(message->add_field());
2650 field->set_name("foo");
2651 field->set_number(1);
2652 field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
2653 field->set_type(FieldDescriptorProto::TYPE_INT32);
2654
2655 FieldDescriptorProto* extension(other_file.add_extension());
2656 extension->set_name("bar");
2657 extension->set_number(7672757);
2658 extension->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
2659 extension->set_type(FieldDescriptorProto::TYPE_MESSAGE);
2660 extension->set_type_name("Bar");
2661 extension->set_extendee("google.protobuf.FileOptions");
2662
2663 EXPECT_TRUE(pool_.BuildFile(other_file) != nullptr);
2664
2665 // qux.proto:
2666 // package qux.baz
2667 // option (baz.bar).foo = 1;
2668 //
2669 // Although "baz.bar" is already defined, the lookup code will try
2670 // "qux.baz.bar", since it's the match from the innermost scope,
2671 // which will cause a symbol not defined error.
2672 ExpectHasValidationErrors(
2673 "package qux.baz;\n"
2674 "import \"base2.proto\";\n"
2675 "option (baz.bar).foo = 1;\n",
2676 "2:7: Option \"(baz.bar)\" is resolved to \"(qux.baz.bar)\","
2677 " which is not defined. The innermost scope is searched first "
2678 "in name resolution. Consider using a leading '.'(i.e., \"(.baz.bar)\")"
2679 " to start from the outermost scope.\n");
2680 }
2681
2682 // ===================================================================
2683 // Test that the output from FileDescriptor::DebugString() (and all other
2684 // descriptor types) is parseable, and results in the same Descriptor
2685 // definitions again afoter parsing (note, however, that the order of messages
2686 // cannot be guaranteed to be the same)
2687
2688 typedef ParserTest ParseDescriptorDebugTest;
2689
2690 class CompareDescriptorNames {
2691 public:
operator ()(const DescriptorProto * left,const DescriptorProto * right) const2692 bool operator()(const DescriptorProto* left,
2693 const DescriptorProto* right) const {
2694 return left->name() < right->name();
2695 }
2696 };
2697
2698 // Sorts nested DescriptorProtos of a DescriptorProto, by name.
SortMessages(DescriptorProto * descriptor_proto)2699 void SortMessages(DescriptorProto* descriptor_proto) {
2700 int size = descriptor_proto->nested_type_size();
2701 // recursively sort; we can't guarantee the order of nested messages either
2702 for (int i = 0; i < size; ++i) {
2703 SortMessages(descriptor_proto->mutable_nested_type(i));
2704 }
2705 DescriptorProto** data =
2706 descriptor_proto->mutable_nested_type()->mutable_data();
2707 std::sort(data, data + size, CompareDescriptorNames());
2708 }
2709
2710 // Sorts DescriptorProtos belonging to a FileDescriptorProto, by name.
SortMessages(FileDescriptorProto * file_descriptor_proto)2711 void SortMessages(FileDescriptorProto* file_descriptor_proto) {
2712 int size = file_descriptor_proto->message_type_size();
2713 // recursively sort; we can't guarantee the order of nested messages either
2714 for (int i = 0; i < size; ++i) {
2715 SortMessages(file_descriptor_proto->mutable_message_type(i));
2716 }
2717 DescriptorProto** data =
2718 file_descriptor_proto->mutable_message_type()->mutable_data();
2719 std::sort(data, data + size, CompareDescriptorNames());
2720 }
2721
2722 // Strips the message and enum field type names for comparison purpose only.
StripFieldTypeName(DescriptorProto * proto)2723 void StripFieldTypeName(DescriptorProto* proto) {
2724 for (int i = 0; i < proto->field_size(); ++i) {
2725 std::string type_name = proto->field(i).type_name();
2726 std::string::size_type pos = type_name.find_last_of('.');
2727 if (pos != std::string::npos) {
2728 proto->mutable_field(i)->mutable_type_name()->assign(
2729 type_name.begin() + pos + 1, type_name.end());
2730 }
2731 }
2732 for (int i = 0; i < proto->nested_type_size(); ++i) {
2733 StripFieldTypeName(proto->mutable_nested_type(i));
2734 }
2735 }
2736
StripFieldTypeName(FileDescriptorProto * file_proto)2737 void StripFieldTypeName(FileDescriptorProto* file_proto) {
2738 for (int i = 0; i < file_proto->message_type_size(); ++i) {
2739 StripFieldTypeName(file_proto->mutable_message_type(i));
2740 }
2741 }
2742
StripEmptyOptions(DescriptorProto & proto)2743 void StripEmptyOptions(DescriptorProto& proto) {
2744 for (auto& ext : *proto.mutable_extension_range()) {
2745 if (ext.has_options() && ext.options().DebugString().empty()) {
2746 ext.clear_options();
2747 }
2748 }
2749 }
2750
StripEmptyOptions(FileDescriptorProto & file_proto)2751 void StripEmptyOptions(FileDescriptorProto& file_proto) {
2752 if (file_proto.message_type_size() == 0) {
2753 return;
2754 }
2755 for (auto& msg : *file_proto.mutable_message_type()) {
2756 StripEmptyOptions(msg);
2757 }
2758 }
2759
TEST_F(ParseDescriptorDebugTest,TestAllDescriptorTypes)2760 TEST_F(ParseDescriptorDebugTest, TestAllDescriptorTypes) {
2761 const FileDescriptor* original_file =
2762 protobuf_unittest::TestAllTypes::descriptor()->file();
2763 FileDescriptorProto expected;
2764 original_file->CopyTo(&expected);
2765 StripEmptyOptions(expected);
2766
2767 // Get the DebugString of the unittest.proto FileDescriptor, which includes
2768 // all other descriptor types
2769 std::string debug_string = original_file->DebugString();
2770
2771 // Parse the debug string
2772 SetupParser(debug_string.c_str());
2773 FileDescriptorProto parsed;
2774 parser_->Parse(input_.get(), &parsed);
2775 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
2776 ASSERT_EQ("", error_collector_.text_) << "Failed to parse:\n" << debug_string;
2777
2778 // We now have a FileDescriptorProto, but to compare with the expected we
2779 // need to link to a FileDescriptor, then output back to a proto. We'll
2780 // also need to give it the same name as the original.
2781 parsed.set_name("google/protobuf/unittest.proto");
2782 // We need the imported dependency before we can build our parsed proto
2783 const FileDescriptor* public_import =
2784 protobuf_unittest_import::PublicImportMessage::descriptor()->file();
2785 FileDescriptorProto public_import_proto;
2786 public_import->CopyTo(&public_import_proto);
2787 ASSERT_TRUE(pool_.BuildFile(public_import_proto) != nullptr);
2788 const FileDescriptor* import =
2789 protobuf_unittest_import::ImportMessage::descriptor()->file();
2790 FileDescriptorProto import_proto;
2791 import->CopyTo(&import_proto);
2792 ASSERT_TRUE(pool_.BuildFile(import_proto) != nullptr);
2793 const FileDescriptor* actual = pool_.BuildFile(parsed);
2794 parsed.Clear();
2795 ASSERT_TRUE(actual != nullptr) << "Failed to validate:\n" << debug_string;
2796 actual->CopyTo(&parsed);
2797 ASSERT_TRUE(actual != nullptr);
2798
2799 // The messages might be in different orders, making them hard to compare.
2800 // So, sort the messages in the descriptor protos (including nested messages,
2801 // recursively).
2802 SortMessages(&expected);
2803 SortMessages(&parsed);
2804
2805 // I really wanted to use StringDiff here for the debug output on fail,
2806 // but the strings are too long for it, and if I increase its max size,
2807 // we get a memory allocation failure :(
2808 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
2809 }
2810
TEST_F(ParseDescriptorDebugTest,TestCustomOptions)2811 TEST_F(ParseDescriptorDebugTest, TestCustomOptions) {
2812 const FileDescriptor* original_file =
2813 protobuf_unittest::AggregateMessage::descriptor()->file();
2814 FileDescriptorProto expected;
2815 original_file->CopyTo(&expected);
2816
2817 std::string debug_string = original_file->DebugString();
2818
2819 // Parse the debug string
2820 SetupParser(debug_string.c_str());
2821 FileDescriptorProto parsed;
2822 parser_->Parse(input_.get(), &parsed);
2823 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
2824 ASSERT_EQ("", error_collector_.text_);
2825
2826 // We now have a FileDescriptorProto, but to compare with the expected we
2827 // need to link to a FileDescriptor, then output back to a proto. We'll
2828 // also need to give it the same name as the original.
2829 parsed.set_name(original_file->name());
2830
2831 // unittest_custom_options.proto depends on descriptor.proto.
2832 const FileDescriptor* import = FileDescriptorProto::descriptor()->file();
2833 FileDescriptorProto import_proto;
2834 import->CopyTo(&import_proto);
2835 ASSERT_TRUE(pool_.BuildFile(import_proto) != nullptr);
2836
2837 FileDescriptorProto any_import;
2838 google::protobuf::Any::descriptor()->file()->CopyTo(&any_import);
2839 ASSERT_TRUE(pool_.BuildFile(any_import) != nullptr);
2840
2841 const FileDescriptor* actual = pool_.BuildFile(parsed);
2842 ASSERT_TRUE(actual != nullptr) << error_collector_.text_;
2843 parsed.Clear();
2844 actual->CopyTo(&parsed);
2845
2846 // The messages might be in different orders, making them hard to compare.
2847 // So, sort the messages in the descriptor protos (including nested messages,
2848 // recursively).
2849 SortMessages(&expected);
2850 SortMessages(&parsed);
2851
2852 EXPECT_EQ(expected.DebugString(), parsed.DebugString());
2853 }
2854
2855 // Ensure that DebugStringWithOptions(), with |include_comments| set to true,
2856 // includes comments from the original parser input in all of the appropriate
2857 // places.
TEST_F(ParseDescriptorDebugTest,TestCommentsInDebugString)2858 TEST_F(ParseDescriptorDebugTest, TestCommentsInDebugString) {
2859 SetupParser(
2860 "// Detached comment before syntax.\n"
2861 "\n"
2862 "// Syntax comment.\n"
2863 "syntax = \"proto2\";\n"
2864 "\n"
2865 "// Detached comment before package.\n"
2866 "\n"
2867 "// Package comment.\n"
2868 "package comment_test;\n"
2869 "\n"
2870 "// Detached comment before TestMessage1.\n"
2871 "\n"
2872 "// Message comment.\n"
2873 "//\n"
2874 "// More detail in message comment.\n"
2875 "message TestMessage1 {\n"
2876 "\n"
2877 " // Detached comment before foo.\n"
2878 "\n"
2879 " // Field comment.\n"
2880 " optional int32 foo = 1;\n"
2881 "\n"
2882 " // Detached comment before NestedMessage.\n"
2883 "\n"
2884 " // Nested-message comment.\n"
2885 " message NestedMessage {\n"
2886 " optional int32 bar = 1;\n"
2887 " }\n"
2888 "}\n"
2889 "\n"
2890 "// Detached comment before MyEnumType.\n"
2891 "\n"
2892 "// Enum comment.\n"
2893 "enum MyEnumType {\n"
2894 "\n"
2895 " // Detached comment before ASDF.\n"
2896 "\n"
2897 " // Enum-value comment.\n"
2898 " ASDF = 1;\n"
2899 "}\n"
2900 "\n"
2901 "// Detached comment before MyService.\n"
2902 "\n"
2903 "// Service comment.\n"
2904 "service MyService {\n"
2905 "\n"
2906 " // Detached comment before MyRPCCall.\n"
2907 "\n"
2908 " // RPC comment.\n"
2909 " rpc MyRPCCall(TestMessage1) returns (TestMessage1) { }\n"
2910 "}\n");
2911
2912 FileDescriptorProto parsed_desc;
2913 parsed_desc.set_name("foo.proto");
2914 SourceLocationTable source_locations;
2915 parser_->RecordSourceLocationsTo(&source_locations);
2916 parser_->Parse(input_.get(), &parsed_desc);
2917 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
2918 ASSERT_EQ("", error_collector_.text_);
2919
2920 // We need to import the FileDescriptorProto to get a FileDescriptor.
2921 MockValidationErrorCollector collector(source_locations, &error_collector_);
2922 const FileDescriptor* descriptor =
2923 pool_.BuildFileCollectingErrors(parsed_desc, &collector);
2924 ASSERT_TRUE(descriptor != nullptr);
2925
2926 // Ensure that each of the comments appears somewhere in the DebugString().
2927 // We don't test the exact comment placement or formatting, because we do not
2928 // want to be too fragile here.
2929 const char* expected_comments[] = {
2930 "Detached comment before syntax.",
2931 "Syntax comment.",
2932 "Detached comment before package.",
2933 "Package comment.",
2934 "Detached comment before TestMessage1.",
2935 "Message comment.",
2936 "More detail in message comment.",
2937 "Detached comment before foo.",
2938 "Field comment",
2939 "Detached comment before NestedMessage.",
2940 "Nested-message comment",
2941 "Detached comment before MyEnumType.",
2942 "Enum comment",
2943 "Detached comment before ASDF.",
2944 "Enum-value comment",
2945 "Detached comment before MyService.",
2946 "Service comment",
2947 "Detached comment before MyRPCCall.",
2948 "RPC comment",
2949 };
2950
2951 DebugStringOptions debug_string_options;
2952 debug_string_options.include_comments = true;
2953
2954 {
2955 const std::string debug_string =
2956 descriptor->DebugStringWithOptions(debug_string_options);
2957
2958 for (int i = 0; i < ABSL_ARRAYSIZE(expected_comments); ++i) {
2959 std::string::size_type found_pos =
2960 debug_string.find(expected_comments[i]);
2961 EXPECT_TRUE(found_pos != std::string::npos)
2962 << "\"" << expected_comments[i] << "\" not found.";
2963 }
2964
2965 // Result of DebugStringWithOptions should be parseable.
2966 SetupParser(debug_string.c_str());
2967 FileDescriptorProto parsed;
2968 parser_->Parse(input_.get(), &parsed);
2969 EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
2970 ASSERT_EQ("", error_collector_.text_) << "Failed to parse:\n"
2971 << debug_string;
2972 }
2973
2974 }
2975
TEST_F(ParseDescriptorDebugTest,TestMaps)2976 TEST_F(ParseDescriptorDebugTest, TestMaps) {
2977 SetupParser(
2978 "syntax = \"proto3\"; "
2979 "message Foo { "
2980 " message Bar { } "
2981 " map<int32, Bar> enum_message_map = 1; "
2982 " map<string, float> primitive_map = 2; "
2983 "} ");
2984 FileDescriptorProto original;
2985 EXPECT_TRUE(parser_->Parse(input_.get(), &original));
2986 original.set_name("foo.proto");
2987 const FileDescriptor* file = pool_.BuildFile(original);
2988 ASSERT_TRUE(file != nullptr);
2989
2990 // Make sure the debug string uses map syntax and does not have the auto
2991 // generated entry.
2992 std::string debug_string = file->DebugString();
2993 EXPECT_TRUE(debug_string.find("map<") != std::string::npos);
2994 EXPECT_TRUE(debug_string.find("option map_entry") == std::string::npos);
2995 EXPECT_TRUE(debug_string.find("MapEntry") == std::string::npos);
2996
2997 // Make sure the descriptor debug string is parsable.
2998 FileDescriptorProto parsed;
2999 SetupParser(debug_string.c_str());
3000 parsed.set_name("foo.proto");
3001 ASSERT_TRUE(parser_->Parse(input_.get(), &parsed));
3002
3003 original.clear_source_code_info();
3004 parsed.clear_source_code_info();
3005 StripFieldTypeName(&original);
3006 StripFieldTypeName(&parsed);
3007 EXPECT_EQ(original.DebugString(), parsed.DebugString());
3008 }
3009
3010 // ===================================================================
3011 // SourceCodeInfo tests.
3012
3013 // Follows a path -- as defined by SourceCodeInfo.Location.path -- from a
3014 // message to a particular sub-field.
3015 // * If the target is itself a message, sets *output_message to point at it,
3016 // *output_field to NULL, and *output_index to -1.
3017 // * Otherwise, if the target is an element of a repeated field, sets
3018 // *output_message to the containing message, *output_field to the descriptor
3019 // of the field, and *output_index to the index of the element.
3020 // * Otherwise, the target is a field (possibly a repeated field, but not any
3021 // one element). Sets *output_message to the containing message,
3022 // *output_field to the descriptor of the field, and *output_index to -1.
3023 // Returns true if the path was valid, false otherwise. A gTest failure is
3024 // recorded before returning false.
FollowPath(const Message & root,RepeatedField<int>::const_iterator path_begin,RepeatedField<int>::const_iterator path_end,const Message ** output_message,const FieldDescriptor ** output_field,int * output_index)3025 bool FollowPath(const Message& root,
3026 RepeatedField<int>::const_iterator path_begin,
3027 RepeatedField<int>::const_iterator path_end,
3028 const Message** output_message,
3029 const FieldDescriptor** output_field, int* output_index) {
3030 if (path_begin == path_end) {
3031 // Path refers to this whole message.
3032 *output_message = &root;
3033 *output_field = nullptr;
3034 *output_index = -1;
3035 return true;
3036 }
3037
3038 const Descriptor* descriptor = root.GetDescriptor();
3039 const Reflection* reflection = root.GetReflection();
3040
3041 const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
3042
3043 if (field == nullptr) {
3044 ADD_FAILURE() << descriptor->name()
3045 << " has no field number: " << *path_begin;
3046 return false;
3047 }
3048
3049 ++path_begin;
3050
3051 if (field->is_repeated()) {
3052 if (path_begin == path_end) {
3053 // Path refers to the whole repeated field.
3054 *output_message = &root;
3055 *output_field = field;
3056 *output_index = -1;
3057 return true;
3058 }
3059
3060 int index = *path_begin++;
3061 int size = reflection->FieldSize(root, field);
3062
3063 if (index >= size) {
3064 ADD_FAILURE() << descriptor->name() << "." << field->name()
3065 << " has size " << size
3066 << ", but path contained index: " << index;
3067 return false;
3068 }
3069
3070 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
3071 // Descend into child message.
3072 const Message& child = reflection->GetRepeatedMessage(root, field, index);
3073 return FollowPath(child, path_begin, path_end, output_message,
3074 output_field, output_index);
3075 } else if (path_begin == path_end) {
3076 // Path refers to this element.
3077 *output_message = &root;
3078 *output_field = field;
3079 *output_index = index;
3080 return true;
3081 } else {
3082 ADD_FAILURE() << descriptor->name() << "." << field->name()
3083 << " is not a message; cannot descend into it.";
3084 return false;
3085 }
3086 } else {
3087 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
3088 const Message& child = reflection->GetMessage(root, field);
3089 return FollowPath(child, path_begin, path_end, output_message,
3090 output_field, output_index);
3091 } else if (path_begin == path_end) {
3092 // Path refers to this field.
3093 *output_message = &root;
3094 *output_field = field;
3095 *output_index = -1;
3096 return true;
3097 } else {
3098 ADD_FAILURE() << descriptor->name() << "." << field->name()
3099 << " is not a message; cannot descend into it.";
3100 return false;
3101 }
3102 }
3103 }
3104
3105 // Check if two spans are equal.
CompareSpans(const RepeatedField<int> & span1,const RepeatedField<int> & span2)3106 bool CompareSpans(const RepeatedField<int>& span1,
3107 const RepeatedField<int>& span2) {
3108 if (span1.size() != span2.size()) return false;
3109 for (int i = 0; i < span1.size(); i++) {
3110 if (span1.Get(i) != span2.Get(i)) return false;
3111 }
3112 return true;
3113 }
3114
3115 // Test fixture for source info tests, which check that source locations are
3116 // recorded correctly in FileDescriptorProto.source_code_info.location.
3117 class SourceInfoTest : public ParserTest {
3118 protected:
3119 // The parsed file (initialized by Parse()).
3120 FileDescriptorProto file_;
3121
3122 // Parse the given text as a .proto file and populate the spans_ map with
3123 // all the source location spans in its SourceCodeInfo table.
Parse(const char * text)3124 bool Parse(const char* text) {
3125 ExtractMarkers(text);
3126 SetupParser(text_without_markers_.c_str());
3127 if (!parser_->Parse(input_.get(), &file_)) {
3128 return false;
3129 }
3130
3131 const SourceCodeInfo& source_info = file_.source_code_info();
3132 for (int i = 0; i < source_info.location_size(); i++) {
3133 const SourceCodeInfo::Location& location = source_info.location(i);
3134 const Message* descriptor_proto = nullptr;
3135 const FieldDescriptor* field = nullptr;
3136 int index = 0;
3137 if (!FollowPath(file_, location.path().begin(), location.path().end(),
3138 &descriptor_proto, &field, &index)) {
3139 return false;
3140 }
3141
3142 spans_[SpanKey(*descriptor_proto, field, index)].push_back(&location);
3143 }
3144
3145 return true;
3146 }
3147
TearDown()3148 void TearDown() override {
3149 for (auto& kv : spans_) {
3150 EXPECT_TRUE(kv.second.empty())
3151 << "Forgot to call HasSpan() for "
3152 << (*kv.second.begin())->DebugString() << " spans.";
3153 }
3154 }
3155
3156 // -----------------------------------------------------------------
3157 // HasSpan() checks that the span of source code delimited by the given
3158 // tags (comments) correspond via the SourceCodeInfo table to the given
3159 // part of the FileDescriptorProto. (If unclear, look at the actual tests;
3160 // it should quickly become obvious.)
3161
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto)3162 bool HasSpan(char start_marker, char end_marker,
3163 const Message& descriptor_proto) {
3164 return HasSpanWithComment(start_marker, end_marker, descriptor_proto,
3165 nullptr, -1, nullptr, nullptr, nullptr);
3166 }
3167
HasSpanWithComment(char start_marker,char end_marker,const Message & descriptor_proto,const char * expected_leading_comments,const char * expected_trailing_comments,const char * expected_leading_detached_comments)3168 bool HasSpanWithComment(char start_marker, char end_marker,
3169 const Message& descriptor_proto,
3170 const char* expected_leading_comments,
3171 const char* expected_trailing_comments,
3172 const char* expected_leading_detached_comments) {
3173 return HasSpanWithComment(start_marker, end_marker, descriptor_proto,
3174 nullptr, -1, expected_leading_comments,
3175 expected_trailing_comments,
3176 expected_leading_detached_comments);
3177 }
3178
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto,const std::string & field_name)3179 bool HasSpan(char start_marker, char end_marker,
3180 const Message& descriptor_proto, const std::string& field_name) {
3181 return HasSpan(start_marker, end_marker, descriptor_proto, field_name, -1);
3182 }
3183
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto,const std::string & field_name,int index)3184 bool HasSpan(char start_marker, char end_marker,
3185 const Message& descriptor_proto, const std::string& field_name,
3186 int index) {
3187 return HasSpan(start_marker, end_marker, descriptor_proto, field_name,
3188 index, nullptr, nullptr, nullptr);
3189 }
3190
HasSpan(char start_marker,char end_marker,const Message & descriptor_proto,const std::string & field_name,int index,const char * expected_leading_comments,const char * expected_trailing_comments,const char * expected_leading_detached_comments)3191 bool HasSpan(char start_marker, char end_marker,
3192 const Message& descriptor_proto, const std::string& field_name,
3193 int index, const char* expected_leading_comments,
3194 const char* expected_trailing_comments,
3195 const char* expected_leading_detached_comments) {
3196 const FieldDescriptor* field =
3197 descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
3198 if (field == nullptr) {
3199 ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
3200 << " has no such field: " << field_name;
3201 return false;
3202 }
3203
3204 return HasSpanWithComment(start_marker, end_marker, descriptor_proto, field,
3205 index, expected_leading_comments,
3206 expected_trailing_comments,
3207 expected_leading_detached_comments);
3208 }
3209
HasSpan(const Message & descriptor_proto)3210 bool HasSpan(const Message& descriptor_proto) {
3211 return HasSpanWithComment('\0', '\0', descriptor_proto, nullptr, -1,
3212 nullptr, nullptr, nullptr);
3213 }
3214
HasSpan(const Message & descriptor_proto,const std::string & field_name)3215 bool HasSpan(const Message& descriptor_proto, const std::string& field_name) {
3216 return HasSpan('\0', '\0', descriptor_proto, field_name, -1);
3217 }
3218
HasSpanWithComment(char start_marker,char end_marker,const Message & descriptor_proto,const FieldDescriptor * field,int index,const char * expected_leading_comments,const char * expected_trailing_comments,const char * expected_leading_detached_comments)3219 bool HasSpanWithComment(char start_marker, char end_marker,
3220 const Message& descriptor_proto,
3221 const FieldDescriptor* field, int index,
3222 const char* expected_leading_comments,
3223 const char* expected_trailing_comments,
3224 const char* expected_leading_detached_comments) {
3225 SpanKey key(descriptor_proto, field, index);
3226 if (start_marker == '\0') {
3227 auto old = spans_.extract(key);
3228 // Return true if we actually removed something.
3229 return !(old.empty() || old.mapped().empty());
3230 }
3231
3232 std::vector<const SourceCodeInfo::Location*>& range = spans_[key];
3233 std::pair<int, int> start_pos = markers_.at(start_marker);
3234 std::pair<int, int> end_pos = markers_.at(end_marker);
3235
3236 RepeatedField<int> expected_span;
3237 expected_span.Add(start_pos.first);
3238 expected_span.Add(start_pos.second);
3239 if (end_pos.first != start_pos.first) {
3240 expected_span.Add(end_pos.first);
3241 }
3242 expected_span.Add(end_pos.second);
3243
3244 for (auto iter = range.begin(); iter != range.end(); ++iter) {
3245 const SourceCodeInfo::Location* location = *iter;
3246 if (CompareSpans(expected_span, location->span())) {
3247 if (expected_leading_comments == nullptr) {
3248 EXPECT_FALSE(location->has_leading_comments());
3249 } else {
3250 EXPECT_TRUE(location->has_leading_comments());
3251 EXPECT_EQ(expected_leading_comments, location->leading_comments());
3252 }
3253 if (expected_trailing_comments == nullptr) {
3254 EXPECT_FALSE(location->has_trailing_comments());
3255 } else {
3256 EXPECT_TRUE(location->has_trailing_comments());
3257 EXPECT_EQ(expected_trailing_comments, location->trailing_comments());
3258 }
3259 if (expected_leading_detached_comments == nullptr) {
3260 EXPECT_EQ(0, location->leading_detached_comments_size());
3261 } else {
3262 EXPECT_EQ(expected_leading_detached_comments,
3263 absl::StrJoin(location->leading_detached_comments(), "\n"));
3264 }
3265 range.erase(iter);
3266 return true;
3267 }
3268 }
3269
3270 return false;
3271 }
3272
3273 private:
3274 struct SpanKey {
3275 const Message* descriptor_proto;
3276 const FieldDescriptor* field;
3277 int index;
3278
3279 inline SpanKey() = default;
SpanKeygoogle::protobuf::compiler::__anon78e44b510111::SourceInfoTest::SpanKey3280 inline SpanKey(const Message& descriptor_proto_param,
3281 const FieldDescriptor* field_param, int index_param)
3282 : descriptor_proto(&descriptor_proto_param),
3283 field(field_param),
3284 index(index_param) {}
3285
3286 template <typename H>
AbslHashValue(H h,const SpanKey & key)3287 friend H AbslHashValue(H h, const SpanKey& key) {
3288 return H::combine(std::move(h), key.descriptor_proto, key.field,
3289 key.index);
3290 }
3291
operator ==(const SpanKey & lhs,const SpanKey & rhs)3292 friend bool operator==(const SpanKey& lhs, const SpanKey& rhs) {
3293 return lhs.descriptor_proto == rhs.descriptor_proto && //
3294 lhs.field == rhs.field && //
3295 lhs.index == rhs.index;
3296 }
3297 };
3298
3299 absl::flat_hash_map<SpanKey, std::vector<const SourceCodeInfo::Location*>>
3300 spans_;
3301 absl::flat_hash_map<char, std::pair<int, int>> markers_;
3302 std::string text_without_markers_;
3303
ExtractMarkers(const char * text)3304 void ExtractMarkers(const char* text) {
3305 markers_.clear();
3306 text_without_markers_.clear();
3307 int line = 0;
3308 int column = 0;
3309 while (*text != '\0') {
3310 if (*text == '$') {
3311 ++text;
3312 ABSL_CHECK_NE('\0', *text);
3313 if (*text == '$') {
3314 text_without_markers_ += '$';
3315 ++column;
3316 } else {
3317 markers_[*text] = std::make_pair(line, column);
3318 ++text;
3319 ABSL_CHECK_EQ('$', *text);
3320 }
3321 } else if (*text == '\n') {
3322 ++line;
3323 column = 0;
3324 text_without_markers_ += *text;
3325 } else {
3326 text_without_markers_ += *text;
3327 ++column;
3328 }
3329 ++text;
3330 }
3331 }
3332 };
3333
TEST_F(SourceInfoTest,BasicFileDecls)3334 TEST_F(SourceInfoTest, BasicFileDecls) {
3335 EXPECT_TRUE(
3336 Parse("$a$syntax = \"proto2\";$i$\n"
3337 "$b$package foo.bar;$c$\n"
3338 "$d$import \"baz.proto\";$e$\n"
3339 "$f$import\"qux.proto\";$h$\n"
3340 "$j$import $k$public$l$ \"bar.proto\";$m$\n"
3341 "$n$import $o$weak$p$ \"bar.proto\";$q$\n"
3342 "\n"
3343 "// comment ignored\n"));
3344
3345 EXPECT_TRUE(HasSpan('a', 'q', file_));
3346 EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
3347 EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
3348 EXPECT_TRUE(HasSpan('f', 'h', file_, "dependency", 1));
3349 EXPECT_TRUE(HasSpan('j', 'm', file_, "dependency", 2));
3350 EXPECT_TRUE(HasSpan('k', 'l', file_, "public_dependency", 0));
3351 EXPECT_TRUE(HasSpan('n', 'q', file_, "dependency", 3));
3352 EXPECT_TRUE(HasSpan('o', 'p', file_, "weak_dependency", 0));
3353 EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
3354 }
3355
TEST_F(SourceInfoTest,Messages)3356 TEST_F(SourceInfoTest, Messages) {
3357 EXPECT_TRUE(
3358 Parse("$a$message $b$Foo$c$ {}$d$\n"
3359 "$e$message $f$Bar$g$ {}$h$\n"));
3360
3361 EXPECT_TRUE(HasSpan('a', 'd', file_.message_type(0)));
3362 EXPECT_TRUE(HasSpan('b', 'c', file_.message_type(0), "name"));
3363 EXPECT_TRUE(HasSpan('e', 'h', file_.message_type(1)));
3364 EXPECT_TRUE(HasSpan('f', 'g', file_.message_type(1), "name"));
3365
3366 // Ignore these.
3367 EXPECT_TRUE(HasSpan(file_));
3368 }
3369
TEST_F(SourceInfoTest,Fields)3370 TEST_F(SourceInfoTest, Fields) {
3371 EXPECT_TRUE(
3372 Parse("message Foo {\n"
3373 " $a$optional$b$ $c$int32$d$ $e$bar$f$ = $g$1$h$;$i$\n"
3374 " $j$repeated$k$ $l$X.Y$m$ $n$baz$o$ = $p$2$q$;$r$\n"
3375 "}\n"));
3376
3377 const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
3378 const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
3379
3380 EXPECT_TRUE(HasSpan('a', 'i', field1));
3381 EXPECT_TRUE(HasSpan('a', 'b', field1, "label"));
3382 EXPECT_TRUE(HasSpan('c', 'd', field1, "type"));
3383 EXPECT_TRUE(HasSpan('e', 'f', field1, "name"));
3384 EXPECT_TRUE(HasSpan('g', 'h', field1, "number"));
3385
3386 EXPECT_TRUE(HasSpan('j', 'r', field2));
3387 EXPECT_TRUE(HasSpan('j', 'k', field2, "label"));
3388 EXPECT_TRUE(HasSpan('l', 'm', field2, "type_name"));
3389 EXPECT_TRUE(HasSpan('n', 'o', field2, "name"));
3390 EXPECT_TRUE(HasSpan('p', 'q', field2, "number"));
3391
3392 // Ignore these.
3393 EXPECT_TRUE(HasSpan(file_));
3394 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3395 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3396 }
3397
TEST_F(SourceInfoTest,Proto3Fields)3398 TEST_F(SourceInfoTest, Proto3Fields) {
3399 EXPECT_TRUE(
3400 Parse("syntax = \"proto3\";\n"
3401 "message Foo {\n"
3402 " $a$int32$b$ $c$bar$d$ = $e$1$f$;$g$\n"
3403 " $h$repeated$i$ $j$X.Y$k$ $l$baz$m$ = $n$2$o$;$p$\n"
3404 "}\n"));
3405
3406 const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
3407 const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
3408
3409 EXPECT_TRUE(HasSpan('a', 'g', field1));
3410 EXPECT_TRUE(HasSpan('a', 'b', field1, "type"));
3411 EXPECT_TRUE(HasSpan('c', 'd', field1, "name"));
3412 EXPECT_TRUE(HasSpan('e', 'f', field1, "number"));
3413
3414 EXPECT_TRUE(HasSpan('h', 'p', field2));
3415 EXPECT_TRUE(HasSpan('h', 'i', field2, "label"));
3416 EXPECT_TRUE(HasSpan('j', 'k', field2, "type_name"));
3417 EXPECT_TRUE(HasSpan('l', 'm', field2, "name"));
3418 EXPECT_TRUE(HasSpan('n', 'o', field2, "number"));
3419
3420 // Ignore these.
3421 EXPECT_TRUE(HasSpan(file_));
3422 EXPECT_TRUE(HasSpan(file_, "syntax"));
3423 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3424 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3425 }
3426
TEST_F(SourceInfoTest,Extensions)3427 TEST_F(SourceInfoTest, Extensions) {
3428 EXPECT_TRUE(
3429 Parse("$a$extend $b$Foo$c$ {\n"
3430 " $d$optional$e$ int32 bar = 1;$f$\n"
3431 " $g$repeated$h$ X.Y baz = 2;$i$\n"
3432 "}$j$\n"
3433 "$k$extend $l$Bar$m$ {\n"
3434 " $n$optional int32 qux = 1;$o$\n"
3435 "}$p$\n"));
3436
3437 const FieldDescriptorProto& field1 = file_.extension(0);
3438 const FieldDescriptorProto& field2 = file_.extension(1);
3439 const FieldDescriptorProto& field3 = file_.extension(2);
3440
3441 EXPECT_TRUE(HasSpan('a', 'j', file_, "extension"));
3442 EXPECT_TRUE(HasSpan('k', 'p', file_, "extension"));
3443
3444 EXPECT_TRUE(HasSpan('d', 'f', field1));
3445 EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
3446 EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
3447
3448 EXPECT_TRUE(HasSpan('g', 'i', field2));
3449 EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
3450 EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
3451
3452 EXPECT_TRUE(HasSpan('n', 'o', field3));
3453 EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
3454
3455 // Ignore these.
3456 EXPECT_TRUE(HasSpan(file_));
3457 EXPECT_TRUE(HasSpan(field1, "type"));
3458 EXPECT_TRUE(HasSpan(field1, "name"));
3459 EXPECT_TRUE(HasSpan(field1, "number"));
3460 EXPECT_TRUE(HasSpan(field2, "type_name"));
3461 EXPECT_TRUE(HasSpan(field2, "name"));
3462 EXPECT_TRUE(HasSpan(field2, "number"));
3463 EXPECT_TRUE(HasSpan(field3, "label"));
3464 EXPECT_TRUE(HasSpan(field3, "type"));
3465 EXPECT_TRUE(HasSpan(field3, "name"));
3466 EXPECT_TRUE(HasSpan(field3, "number"));
3467 }
3468
TEST_F(SourceInfoTest,NestedExtensions)3469 TEST_F(SourceInfoTest, NestedExtensions) {
3470 EXPECT_TRUE(
3471 Parse("message Message {\n"
3472 " $a$extend $b$Foo$c$ {\n"
3473 " $d$optional$e$ int32 bar = 1;$f$\n"
3474 " $g$repeated$h$ X.Y baz = 2;$i$\n"
3475 " }$j$\n"
3476 " $k$extend $l$Bar$m$ {\n"
3477 " $n$optional int32 qux = 1;$o$\n"
3478 " }$p$\n"
3479 "}\n"));
3480
3481 const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
3482 const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
3483 const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
3484
3485 EXPECT_TRUE(HasSpan('a', 'j', file_.message_type(0), "extension"));
3486 EXPECT_TRUE(HasSpan('k', 'p', file_.message_type(0), "extension"));
3487
3488 EXPECT_TRUE(HasSpan('d', 'f', field1));
3489 EXPECT_TRUE(HasSpan('d', 'e', field1, "label"));
3490 EXPECT_TRUE(HasSpan('b', 'c', field1, "extendee"));
3491
3492 EXPECT_TRUE(HasSpan('g', 'i', field2));
3493 EXPECT_TRUE(HasSpan('g', 'h', field2, "label"));
3494 EXPECT_TRUE(HasSpan('b', 'c', field2, "extendee"));
3495
3496 EXPECT_TRUE(HasSpan('n', 'o', field3));
3497 EXPECT_TRUE(HasSpan('l', 'm', field3, "extendee"));
3498
3499 // Ignore these.
3500 EXPECT_TRUE(HasSpan(file_));
3501 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3502 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3503 EXPECT_TRUE(HasSpan(field1, "type"));
3504 EXPECT_TRUE(HasSpan(field1, "name"));
3505 EXPECT_TRUE(HasSpan(field1, "number"));
3506 EXPECT_TRUE(HasSpan(field2, "type_name"));
3507 EXPECT_TRUE(HasSpan(field2, "name"));
3508 EXPECT_TRUE(HasSpan(field2, "number"));
3509 EXPECT_TRUE(HasSpan(field3, "label"));
3510 EXPECT_TRUE(HasSpan(field3, "type"));
3511 EXPECT_TRUE(HasSpan(field3, "name"));
3512 EXPECT_TRUE(HasSpan(field3, "number"));
3513 }
3514
TEST_F(SourceInfoTest,ExtensionRanges)3515 TEST_F(SourceInfoTest, ExtensionRanges) {
3516 EXPECT_TRUE(
3517 Parse("message Message {\n"
3518 " $a$extensions $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
3519 " $i$extensions $j$8$k$ to $l$max$m$;$n$\n"
3520 "}\n"));
3521
3522 const DescriptorProto::ExtensionRange& range1 =
3523 file_.message_type(0).extension_range(0);
3524 const DescriptorProto::ExtensionRange& range2 =
3525 file_.message_type(0).extension_range(1);
3526 const DescriptorProto::ExtensionRange& range3 =
3527 file_.message_type(0).extension_range(2);
3528
3529 EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "extension_range"));
3530 EXPECT_TRUE(HasSpan('i', 'n', file_.message_type(0), "extension_range"));
3531
3532 EXPECT_TRUE(HasSpan('b', 'e', range1));
3533 EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
3534 EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
3535
3536 EXPECT_TRUE(HasSpan('f', 'g', range2));
3537 EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
3538 EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
3539
3540 EXPECT_TRUE(HasSpan('j', 'm', range3));
3541 EXPECT_TRUE(HasSpan('j', 'k', range3, "start"));
3542 EXPECT_TRUE(HasSpan('l', 'm', range3, "end"));
3543
3544 // Ignore these.
3545 EXPECT_TRUE(HasSpan(file_));
3546 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3547 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3548 }
3549
TEST_F(SourceInfoTest,ReservedRanges)3550 TEST_F(SourceInfoTest, ReservedRanges) {
3551 EXPECT_TRUE(
3552 Parse("message Message {\n"
3553 " $a$reserved $b$1$c$ to $d$4$e$, $f$6$g$;$h$\n"
3554 "}\n"));
3555
3556 const DescriptorProto::ReservedRange& range1 =
3557 file_.message_type(0).reserved_range(0);
3558 const DescriptorProto::ReservedRange& range2 =
3559 file_.message_type(0).reserved_range(1);
3560
3561 EXPECT_TRUE(HasSpan('a', 'h', file_.message_type(0), "reserved_range"));
3562
3563 EXPECT_TRUE(HasSpan('b', 'e', range1));
3564 EXPECT_TRUE(HasSpan('b', 'c', range1, "start"));
3565 EXPECT_TRUE(HasSpan('d', 'e', range1, "end"));
3566
3567 EXPECT_TRUE(HasSpan('f', 'g', range2));
3568 EXPECT_TRUE(HasSpan('f', 'g', range2, "start"));
3569 EXPECT_TRUE(HasSpan('f', 'g', range2, "end"));
3570
3571 // Ignore these.
3572 EXPECT_TRUE(HasSpan(file_));
3573 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3574 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3575 }
3576
TEST_F(SourceInfoTest,Oneofs)3577 TEST_F(SourceInfoTest, Oneofs) {
3578 EXPECT_TRUE(
3579 Parse("message Foo {\n"
3580 " $a$oneof $c$foo$d$ {\n"
3581 " $e$int32$f$ $g$a$h$ = $i$1$j$;$k$\n"
3582 " }$r$\n"
3583 "}\n"));
3584
3585 const OneofDescriptorProto& oneof_decl = file_.message_type(0).oneof_decl(0);
3586 const FieldDescriptorProto& field = file_.message_type(0).field(0);
3587
3588 EXPECT_TRUE(HasSpan('a', 'r', oneof_decl));
3589 EXPECT_TRUE(HasSpan('c', 'd', oneof_decl, "name"));
3590
3591 EXPECT_TRUE(HasSpan('e', 'k', field));
3592 EXPECT_TRUE(HasSpan('e', 'f', field, "type"));
3593 EXPECT_TRUE(HasSpan('g', 'h', field, "name"));
3594 EXPECT_TRUE(HasSpan('i', 'j', field, "number"));
3595
3596 // Ignore these.
3597 EXPECT_TRUE(HasSpan(file_));
3598 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3599 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3600 }
3601
TEST_F(SourceInfoTest,NestedMessages)3602 TEST_F(SourceInfoTest, NestedMessages) {
3603 EXPECT_TRUE(
3604 Parse("message Foo {\n"
3605 " $a$message $b$Bar$c$ {\n"
3606 " $d$message $e$Baz$f$ {}$g$\n"
3607 " }$h$\n"
3608 " $i$message $j$Qux$k$ {}$l$\n"
3609 "}\n"));
3610
3611 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
3612 const DescriptorProto& baz = bar.nested_type(0);
3613 const DescriptorProto& qux = file_.message_type(0).nested_type(1);
3614
3615 EXPECT_TRUE(HasSpan('a', 'h', bar));
3616 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
3617 EXPECT_TRUE(HasSpan('d', 'g', baz));
3618 EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
3619 EXPECT_TRUE(HasSpan('i', 'l', qux));
3620 EXPECT_TRUE(HasSpan('j', 'k', qux, "name"));
3621
3622 // Ignore these.
3623 EXPECT_TRUE(HasSpan(file_));
3624 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3625 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3626 }
3627
TEST_F(SourceInfoTest,Groups)3628 TEST_F(SourceInfoTest, Groups) {
3629 EXPECT_TRUE(
3630 Parse("message Foo {\n"
3631 " message Bar {}\n"
3632 " $a$optional$b$ $c$group$d$ $e$Baz$f$ = $g$1$h$ {\n"
3633 " $i$message Qux {}$j$\n"
3634 " }$k$\n"
3635 "}\n"));
3636
3637 const DescriptorProto& bar = file_.message_type(0).nested_type(0);
3638 const DescriptorProto& baz = file_.message_type(0).nested_type(1);
3639 const DescriptorProto& qux = baz.nested_type(0);
3640 const FieldDescriptorProto& field = file_.message_type(0).field(0);
3641
3642 EXPECT_TRUE(HasSpan('a', 'k', field));
3643 EXPECT_TRUE(HasSpan('a', 'b', field, "label"));
3644 EXPECT_TRUE(HasSpan('c', 'd', field, "type"));
3645 EXPECT_TRUE(HasSpan('e', 'f', field, "name"));
3646 EXPECT_TRUE(HasSpan('e', 'f', field, "type_name"));
3647 EXPECT_TRUE(HasSpan('g', 'h', field, "number"));
3648
3649 EXPECT_TRUE(HasSpan('a', 'k', baz));
3650 EXPECT_TRUE(HasSpan('e', 'f', baz, "name"));
3651 EXPECT_TRUE(HasSpan('i', 'j', qux));
3652
3653 // Ignore these.
3654 EXPECT_TRUE(HasSpan(file_));
3655 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3656 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3657 EXPECT_TRUE(HasSpan(bar));
3658 EXPECT_TRUE(HasSpan(bar, "name"));
3659 EXPECT_TRUE(HasSpan(qux, "name"));
3660 }
3661
TEST_F(SourceInfoTest,Enums)3662 TEST_F(SourceInfoTest, Enums) {
3663 EXPECT_TRUE(
3664 Parse("$a$enum $b$Foo$c$ {}$d$\n"
3665 "$e$enum $f$Bar$g$ {}$h$\n"));
3666
3667 EXPECT_TRUE(HasSpan('a', 'd', file_.enum_type(0)));
3668 EXPECT_TRUE(HasSpan('b', 'c', file_.enum_type(0), "name"));
3669 EXPECT_TRUE(HasSpan('e', 'h', file_.enum_type(1)));
3670 EXPECT_TRUE(HasSpan('f', 'g', file_.enum_type(1), "name"));
3671
3672 // Ignore these.
3673 EXPECT_TRUE(HasSpan(file_));
3674 }
3675
TEST_F(SourceInfoTest,EnumValues)3676 TEST_F(SourceInfoTest, EnumValues) {
3677 EXPECT_TRUE(
3678 Parse("enum Foo {\n"
3679 " $a$BAR$b$ = $c$1$d$;$e$\n"
3680 " $f$BAZ$g$ = $h$2$i$;$j$\n"
3681 "}"));
3682
3683 const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
3684 const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
3685
3686 EXPECT_TRUE(HasSpan('a', 'e', bar));
3687 EXPECT_TRUE(HasSpan('a', 'b', bar, "name"));
3688 EXPECT_TRUE(HasSpan('c', 'd', bar, "number"));
3689 EXPECT_TRUE(HasSpan('f', 'j', baz));
3690 EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
3691 EXPECT_TRUE(HasSpan('h', 'i', baz, "number"));
3692
3693 // Ignore these.
3694 EXPECT_TRUE(HasSpan(file_));
3695 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
3696 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
3697 }
3698
TEST_F(SourceInfoTest,EnumReservedRange)3699 TEST_F(SourceInfoTest, EnumReservedRange) {
3700 EXPECT_TRUE(
3701 Parse("enum TestEnum {\n"
3702 " $a$reserved $b$1$c$ to $d$10$e$;$f$\n"
3703 "}"));
3704
3705 const EnumDescriptorProto::EnumReservedRange& bar =
3706 file_.enum_type(0).reserved_range(0);
3707
3708 EXPECT_TRUE(HasSpan('a', 'f', file_.enum_type(0), "reserved_range"));
3709 EXPECT_TRUE(HasSpan('b', 'e', bar));
3710 EXPECT_TRUE(HasSpan('b', 'c', bar, "start"));
3711 EXPECT_TRUE(HasSpan('d', 'e', bar, "end"));
3712
3713 // Ignore these.
3714 EXPECT_TRUE(HasSpan(file_));
3715 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
3716 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
3717 }
3718
TEST_F(SourceInfoTest,EnumReservedName)3719 TEST_F(SourceInfoTest, EnumReservedName) {
3720 EXPECT_TRUE(
3721 Parse("enum TestEnum {\n"
3722 " $a$reserved $b$'foo'$c$;$d$\n"
3723 "}"));
3724
3725 const EnumDescriptorProto& bar = file_.enum_type(0);
3726
3727 EXPECT_TRUE(HasSpan('a', 'd', bar, "reserved_name"));
3728 EXPECT_TRUE(HasSpan('b', 'c', bar, "reserved_name", 0));
3729
3730 // Ignore these.
3731 EXPECT_TRUE(HasSpan(file_));
3732 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
3733 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
3734 }
3735
TEST_F(SourceInfoTest,NestedEnums)3736 TEST_F(SourceInfoTest, NestedEnums) {
3737 EXPECT_TRUE(
3738 Parse("message Foo {\n"
3739 " $a$enum $b$Bar$c$ {}$d$\n"
3740 " $e$enum $f$Baz$g$ {}$h$\n"
3741 "}\n"));
3742
3743 const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
3744 const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
3745
3746 EXPECT_TRUE(HasSpan('a', 'd', bar));
3747 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
3748 EXPECT_TRUE(HasSpan('e', 'h', baz));
3749 EXPECT_TRUE(HasSpan('f', 'g', baz, "name"));
3750
3751 // Ignore these.
3752 EXPECT_TRUE(HasSpan(file_));
3753 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3754 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3755 }
3756
TEST_F(SourceInfoTest,Services)3757 TEST_F(SourceInfoTest, Services) {
3758 EXPECT_TRUE(
3759 Parse("$a$service $b$Foo$c$ {}$d$\n"
3760 "$e$service $f$Bar$g$ {}$h$\n"));
3761
3762 EXPECT_TRUE(HasSpan('a', 'd', file_.service(0)));
3763 EXPECT_TRUE(HasSpan('b', 'c', file_.service(0), "name"));
3764 EXPECT_TRUE(HasSpan('e', 'h', file_.service(1)));
3765 EXPECT_TRUE(HasSpan('f', 'g', file_.service(1), "name"));
3766
3767 // Ignore these.
3768 EXPECT_TRUE(HasSpan(file_));
3769 }
3770
TEST_F(SourceInfoTest,MethodsAndStreams)3771 TEST_F(SourceInfoTest, MethodsAndStreams) {
3772 EXPECT_TRUE(
3773 Parse("service Foo {\n"
3774 " $a$rpc $b$Bar$c$($d$X$e$) returns($f$Y$g$);$h$"
3775 " $i$rpc $j$Baz$k$($l$Z$m$) returns($n$W$o$);$p$"
3776 "}"));
3777
3778 const MethodDescriptorProto& bar = file_.service(0).method(0);
3779 const MethodDescriptorProto& baz = file_.service(0).method(1);
3780
3781 EXPECT_TRUE(HasSpan('a', 'h', bar));
3782 EXPECT_TRUE(HasSpan('b', 'c', bar, "name"));
3783 EXPECT_TRUE(HasSpan('d', 'e', bar, "input_type"));
3784 EXPECT_TRUE(HasSpan('f', 'g', bar, "output_type"));
3785
3786 EXPECT_TRUE(HasSpan('i', 'p', baz));
3787 EXPECT_TRUE(HasSpan('j', 'k', baz, "name"));
3788 EXPECT_TRUE(HasSpan('l', 'm', baz, "input_type"));
3789 EXPECT_TRUE(HasSpan('n', 'o', baz, "output_type"));
3790
3791 // Ignore these.
3792 EXPECT_TRUE(HasSpan(file_));
3793 EXPECT_TRUE(HasSpan(file_.service(0)));
3794 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
3795 }
3796
3797
TEST_F(SourceInfoTest,Options)3798 TEST_F(SourceInfoTest, Options) {
3799 EXPECT_TRUE(
3800 Parse("$a$option $b$foo$c$.$d$($e$bar.baz$f$)$g$ = "
3801 "$h$123$i$;$j$\n"
3802 "$k$option qux = $l$-123$m$;$n$\n"
3803 "$o$option corge = $p$abc$q$;$r$\n"
3804 "$s$option grault = $t$'blah'$u$;$v$\n"
3805 "$w$option garply = $x${ yadda yadda }$y$;$z$\n"
3806 "$0$option waldo = $1$123.0$2$;$3$\n"));
3807
3808 const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
3809 const UninterpretedOption& option2 = file_.options().uninterpreted_option(1);
3810 const UninterpretedOption& option3 = file_.options().uninterpreted_option(2);
3811 const UninterpretedOption& option4 = file_.options().uninterpreted_option(3);
3812 const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
3813 const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
3814
3815 EXPECT_TRUE(HasSpan('a', 'j', file_.options()));
3816 EXPECT_TRUE(HasSpan('a', 'j', option1));
3817 EXPECT_TRUE(HasSpan('b', 'g', option1, "name"));
3818 EXPECT_TRUE(HasSpan('b', 'c', option1.name(0)));
3819 EXPECT_TRUE(HasSpan('b', 'c', option1.name(0), "name_part"));
3820 EXPECT_TRUE(HasSpan('d', 'g', option1.name(1)));
3821 EXPECT_TRUE(HasSpan('e', 'f', option1.name(1), "name_part"));
3822 EXPECT_TRUE(HasSpan('h', 'i', option1, "positive_int_value"));
3823
3824 EXPECT_TRUE(HasSpan('k', 'n', file_.options()));
3825 EXPECT_TRUE(HasSpan('l', 'm', option2, "negative_int_value"));
3826
3827 EXPECT_TRUE(HasSpan('o', 'r', file_.options()));
3828 EXPECT_TRUE(HasSpan('p', 'q', option3, "identifier_value"));
3829
3830 EXPECT_TRUE(HasSpan('s', 'v', file_.options()));
3831 EXPECT_TRUE(HasSpan('t', 'u', option4, "string_value"));
3832
3833 EXPECT_TRUE(HasSpan('w', 'z', file_.options()));
3834 EXPECT_TRUE(HasSpan('x', 'y', option5, "aggregate_value"));
3835
3836 EXPECT_TRUE(HasSpan('0', '3', file_.options()));
3837 EXPECT_TRUE(HasSpan('1', '2', option6, "double_value"));
3838
3839 // Ignore these.
3840 EXPECT_TRUE(HasSpan(file_));
3841 EXPECT_TRUE(HasSpan(option2));
3842 EXPECT_TRUE(HasSpan(option3));
3843 EXPECT_TRUE(HasSpan(option4));
3844 EXPECT_TRUE(HasSpan(option5));
3845 EXPECT_TRUE(HasSpan(option6));
3846 EXPECT_TRUE(HasSpan(option2, "name"));
3847 EXPECT_TRUE(HasSpan(option3, "name"));
3848 EXPECT_TRUE(HasSpan(option4, "name"));
3849 EXPECT_TRUE(HasSpan(option5, "name"));
3850 EXPECT_TRUE(HasSpan(option6, "name"));
3851 EXPECT_TRUE(HasSpan(option2.name(0)));
3852 EXPECT_TRUE(HasSpan(option3.name(0)));
3853 EXPECT_TRUE(HasSpan(option4.name(0)));
3854 EXPECT_TRUE(HasSpan(option5.name(0)));
3855 EXPECT_TRUE(HasSpan(option6.name(0)));
3856 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
3857 EXPECT_TRUE(HasSpan(option3.name(0), "name_part"));
3858 EXPECT_TRUE(HasSpan(option4.name(0), "name_part"));
3859 EXPECT_TRUE(HasSpan(option5.name(0), "name_part"));
3860 EXPECT_TRUE(HasSpan(option6.name(0), "name_part"));
3861 }
3862
TEST_F(SourceInfoTest,ScopedOptions)3863 TEST_F(SourceInfoTest, ScopedOptions) {
3864 EXPECT_TRUE(
3865 Parse("message Foo {\n"
3866 " $a$option mopt = 1;$b$\n"
3867 "}\n"
3868 "enum Bar {\n"
3869 " $c$option eopt = 1;$d$\n"
3870 "}\n"
3871 "service Baz {\n"
3872 " $e$option sopt = 1;$f$\n"
3873 " rpc M(X) returns(Y) {\n"
3874 " $g$option mopt = 1;$h$\n"
3875 " }\n"
3876 " rpc MS4($1$stream$2$ X) returns($3$stream$4$ Y) {\n"
3877 " $k$option mopt = 1;$l$\n"
3878 " }\n"
3879 "}\n"));
3880
3881 EXPECT_TRUE(HasSpan('a', 'b', file_.message_type(0).options()));
3882 EXPECT_TRUE(HasSpan('c', 'd', file_.enum_type(0).options()));
3883 EXPECT_TRUE(HasSpan('e', 'f', file_.service(0).options()));
3884 EXPECT_TRUE(HasSpan('g', 'h', file_.service(0).method(0).options()));
3885
3886 // Ignore these.
3887 EXPECT_TRUE(HasSpan(file_));
3888 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3889 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3890 EXPECT_TRUE(HasSpan(file_.message_type(0).options().uninterpreted_option(0)));
3891 EXPECT_TRUE(
3892 HasSpan(file_.message_type(0).options().uninterpreted_option(0), "name"));
3893 EXPECT_TRUE(
3894 HasSpan(file_.message_type(0).options().uninterpreted_option(0).name(0)));
3895 EXPECT_TRUE(
3896 HasSpan(file_.message_type(0).options().uninterpreted_option(0).name(0),
3897 "name_part"));
3898 EXPECT_TRUE(HasSpan(file_.message_type(0).options().uninterpreted_option(0),
3899 "positive_int_value"));
3900 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
3901 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
3902 EXPECT_TRUE(HasSpan(file_.enum_type(0).options().uninterpreted_option(0)));
3903 EXPECT_TRUE(
3904 HasSpan(file_.enum_type(0).options().uninterpreted_option(0), "name"));
3905 EXPECT_TRUE(
3906 HasSpan(file_.enum_type(0).options().uninterpreted_option(0).name(0)));
3907 EXPECT_TRUE(
3908 HasSpan(file_.enum_type(0).options().uninterpreted_option(0).name(0),
3909 "name_part"));
3910 EXPECT_TRUE(HasSpan(file_.enum_type(0).options().uninterpreted_option(0),
3911 "positive_int_value"));
3912 EXPECT_TRUE(HasSpan(file_.service(0)));
3913 EXPECT_TRUE(HasSpan(file_.service(0), "name"));
3914 EXPECT_TRUE(HasSpan(file_.service(0).method(0)));
3915 EXPECT_TRUE(HasSpan(file_.service(0).options().uninterpreted_option(0)));
3916 EXPECT_TRUE(
3917 HasSpan(file_.service(0).options().uninterpreted_option(0), "name"));
3918 EXPECT_TRUE(
3919 HasSpan(file_.service(0).options().uninterpreted_option(0).name(0)));
3920 EXPECT_TRUE(HasSpan(
3921 file_.service(0).options().uninterpreted_option(0).name(0), "name_part"));
3922 EXPECT_TRUE(HasSpan(file_.service(0).options().uninterpreted_option(0),
3923 "positive_int_value"));
3924 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name"));
3925 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type"));
3926 EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type"));
3927 EXPECT_TRUE(
3928 HasSpan(file_.service(0).method(0).options().uninterpreted_option(0)));
3929 EXPECT_TRUE(HasSpan(
3930 file_.service(0).method(0).options().uninterpreted_option(0), "name"));
3931 EXPECT_TRUE(HasSpan(
3932 file_.service(0).method(0).options().uninterpreted_option(0).name(0)));
3933 EXPECT_TRUE(HasSpan(
3934 file_.service(0).method(0).options().uninterpreted_option(0).name(0),
3935 "name_part"));
3936 EXPECT_TRUE(
3937 HasSpan(file_.service(0).method(0).options().uninterpreted_option(0),
3938 "positive_int_value"));
3939
3940 EXPECT_TRUE(HasSpan('k', 'l', file_.service(0).method(1).options()));
3941 EXPECT_TRUE(HasSpan(file_.service(0).method(1)));
3942 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "name"));
3943 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "input_type"));
3944 EXPECT_TRUE(HasSpan(file_.service(0).method(1), "output_type"));
3945 EXPECT_TRUE(
3946 HasSpan(file_.service(0).method(1).options().uninterpreted_option(0)));
3947 EXPECT_TRUE(HasSpan(
3948 file_.service(0).method(1).options().uninterpreted_option(0), "name"));
3949 EXPECT_TRUE(HasSpan(
3950 file_.service(0).method(1).options().uninterpreted_option(0).name(0)));
3951 EXPECT_TRUE(HasSpan(
3952 file_.service(0).method(1).options().uninterpreted_option(0).name(0),
3953 "name_part"));
3954 EXPECT_TRUE(
3955 HasSpan(file_.service(0).method(1).options().uninterpreted_option(0),
3956 "positive_int_value"));
3957 EXPECT_TRUE(
3958 HasSpan('1', '2', file_.service(0).method(1), "client_streaming"));
3959 EXPECT_TRUE(
3960 HasSpan('3', '4', file_.service(0).method(1), "server_streaming"));
3961 }
3962
TEST_F(SourceInfoTest,FieldOptions)3963 TEST_F(SourceInfoTest, FieldOptions) {
3964 // The actual "name = value" pairs are parsed by the same code as for
3965 // top-level options so we won't re-test that -- just make sure that the
3966 // syntax used for field options is understood.
3967 EXPECT_TRUE(
3968 Parse("message Foo {"
3969 " optional int32 bar = 1 "
3970 "$a$[default=$b$123$c$,$d$opt1=123$e$,"
3971 "$f$opt2='hi'$g$]$h$;"
3972 "}\n"));
3973
3974 const FieldDescriptorProto& field = file_.message_type(0).field(0);
3975 const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
3976 const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
3977
3978 EXPECT_TRUE(HasSpan('a', 'h', field.options()));
3979 EXPECT_TRUE(HasSpan('b', 'c', field, "default_value"));
3980 EXPECT_TRUE(HasSpan('d', 'e', option1));
3981 EXPECT_TRUE(HasSpan('f', 'g', option2));
3982
3983 // Ignore these.
3984 EXPECT_TRUE(HasSpan(file_));
3985 EXPECT_TRUE(HasSpan(file_.message_type(0)));
3986 EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
3987 EXPECT_TRUE(HasSpan(field));
3988 EXPECT_TRUE(HasSpan(field, "label"));
3989 EXPECT_TRUE(HasSpan(field, "type"));
3990 EXPECT_TRUE(HasSpan(field, "name"));
3991 EXPECT_TRUE(HasSpan(field, "number"));
3992 EXPECT_TRUE(HasSpan(option1, "name"));
3993 EXPECT_TRUE(HasSpan(option2, "name"));
3994 EXPECT_TRUE(HasSpan(option1.name(0)));
3995 EXPECT_TRUE(HasSpan(option2.name(0)));
3996 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
3997 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
3998 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
3999 EXPECT_TRUE(HasSpan(option2, "string_value"));
4000 }
4001
TEST_F(SourceInfoTest,EnumValueOptions)4002 TEST_F(SourceInfoTest, EnumValueOptions) {
4003 // The actual "name = value" pairs are parsed by the same code as for
4004 // top-level options so we won't re-test that -- just make sure that the
4005 // syntax used for enum options is understood.
4006 EXPECT_TRUE(
4007 Parse("enum Foo {"
4008 " BAR = 1 $a$[$b$opt1=123$c$,$d$opt2='hi'$e$]$f$;"
4009 "}\n"));
4010
4011 const EnumValueDescriptorProto& value = file_.enum_type(0).value(0);
4012 const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
4013 const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
4014
4015 EXPECT_TRUE(HasSpan('a', 'f', value.options()));
4016 EXPECT_TRUE(HasSpan('b', 'c', option1));
4017 EXPECT_TRUE(HasSpan('d', 'e', option2));
4018
4019 // Ignore these.
4020 EXPECT_TRUE(HasSpan(file_));
4021 EXPECT_TRUE(HasSpan(file_.enum_type(0)));
4022 EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
4023 EXPECT_TRUE(HasSpan(value));
4024 EXPECT_TRUE(HasSpan(value, "name"));
4025 EXPECT_TRUE(HasSpan(value, "number"));
4026 EXPECT_TRUE(HasSpan(option1, "name"));
4027 EXPECT_TRUE(HasSpan(option2, "name"));
4028 EXPECT_TRUE(HasSpan(option1.name(0)));
4029 EXPECT_TRUE(HasSpan(option2.name(0)));
4030 EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
4031 EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
4032 EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
4033 EXPECT_TRUE(HasSpan(option2, "string_value"));
4034 }
4035
TEST_F(SourceInfoTest,DocComments)4036 TEST_F(SourceInfoTest, DocComments) {
4037 EXPECT_TRUE(
4038 Parse("// Foo leading\n"
4039 "// line 2\n"
4040 "$a$message Foo {\n"
4041 " // Foo trailing\n"
4042 " // line 2\n"
4043 "\n"
4044 " // detached\n"
4045 "\n"
4046 " // bar leading\n"
4047 " $b$optional int32 bar = 1;$c$\n"
4048 " // bar trailing\n"
4049 "}$d$\n"
4050 "// ignored\n"));
4051
4052 const DescriptorProto& foo = file_.message_type(0);
4053 const FieldDescriptorProto& bar = foo.field(0);
4054
4055 EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n",
4056 " Foo trailing\n line 2\n", nullptr));
4057 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
4058 " bar trailing\n", " detached\n"));
4059
4060 // Ignore these.
4061 EXPECT_TRUE(HasSpan(file_));
4062 EXPECT_TRUE(HasSpan(foo, "name"));
4063 EXPECT_TRUE(HasSpan(bar, "label"));
4064 EXPECT_TRUE(HasSpan(bar, "type"));
4065 EXPECT_TRUE(HasSpan(bar, "name"));
4066 EXPECT_TRUE(HasSpan(bar, "number"));
4067 }
4068
TEST_F(SourceInfoTest,DocComments2)4069 TEST_F(SourceInfoTest, DocComments2) {
4070 EXPECT_TRUE(
4071 Parse("// detached before message.\n"
4072 "\n"
4073 "// Foo leading\n"
4074 "// line 2\n"
4075 "$a$message Foo {\n"
4076 " /* Foo trailing\n"
4077 " * line 2 */\n"
4078 " // detached\n"
4079 " /* bar leading\n"
4080 " */"
4081 " $b$optional int32 bar = 1;$c$ // bar trailing\n"
4082 " // ignored detached\n"
4083 "}$d$\n"
4084 "// ignored\n"
4085 "\n"
4086 "// detached before option\n"
4087 "\n"
4088 "// option leading\n"
4089 "$e$option baz = 123;$f$\n"
4090 "// option trailing\n"));
4091
4092 const DescriptorProto& foo = file_.message_type(0);
4093 const FieldDescriptorProto& bar = foo.field(0);
4094 const UninterpretedOption& baz = file_.options().uninterpreted_option(0);
4095
4096 EXPECT_TRUE(HasSpanWithComment('a', 'd', foo, " Foo leading\n line 2\n",
4097 " Foo trailing\n line 2 ",
4098 " detached before message.\n"));
4099 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
4100 " bar trailing\n", " detached\n"));
4101 EXPECT_TRUE(HasSpanWithComment('e', 'f', baz, " option leading\n",
4102 " option trailing\n",
4103 " detached before option\n"));
4104
4105 // Ignore these.
4106 EXPECT_TRUE(HasSpan(file_));
4107 EXPECT_TRUE(HasSpan(foo, "name"));
4108 EXPECT_TRUE(HasSpan(bar, "label"));
4109 EXPECT_TRUE(HasSpan(bar, "type"));
4110 EXPECT_TRUE(HasSpan(bar, "name"));
4111 EXPECT_TRUE(HasSpan(bar, "number"));
4112 EXPECT_TRUE(HasSpan(file_.options()));
4113 EXPECT_TRUE(HasSpan(baz, "name"));
4114 EXPECT_TRUE(HasSpan(baz.name(0)));
4115 EXPECT_TRUE(HasSpan(baz.name(0), "name_part"));
4116 EXPECT_TRUE(HasSpan(baz, "positive_int_value"));
4117 }
4118
TEST_F(SourceInfoTest,DocComments3)4119 TEST_F(SourceInfoTest, DocComments3) {
4120 EXPECT_TRUE(
4121 Parse("$a$message Foo {\n"
4122 " // bar leading\n"
4123 " $b$optional int32 bar = 1 [(baz.qux) = {}];$c$\n"
4124 " // bar trailing\n"
4125 "}$d$\n"
4126 "// ignored\n"));
4127
4128 const DescriptorProto& foo = file_.message_type(0);
4129 const FieldDescriptorProto& bar = foo.field(0);
4130
4131 EXPECT_TRUE(HasSpanWithComment('b', 'c', bar, " bar leading\n",
4132 " bar trailing\n", nullptr));
4133
4134 // Ignore these.
4135 EXPECT_TRUE(HasSpan(file_));
4136 EXPECT_TRUE(HasSpan(foo));
4137 EXPECT_TRUE(HasSpan(foo, "name"));
4138 EXPECT_TRUE(HasSpan(bar, "label"));
4139 EXPECT_TRUE(HasSpan(bar, "type"));
4140 EXPECT_TRUE(HasSpan(bar, "name"));
4141 EXPECT_TRUE(HasSpan(bar, "number"));
4142 EXPECT_TRUE(HasSpan(bar.options()));
4143 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0)));
4144 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0), "name"));
4145 EXPECT_TRUE(HasSpan(bar.options().uninterpreted_option(0).name(0)));
4146 EXPECT_TRUE(
4147 HasSpan(bar.options().uninterpreted_option(0).name(0), "name_part"));
4148 EXPECT_TRUE(
4149 HasSpan(bar.options().uninterpreted_option(0), "aggregate_value"));
4150 }
4151
TEST_F(SourceInfoTest,DocCommentsTopLevel)4152 TEST_F(SourceInfoTest, DocCommentsTopLevel) {
4153 EXPECT_TRUE(
4154 Parse("// detached before syntax paragraph 1\n"
4155 "\n"
4156 "// detached before syntax paragraph 2\n"
4157 "\n"
4158 "// syntax leading\n"
4159 "$a$syntax = \"proto2\";$b$\n"
4160 "// syntax trailing\n"
4161 "\n"
4162 "// syntax-package detached comments\n"
4163 "\n"
4164 ";\n"
4165 "\n"
4166 "// detached after empty before package\n"
4167 "\n"
4168 "// package leading\n"
4169 "$c$package foo;$d$\n"
4170 "// package trailing\n"
4171 "\n"
4172 "// ignored detach\n"
4173 "\n"));
4174
4175 EXPECT_TRUE(HasSpan('a', 'b', file_, "syntax", -1, " syntax leading\n",
4176 " syntax trailing\n",
4177 " detached before syntax paragraph 1\n"
4178 "\n"
4179 " detached before syntax paragraph 2\n"));
4180 EXPECT_TRUE(HasSpan('c', 'd', file_, "package", -1, " package leading\n",
4181 " package trailing\n",
4182 " syntax-package detached comments\n"
4183 "\n"
4184 " detached after empty before package\n"));
4185
4186 // ignore these.
4187 EXPECT_TRUE(HasSpan(file_));
4188 }
4189
TEST_F(SourceInfoTest,DocCommentsOneof)4190 TEST_F(SourceInfoTest, DocCommentsOneof) {
4191 EXPECT_TRUE(
4192 Parse("// Foo leading\n"
4193 "$a$message Foo {\n"
4194 " /* Foo trailing\n"
4195 " */\n"
4196 " // detached before oneof\n"
4197 " /* bar leading\n"
4198 " * line 2 */\n"
4199 " $b$oneof bar {\n"
4200 " /* bar trailing\n"
4201 " * line 2 */\n"
4202 " // detached before bar_int\n"
4203 " /* bar_int leading\n"
4204 " */\n"
4205 " $c$int32 bar_int = 1;$d$ // bar_int trailing\n"
4206 " // detach comment ignored\n"
4207 " }$e$\n"
4208 "}$f$\n"));
4209
4210 const DescriptorProto& foo = file_.message_type(0);
4211 const OneofDescriptorProto& bar = foo.oneof_decl(0);
4212 const FieldDescriptorProto& bar_int = foo.field(0);
4213
4214 EXPECT_TRUE(HasSpanWithComment('a', 'f', foo, " Foo leading\n",
4215 " Foo trailing\n", nullptr));
4216 EXPECT_TRUE(HasSpanWithComment('b', 'e', bar, " bar leading\n line 2 ",
4217 " bar trailing\n line 2 ",
4218 " detached before oneof\n"));
4219 EXPECT_TRUE(HasSpanWithComment('c', 'd', bar_int, " bar_int leading\n",
4220 " bar_int trailing\n",
4221 " detached before bar_int\n"));
4222
4223 // Ignore these.
4224 EXPECT_TRUE(HasSpan(file_));
4225 EXPECT_TRUE(HasSpan(foo, "name"));
4226 EXPECT_TRUE(HasSpan(bar, "name"));
4227 EXPECT_TRUE(HasSpan(bar_int, "type"));
4228 EXPECT_TRUE(HasSpan(bar_int, "name"));
4229 EXPECT_TRUE(HasSpan(bar_int, "number"));
4230 }
4231
4232 // ===================================================================
4233
4234 typedef ParserTest ParseEditionsTest;
4235
TEST_F(ParseEditionsTest,Editions)4236 TEST_F(ParseEditionsTest, Editions) {
4237 ExpectParsesTo(
4238 R"schema(
4239 edition = "2023";
4240 message A {
4241 int32 b = 1;
4242 })schema",
4243 "message_type \t {"
4244 " name: \"A\""
4245 " field {"
4246 " name: \"b\""
4247 " number: 1"
4248 " label: LABEL_OPTIONAL"
4249 " type: TYPE_INT32"
4250 " }"
4251 "}"
4252 "syntax: \"editions\""
4253 "edition: EDITION_2023\n");
4254 }
4255
TEST_F(ParseEditionsTest,TestEdition)4256 TEST_F(ParseEditionsTest, TestEdition) {
4257 ExpectParsesTo(
4258 R"schema(
4259 edition = "99998_TEST_ONLY";
4260 )schema",
4261 "syntax: \"editions\""
4262 "edition: EDITION_99998_TEST_ONLY\n");
4263 }
4264
TEST_F(ParseEditionsTest,ExtensionsParse)4265 TEST_F(ParseEditionsTest, ExtensionsParse) {
4266 ExpectParsesTo(
4267 R"schema(
4268 edition = '2023';
4269 message Foo {
4270 extensions 100 to 199;
4271 }
4272 extend Foo { string foo = 101; })schema",
4273 "message_type \t {"
4274 " name: \"Foo\""
4275 " extension_range {"
4276 " start: 100"
4277 " end: 200"
4278 " }"
4279 "}"
4280 "extension {"
4281 " name: \"foo\""
4282 " extendee: \"Foo\""
4283 " number: 101"
4284 " label: LABEL_OPTIONAL"
4285 " type: TYPE_STRING"
4286 "}"
4287 "syntax: \"editions\""
4288 "edition: EDITION_2023\n");
4289 }
4290
TEST_F(ParseEditionsTest,MapFeatures)4291 TEST_F(ParseEditionsTest, MapFeatures) {
4292 ExpectParsesTo(
4293 R"schema(
4294 edition = '2023';
4295 message Foo {
4296 map<string, int> map_field = 1 [
4297 features.my_feature = SOMETHING
4298 ];
4299 })schema",
4300 R"pb(message_type {
4301 name: "Foo"
4302 field {
4303 name: "map_field"
4304 number: 1
4305 label: LABEL_REPEATED
4306 type_name: "MapFieldEntry"
4307 options {
4308 uninterpreted_option {
4309 name { name_part: "features" is_extension: false }
4310 name { name_part: "my_feature" is_extension: false }
4311 identifier_value: "SOMETHING"
4312 }
4313 }
4314 }
4315 nested_type {
4316 name: "MapFieldEntry"
4317 field {
4318 name: "key"
4319 number: 1
4320 label: LABEL_OPTIONAL
4321 type: TYPE_STRING
4322 options {
4323 uninterpreted_option {
4324 name { name_part: "features" is_extension: false }
4325 name { name_part: "my_feature" is_extension: false }
4326 identifier_value: "SOMETHING"
4327 }
4328 }
4329 }
4330 field {
4331 name: "value"
4332 number: 2
4333 label: LABEL_OPTIONAL
4334 type_name: "int"
4335 options {
4336 uninterpreted_option {
4337 name { name_part: "features" is_extension: false }
4338 name { name_part: "my_feature" is_extension: false }
4339 identifier_value: "SOMETHING"
4340 }
4341 }
4342 }
4343 options { map_entry: true }
4344 }
4345 }
4346 syntax: "editions"
4347 edition: EDITION_2023)pb");
4348 }
4349
TEST_F(ParseEditionsTest,EmptyEdition)4350 TEST_F(ParseEditionsTest, EmptyEdition) {
4351 ExpectHasEarlyExitErrors(
4352 R"schema(
4353 edition = "";
4354 message A {
4355 optional int32 b = 1;
4356 })schema",
4357 "1:18: Unknown edition \"\".\n");
4358 }
4359
TEST_F(ParseEditionsTest,InvalidEdition)4360 TEST_F(ParseEditionsTest, InvalidEdition) {
4361 ExpectHasEarlyExitErrors(
4362 R"schema(
4363 edition = "2023_INVALID";
4364 message A {
4365 optional int32 b = 1;
4366 })schema",
4367 "1:18: Unknown edition \"2023_INVALID\".\n");
4368 }
4369
TEST_F(ParseEditionsTest,UnknownEdition)4370 TEST_F(ParseEditionsTest, UnknownEdition) {
4371 ExpectHasEarlyExitErrors(
4372 R"schema(
4373 edition = "UNKNOWN";
4374 message A {
4375 optional int32 b = 1;
4376 })schema",
4377 "1:18: Unknown edition \"UNKNOWN\".\n");
4378 }
4379
TEST_F(ParseEditionsTest,LegacyProto2Edition)4380 TEST_F(ParseEditionsTest, LegacyProto2Edition) {
4381 ExpectHasEarlyExitErrors(
4382 R"schema(
4383 edition = "PROTO2";
4384 message A {
4385 optional int32 b = 1;
4386 })schema",
4387 "1:18: Unknown edition \"PROTO2\".\n");
4388 }
4389
TEST_F(ParseEditionsTest,LegacyProto3Edition)4390 TEST_F(ParseEditionsTest, LegacyProto3Edition) {
4391 ExpectHasEarlyExitErrors(
4392 R"schema(
4393 edition = "PROTO3";
4394 message A {
4395 optional int32 b = 1;
4396 })schema",
4397 "1:18: Unknown edition \"PROTO3\".\n");
4398 }
4399
TEST_F(ParseEditionsTest,SyntaxEditions)4400 TEST_F(ParseEditionsTest, SyntaxEditions) {
4401 ExpectHasEarlyExitErrors(
4402 R"schema(
4403 syntax = "editions";
4404 message A {
4405 optional int32 b = 1;
4406 })schema",
4407 "1:17: Unrecognized syntax identifier \"editions\". This parser only "
4408 "recognizes \"proto2\" and \"proto3\".\n");
4409 }
4410
TEST_F(ParseEditionsTest,MixedSyntaxAndEdition)4411 TEST_F(ParseEditionsTest, MixedSyntaxAndEdition) {
4412 ExpectHasErrors(
4413 R"schema(
4414 syntax = "proto2";
4415 edition = "2023";
4416 message A {
4417 optional int32 b = 1;
4418 })schema",
4419 "2:8: Expected top-level statement (e.g. \"message\").\n");
4420 }
4421
TEST_F(ParseEditionsTest,MixedEditionAndSyntax)4422 TEST_F(ParseEditionsTest, MixedEditionAndSyntax) {
4423 ExpectHasErrors(
4424 R"schema(
4425 edition = "2023";
4426 syntax = "proto2";
4427 message A {
4428 int32 b = 1;
4429 })schema",
4430 "2:8: Expected top-level statement (e.g. \"message\").\n");
4431 }
4432
TEST_F(ParseEditionsTest,OptionalKeywordBanned)4433 TEST_F(ParseEditionsTest, OptionalKeywordBanned) {
4434 ExpectHasErrors(
4435 R"schema(
4436 edition = "2023";
4437 message A {
4438 optional int32 b = 1;
4439 })schema",
4440 "3:10: Label \"optional\" is not supported in editions. By default, all "
4441 "singular fields have presence unless features.field_presence is set.\n");
4442 }
4443
TEST_F(ParseEditionsTest,RequiredKeywordBanned)4444 TEST_F(ParseEditionsTest, RequiredKeywordBanned) {
4445 ExpectHasErrors(
4446 R"schema(
4447 edition = "2023";
4448 message A {
4449 required int32 b = 1;
4450 })schema",
4451 "3:10: Label \"required\" is not supported in editions, use "
4452 "features.field_presence = LEGACY_REQUIRED.\n");
4453 }
4454
TEST_F(ParseEditionsTest,GroupsBanned)4455 TEST_F(ParseEditionsTest, GroupsBanned) {
4456 ExpectHasErrors(
4457 R"schema(
4458 edition = "2023";
4459 message TestMessage {
4460 group TestGroup = 1 {};
4461 })schema",
4462 "3:10: Group syntax is no longer supported in editions. To get group "
4463 "behavior you can specify features.message_encoding = DELIMITED on a "
4464 "message field.\n");
4465 }
4466
TEST_F(ParseEditionsTest,ValidationError)4467 TEST_F(ParseEditionsTest, ValidationError) {
4468 ExpectHasValidationErrors(
4469 R"schema(
4470 edition = "2023";
4471 option features.field_presence = IMPLICIT;
4472 option java_package = "blah";
4473 message TestMessage {
4474 string foo = 1 [default = "hello"];
4475 })schema",
4476 "5:17: Implicit presence fields can't specify defaults.\n");
4477 }
4478
TEST_F(ParseEditionsTest,InvalidMerge)4479 TEST_F(ParseEditionsTest, InvalidMerge) {
4480 ExpectHasValidationErrors(
4481 R"schema(
4482 edition = "2023";
4483 option features.field_presence = IMPLICIT;
4484 option java_package = "blah";
4485 message TestMessage {
4486 string foo = 1 [
4487 default = "hello",
4488 features.field_presence = FIELD_PRESENCE_UNKNOWN,
4489 features.enum_type = ENUM_TYPE_UNKNOWN
4490 ];
4491 })schema",
4492 "5:17: Feature field `field_presence` must resolve to a known value, "
4493 "found FIELD_PRESENCE_UNKNOWN\n");
4494 }
4495
TEST_F(ParseEditionsTest,FeaturesWithoutEditions)4496 TEST_F(ParseEditionsTest, FeaturesWithoutEditions) {
4497 ExpectHasValidationErrors(
4498 R"schema(
4499 syntax = "proto3";
4500 option features.field_presence = IMPLICIT;
4501 message TestMessage {
4502 string foo = 1 [
4503 default = "hello",
4504 features.field_presence = EXPLICIT
4505 ];
4506 })schema",
4507 "1:8: Features are only valid under editions.\n"
4508 "4:17: Features are only valid under editions.\n");
4509 }
4510
4511
4512 } // anonymous namespace
4513
4514 } // namespace compiler
4515 } // namespace protobuf
4516 } // namespace google
4517
4518 #include "google/protobuf/port_undef.inc"
4519