Skip to content

Commit df1aad4

Browse files
Fix TextFormat.Parser to appropriately handle unknown values for open enums
PiperOrigin-RevId: 661229108
1 parent 903c3f1 commit df1aad4

File tree

4 files changed

+45
-15
lines changed

4 files changed

+45
-15
lines changed

conformance/text_format_conformance_suite.cc

+26
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,14 @@ TextFormatConformanceTestSuiteImpl<MessageType>::
147147
} else {
148148
if (MessageType::GetDescriptor()->name() == "TestAllTypesProto2") {
149149
RunGroupTests();
150+
RunClosedEnumTests();
150151
}
151152
if (MessageType::GetDescriptor()->name() == "TestAllTypesEdition2023") {
152153
RunDelimitedTests();
153154
}
154155
if (MessageType::GetDescriptor()->name() == "TestAllTypesProto3") {
155156
RunAnyTests();
157+
RunOpenEnumTests();
156158
// TODO Run these over proto2 also.
157159
RunAllTests();
158160
}
@@ -865,5 +867,29 @@ void TextFormatConformanceTestSuiteImpl<MessageType>::
865867
RECOMMENDED, input, expected);
866868
}
867869

870+
template <typename MessageType>
871+
void TextFormatConformanceTestSuiteImpl<MessageType>::RunOpenEnumTests() {
872+
RunValidTextFormatTest("ClosedEnumFieldByNumber", REQUIRED,
873+
R"(
874+
optional_nested_enum: 1
875+
)");
876+
RunValidTextFormatTest("ClosedEnumFieldWithUnknownNumber", REQUIRED,
877+
R"(
878+
optional_nested_enum: 42
879+
)");
880+
}
881+
882+
template <typename MessageType>
883+
void TextFormatConformanceTestSuiteImpl<MessageType>::RunClosedEnumTests() {
884+
RunValidTextFormatTest("ClosedEnumFieldByNumber", REQUIRED,
885+
R"(
886+
optional_nested_enum: 1
887+
)");
888+
ExpectParseFailure("ClosedEnumFieldWithUnknownNumber", REQUIRED,
889+
R"(
890+
optional_nested_enum: 42
891+
)");
892+
}
893+
868894
} // namespace protobuf
869895
} // namespace google

conformance/text_format_conformance_suite.h

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class TextFormatConformanceTestSuiteImpl {
5252
void RunDelimitedTests();
5353
void RunGroupTests();
5454
void RunAnyTests();
55+
void RunOpenEnumTests();
56+
void RunClosedEnumTests();
5557

5658
void RunTextFormatPerformanceTests();
5759
void RunValidTextFormatTest(const std::string& test_name,

java/core/src/main/java/com/google/protobuf/TextFormat.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,12 @@ private void printFieldValue(
534534
break;
535535

536536
case ENUM:
537-
generator.print(((EnumValueDescriptor) value).getName());
537+
if (((EnumValueDescriptor) value).getIndex() == -1) {
538+
// Unknown enum value, print the number instead of the name.
539+
generator.print(Integer.toString(((EnumValueDescriptor) value).getNumber()));
540+
} else {
541+
generator.print(((EnumValueDescriptor) value).getName());
542+
}
538543
break;
539544

540545
case MESSAGE:
@@ -2195,7 +2200,10 @@ private void consumeFieldValue(
21952200

21962201
if (tokenizer.lookingAtInteger()) {
21972202
final int number = tokenizer.consumeInt32();
2198-
value = enumType.findValueByNumber(number);
2203+
value =
2204+
enumType.isClosed()
2205+
? enumType.findValueByNumber(number)
2206+
: enumType.findValueByNumberCreatingIfUnknown(number);
21992207
if (value == null) {
22002208
String unknownValueMsg =
22012209
"Enum type \""

java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java

+7-13
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import com.google.protobuf.Proto2UnknownEnumValuesTestProto.Proto2EnumMessageWithEnumSubset;
2020
import com.google.protobuf.Proto2UnknownEnumValuesTestProto.Proto2TestEnum;
2121
import com.google.protobuf.Proto2UnknownEnumValuesTestProto.Proto2TestEnumSubset;
22-
import com.google.protobuf.TextFormat.ParseException;
2322
import org.junit.Test;
2423
import org.junit.runner.RunWith;
2524
import org.junit.runners.JUnit4;
@@ -221,7 +220,7 @@ public void testUnknownEnumValueWithDynamicMessage() throws Exception {
221220
}
222221

223222
@Test
224-
public void testUnknownEnumValuesInTextFormat() {
223+
public void testUnknownEnumValuesInTextFormat() throws Exception {
225224
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
226225
builder.setOptionalNestedEnumValue(4321);
227226
builder.addRepeatedNestedEnumValue(5432);
@@ -232,18 +231,13 @@ public void testUnknownEnumValuesInTextFormat() {
232231
String textData = TextFormat.printer().printToString(message);
233232
assertThat(textData)
234233
.isEqualTo(
235-
"optional_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_4321\n"
236-
+ "repeated_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_5432\n"
237-
+ "packed_nested_enum: UNKNOWN_ENUM_VALUE_NestedEnum_6543\n");
234+
"optional_nested_enum: 4321\n"
235+
+ "repeated_nested_enum: 5432\n"
236+
+ "packed_nested_enum: 6543\n");
238237

239-
// Parsing unknown enum values will fail just like parsing other kinds of
240-
// unknown fields.
241-
try {
242-
TextFormat.merge(textData, builder);
243-
assertWithMessage("Expected exception").fail();
244-
} catch (ParseException e) {
245-
// expected.
246-
}
238+
builder.clear();
239+
TextFormat.merge(textData, builder);
240+
assertThat(message.equals(builder.build())).isTrue();
247241
}
248242

249243
@Test

0 commit comments

Comments
 (0)