@@ -4059,8 +4059,8 @@ class ValidationErrorTest : public testing::Test {
4059
4059
return ABSL_DIE_IF_NULL (pool_.BuildFile (file_proto));
4060
4060
}
4061
4061
4062
- const FileDescriptor* ParseAndBuildFile (absl::string_view file_name,
4063
- absl::string_view file_text) {
4062
+ FileDescriptorProto ParseFile (absl::string_view file_name,
4063
+ absl::string_view file_text) {
4064
4064
io::ArrayInputStream input_stream (file_text.data (), file_text.size ());
4065
4065
SimpleErrorCollector error_collector;
4066
4066
io::Tokenizer tokenizer (&input_stream, &error_collector);
@@ -4072,7 +4072,12 @@ class ValidationErrorTest : public testing::Test {
4072
4072
<< file_text;
4073
4073
ABSL_CHECK_EQ (" " , error_collector.last_error ());
4074
4074
proto.set_name (file_name);
4075
- return pool_.BuildFile (proto);
4075
+ return proto;
4076
+ }
4077
+
4078
+ const FileDescriptor* ParseAndBuildFile (absl::string_view file_name,
4079
+ absl::string_view file_text) {
4080
+ return pool_.BuildFile (ParseFile (file_name, file_text));
4076
4081
}
4077
4082
4078
4083
@@ -4096,6 +4101,17 @@ class ValidationErrorTest : public testing::Test {
4096
4101
BuildFileWithErrors (file_proto, expected_errors);
4097
4102
}
4098
4103
4104
+ // Parse a proto file and build it. Expect errors to be produced which match
4105
+ // the given error text.
4106
+ void ParseAndBuildFileWithErrors (absl::string_view file_name,
4107
+ absl::string_view file_text,
4108
+ absl::string_view expected_errors) {
4109
+ MockErrorCollector error_collector;
4110
+ EXPECT_TRUE (pool_.BuildFileCollectingErrors (ParseFile (file_name, file_text),
4111
+ &error_collector) == nullptr );
4112
+ EXPECT_EQ (expected_errors, error_collector.text_ );
4113
+ }
4114
+
4099
4115
// Parse file_text as a FileDescriptorProto in text format and add it
4100
4116
// to the DescriptorPool. Expect errors to be produced which match the
4101
4117
// given warning text.
@@ -10354,6 +10370,44 @@ TEST_F(FeaturesTest, InvalidOpenEnumNonZeroFirstValue) {
10354
10370
" enums.\n " );
10355
10371
}
10356
10372
10373
+ TEST_F (FeaturesTest, InvalidUseFeaturesInSameFile) {
10374
+ BuildDescriptorMessagesInTestPool ();
10375
+ ParseAndBuildFileWithErrors (" foo.proto" , R"schema(
10376
+ edition = "2023";
10377
+
10378
+ package test;
10379
+ import "google/protobuf/descriptor.proto";
10380
+
10381
+ message Foo {
10382
+ string bar = 1 [
10383
+ features.(test.custom).foo = "xyz",
10384
+ features.(test.another) = {foo: -321}
10385
+ ];
10386
+ }
10387
+
10388
+ message Custom {
10389
+ string foo = 1 [features = { [test.custom]: {foo: "abc"} }];
10390
+ }
10391
+ message Another {
10392
+ Enum foo = 1;
10393
+ }
10394
+
10395
+ enum Enum {
10396
+ option features.enum_type = CLOSED;
10397
+ ZERO = 0;
10398
+ ONE = 1;
10399
+ }
10400
+
10401
+ extend google.protobuf.FeatureSet {
10402
+ Custom custom = 1002 [features.message_encoding=DELIMITED];
10403
+ Another another = 1001;
10404
+ }
10405
+ )schema" ,
10406
+ " foo.proto: test.Foo.bar: OPTION_NAME: Feature "
10407
+ " \" features.(test.custom)\" can't be used in the "
10408
+ " same file it's defined in.\n " );
10409
+ }
10410
+
10357
10411
TEST_F (FeaturesTest, ClosedEnumNonZeroFirstValue) {
10358
10412
BuildDescriptorMessagesInTestPool ();
10359
10413
const FileDescriptor* file = BuildFile (
0 commit comments