From 903d93ebc28b950f51f99082ad670769631a670a Mon Sep 17 00:00:00 2001 From: Tom Ball Date: Fri, 20 Oct 2023 09:20:53 -0700 Subject: [PATCH] Defines NextCode on Cider/V projects for j2objc's ios_application and ios_j2objc_test targets. PiperOrigin-RevId: 575238280 --- .../protobuf/compiler/j2objc/j2objc_enum.cc | 112 +++++++++++++++--- .../src/com/google/protobuf/Descriptors.m | 17 ++- .../protobuf/Descriptors_PackagePrivate.h | 7 +- protobuf/tests/EnumsTest.java | 24 +++- protobuf/tests/Makefile | 2 + protobuf/tests/Proto3EnumTest.java | 104 ++++++++++++++++ protobuf/tests/protos/enum_fields.proto | 17 ++- protobuf/tests/protos/proto3_enum.proto | 41 +++++++ 8 files changed, 290 insertions(+), 34 deletions(-) create mode 100644 protobuf/tests/Proto3EnumTest.java create mode 100644 protobuf/tests/protos/proto3_enum.proto diff --git a/protobuf/compiler/src/google/protobuf/compiler/j2objc/j2objc_enum.cc b/protobuf/compiler/src/google/protobuf/compiler/j2objc/j2objc_enum.cc index d8f63da013..42981c7f7d 100644 --- a/protobuf/compiler/src/google/protobuf/compiler/j2objc/j2objc_enum.cc +++ b/protobuf/compiler/src/google/protobuf/compiler/j2objc/j2objc_enum.cc @@ -33,10 +33,11 @@ // Sanjay Ghemawat, Jeff Dean, Cyrus Najmabadi, and others. #include +#include #include -#include +#include "google/protobuf/compiler/j2objc/common.h" namespace google { namespace protobuf { @@ -66,6 +67,7 @@ EnumGenerator::~EnumGenerator() { void EnumGenerator::CollectSourceImports(std::set* imports) const { imports->insert("java/lang/IllegalArgumentException.h"); + imports->insert("java/lang/IllegalStateException.h"); } void EnumGenerator::GenerateHeader(io::Printer* printer) { @@ -85,6 +87,11 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { EnumOrdinalName(canonical_values_[i]), "ordinal", SimpleItoa(i)); } + if (!descriptor_->is_closed()) { + printer->Print("$ordinalname$_UNRECOGNIZED = $count$,\n", "ordinalname", + COrdinalEnumName(descriptor_), "count", + SimpleItoa(canonical_values_.size())); + } printer->Outdent(); printer->Print("};\n\n"); @@ -113,6 +120,10 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { EnumValueName(canonical_values_[i]), "value", SimpleItoa(canonical_values_[i]->number())); } + if (!descriptor_->is_closed()) { + printer->Print("$ordinalname$_UNRECOGNIZED = -1,\n", "ordinalname", + CValueEnumName(descriptor_)); + } printer->Outdent(); printer->Print("};\n\n"); @@ -140,6 +151,13 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { SimpleItoa(canonical_values_[i]->number()), "valuepreprocessorname", CValuePreprocessorName(descriptor_)); } + if (!descriptor_->is_closed()) { + printer->Print( + "#define $classname$_UNRECOGNIZED_VALUE " + "($valuepreprocessorname$)-1\n", + "classname", ClassName(descriptor_), "valuepreprocessorname", + CValuePreprocessorName(descriptor_)); + } printer->Print( "\n" @@ -184,26 +202,32 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { "classname", ClassName(descriptor_), "name", canonical_values_[i]->name()); } + if (!descriptor_->is_closed()) { + printer->Print( + "FOUNDATION_EXPORT $classname$ *$classname$_get_UNRECOGNIZED(void);\n", + "classname", ClassName(descriptor_)); + } } const int kMaxRowChars = 80; void EnumGenerator::GenerateSource(io::Printer* printer) { + const int canonical_count = canonical_values_.size(); + const int enum_count = canonical_count + (descriptor_->is_closed() ? 0 : 1); printer->Print( "\nJ2OBJC_INITIALIZED_DEFN($classname$)\n" "\n" "$classname$ *$classname$_values_[$count$];\n" "\n" "ComGoogleProtobufDescriptors_EnumDescriptor" - " *$classname$_descriptor_ = nil;\n" + " *$classname$_descriptor_ = nil;\n" "\n" "@implementation $classname$\n" "\n" "+ (void)initialize {\n" " if (self == [$classname$ class]) {\n" " NSString *names[] = {", - "classname", ClassName(descriptor_), - "count", SimpleItoa(canonical_values_.size())); + "classname", ClassName(descriptor_), "count", SimpleItoa(enum_count)); // Count characters and only add line breaks when the line exceeds the max. int row_chars = kMaxRowChars + 1; @@ -217,6 +241,9 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { printer->Print(" @\"$name$\",", "name", name); row_chars += added_chars; } + if (!descriptor_->is_closed()) { + printer->Print(" @\"UNRECOGNIZED\","); + } printer->Print("\n" " };\n" " jint int_values[] = {"); @@ -231,19 +258,22 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { printer->Print(" $value$,", "value", value); row_chars += added_chars; } + if (!descriptor_->is_closed()) { + printer->Print(" -1,"); + } printer->Print( "\n" " };\n" " $classname$_descriptor_ = " "CGPInitializeEnumType(self, $count$, $classname$_values_, names," - " int_values);\n" + " int_values, $is_closed$);\n" " J2OBJC_SET_INITIALIZED($classname$)\n" " }\n" "}\n" "\n" "+ (IOSObjectArray *)values {\n" - " return $classname$_values();" + " return $classname$_values();\n" "}\n" "\n" "+ ($classname$ *)valueOfWithNSString:(NSString *)name {\n" @@ -257,8 +287,26 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "+ ($classname$ *)forNumberWithInt:($valuepreprocessorname$)value {\n" " return $classname$_forNumberWithInt_(value);\n" "}\n" - "\n" - "- ($valuepreprocessorname$)getNumber {\n" + "\n", + "classname", ClassName(descriptor_), "count", SimpleItoa(enum_count), + "valuepreprocessorname", CValuePreprocessorName(descriptor_), + "is_closed", SimpleItoa(descriptor_->is_closed())); + + printer->Print( + "- ($valuepreprocessorname$)getNumber {\n", + "valuepreprocessorname", CValuePreprocessorName(descriptor_)); + if (!descriptor_->is_closed()) { + printer->Print( + // "=="" is safe because it's testing a unique enum constant. + " if (self == $classname$_get_UNRECOGNIZED()) {\n" + " @throw " + "create_JavaLangIllegalArgumentException_initWithNSString_(\n" + " @\"Can't get the number of an unknown enum value.\");\n" + " }\n", + "classname", ClassName(descriptor_)); + } + + printer->Print( " return value_;\n" "}\n" "\n" @@ -267,7 +315,20 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "}\n" "\n" "- (ComGoogleProtobufDescriptors_EnumValueDescriptor *)" - "getValueDescriptor {\n" + "getValueDescriptor {\n", + "classname", ClassName(descriptor_)); + + if (!descriptor_->is_closed()) { + printer->Print( + " if (value_ == $classname$_Value_UNRECOGNIZED) {\n" + " @throw create_JavaLangIllegalStateException_initWithNSString_(\n" + " @\"Can't get the descriptor of an unrecognized enum " + "value.\");\n" + " }\n", + "classname", ClassName(descriptor_)); + } + + printer->Print( " return $classname$_descriptor_->values_->buffer_[[self ordinal]];\n" "}\n" "\n" @@ -276,13 +337,13 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "J2OBJC_CLASS_TYPE_LITERAL_SOURCE($classname$)\n" "\n" "IOSObjectArray *$classname$_values(void) {\n" - " $classname$_initialize();" + " $classname$_initialize();\n" " return [IOSObjectArray arrayWithObjects:$classname$_values_" " count:$count$ type:$classname$_class_()];\n" "}\n" "\n" "$classname$ *$classname$_valueOfWithNSString_(NSString *name) {\n" - " $classname$_initialize();" + " $classname$_initialize();\n" " for (jint i = 0; i < $count$; i++) {\n" " $classname$ *e = $classname$_values_[i];\n" " if ([name isEqual:[e name]]) {\n" @@ -290,7 +351,11 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { " }\n" " }\n" " @throw create_JavaLangIllegalArgumentException_initWithNSString_(" - "name);\n" + "name);\n", + "classname", ClassName(descriptor_), "count", + SimpleItoa(enum_count)); // Include UNRECOGNIZED constant. + + printer->Print( "}\n" "\n" "$classname$ *$classname$_valueOfWithInt_($valuepreprocessorname$ value) " @@ -300,7 +365,7 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "\n" "$classname$ *$classname$_forNumberWithInt_($valuepreprocessorname$ " "value) {\n" - " $classname$_initialize();" + " $classname$_initialize();\n" " for (jint i = 0; i < $count$; i++) {\n" " $classname$ *e = $classname$_values_[i];\n" " if (value == [e getNumber]) {\n" @@ -309,7 +374,11 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { " }\n" " return nil;\n" "}\n" - "\n" + "\n", + "classname", ClassName(descriptor_), "count", SimpleItoa(canonical_count), + "valuepreprocessorname", CValuePreprocessorName(descriptor_)); + + printer->Print( "$classname$ *$classname$_fromOrdinal($ordinalpreprocessorname$ ordinal) " "{\n" " $classname$_initialize();\n" @@ -318,11 +387,8 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { " }\n" " return $classname$_values_[ordinal];\n" "}\n", - "classname", ClassName(descriptor_), "count", - SimpleItoa(canonical_values_.size()), "ordinalpreprocessorname", - COrdinalPreprocessorName(descriptor_), "valueenumname", - CValueEnumName(descriptor_), "valuepreprocessorname", - CValuePreprocessorName(descriptor_)); + "classname", ClassName(descriptor_), "count", SimpleItoa(enum_count), + "ordinalpreprocessorname", COrdinalPreprocessorName(descriptor_)); for (int i = 0; i < canonical_values_.size(); i++) { printer->Print( @@ -333,6 +399,14 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "classname", ClassName(descriptor_), "name", canonical_values_[i]->name()); } + if (!descriptor_->is_closed()) { + printer->Print( + "\n$classname$ *$classname$_get_$name$(void) {\n" + " $classname$_initialize();\n" + " return $classname$_values_[$classname$_Enum_$name$];\n" + "}\n", + "classname", ClassName(descriptor_), "name", "UNRECOGNIZED"); + } } } // namespace j2objc diff --git a/protobuf/runtime/src/com/google/protobuf/Descriptors.m b/protobuf/runtime/src/com/google/protobuf/Descriptors.m index 3c31a4c949..505e4b44b4 100644 --- a/protobuf/runtime/src/com/google/protobuf/Descriptors.m +++ b/protobuf/runtime/src/com/google/protobuf/Descriptors.m @@ -137,7 +137,7 @@ void CGPInitFields( CGPEnumDescriptor *CGPInitializeEnumType( Class enumClass, jint valuesCount, JavaLangEnum *values[], - NSString **names, jint *intValues) { + NSString **names, jint *intValues, jboolean is_closed) { Ivar valueIvar = class_getInstanceVariable(enumClass, "value_"); ptrdiff_t valueOffset = ivar_getOffset(valueIvar); @@ -175,7 +175,9 @@ void CGPInitFields( // Construct the enum descriptor. CGPEnumDescriptor *enumDesc = objc_constructInstance([CGPEnumDescriptor class], (void *)enumDescPtr); - return [enumDesc initWithValueOffset:valueOffset retainedValues:valuesArray]; + return [enumDesc initWithValueOffset:valueOffset + retainedValues:valuesArray + is_closed:is_closed]; } void CGPInitializeOneofCaseEnum( @@ -453,22 +455,27 @@ id CGPFieldGetDefaultValue(CGPFieldDescriptor *field) { CGPEnumValueDescriptor *CGPEnumValueDescriptorFromInt(CGPEnumDescriptor *enumType, jint value) { NSUInteger count = enumType->values_->size_; + NSUInteger numValues = enumType->is_closed_ ? count : count - 1; // Skip the UNRECOGNIZED value. CGPEnumValueDescriptor **valuesBuf = enumType->values_->buffer_; - for (NSUInteger i = 0; i < count; i++) { + for (NSUInteger i = 0; i < numValues; i++) { CGPEnumValueDescriptor *valueDescriptor = valuesBuf[i]; if (valueDescriptor->number_ == value) { return valueDescriptor; } } - return nil; + // If proto3 (not closed), the UNRECOGNIZED value is the last values element. + return enumType->is_closed_ ? nil : valuesBuf[count - 1]; } @implementation ComGoogleProtobufDescriptors_EnumDescriptor -- (instancetype)initWithValueOffset:(ptrdiff_t)valueOffset retainedValues:(IOSObjectArray *)values { +- (instancetype)initWithValueOffset:(ptrdiff_t)valueOffset + retainedValues:(IOSObjectArray *)values + is_closed:(jboolean)is_closed { if (self = [super init]) { valueOffset_ = valueOffset; values_ = values; // Already retained. + is_closed_ = is_closed; } return self; } diff --git a/protobuf/runtime/src/com/google/protobuf/Descriptors_PackagePrivate.h b/protobuf/runtime/src/com/google/protobuf/Descriptors_PackagePrivate.h index 2a6831c981..fbd9b86e84 100644 --- a/protobuf/runtime/src/com/google/protobuf/Descriptors_PackagePrivate.h +++ b/protobuf/runtime/src/com/google/protobuf/Descriptors_PackagePrivate.h @@ -135,9 +135,12 @@ typedef struct CGPOneofData { @public ptrdiff_t valueOffset_; IOSObjectArray *values_; + jboolean is_closed_; } -- (instancetype)initWithValueOffset:(ptrdiff_t)valueOffset retainedValues:(IOSObjectArray *)values; +- (instancetype)initWithValueOffset:(ptrdiff_t)valueOffset + retainedValues:(IOSObjectArray *)values + is_closed:(jboolean)is_closed; @end @@ -194,7 +197,7 @@ IOSObjectArray *CGPGetSerializationOrderFields(CGPDescriptor *descriptor); CGPEnumDescriptor *CGPInitializeEnumType( Class enumClass, jint valuesCount, __strong JavaLangEnum *values[], - __strong NSString **names, jint *intValues); + __strong NSString **names, jint *intValues, jboolean is_closed); void CGPInitializeOneofCaseEnum( Class enumClass, jint valuesCount, diff --git a/protobuf/tests/EnumsTest.java b/protobuf/tests/EnumsTest.java index c4d40ba8c7..8954a2d5ad 100644 --- a/protobuf/tests/EnumsTest.java +++ b/protobuf/tests/EnumsTest.java @@ -13,18 +13,17 @@ */ import com.google.protobuf.ExtensionRegistry; - +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; import protos.Color; import protos.EnumFields; import protos.EnumMsg; import protos.EnumMsg.InnerMsg.Utensil; import protos.EnumMsg.Shape; import protos.EnumMsgOrBuilder; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.ArrayList; -import java.util.List; +import protos.Foo; +import protos.SomeEnum; /** * Tests for correct behavior of enum fields. @@ -101,6 +100,19 @@ public void testAddAll() throws Exception { assertEquals(Shape.CIRCLE, builder.getEnumR(2)); } + public void testMinusOne() throws Exception { + assertEquals(0, SomeEnum.UNKNOWN.getNumber()); + assertEquals(1, SomeEnum.A.getNumber()); + assertEquals(-1, SomeEnum.UNRECOGNIZED.getNumber()); + + assertEquals(SomeEnum.UNKNOWN, SomeEnum.forNumber(0)); + assertEquals(SomeEnum.A, SomeEnum.forNumber(1)); + assertEquals(SomeEnum.UNRECOGNIZED, SomeEnum.forNumber(-1)); + + Foo foo = Foo.parseFrom(new byte[] {0x08, 0x7f}, ExtensionRegistry.getEmptyRegistry()); + assertEquals(SomeEnum.UNKNOWN, foo.getE()); + } + private void checkFields(EnumMsgOrBuilder msg) { assertEquals(Shape.SQUARE, msg.getEnumF()); assertEquals(Color.RED, msg.getOuterEnumF()); diff --git a/protobuf/tests/Makefile b/protobuf/tests/Makefile index b7b5c90e0a..c0881d9c84 100644 --- a/protobuf/tests/Makefile +++ b/protobuf/tests/Makefile @@ -16,6 +16,7 @@ JAVA_TESTS = \ MessagesTest.java \ OneofTest.java \ PrimitivesTest.java \ + Proto3EnumTest.java \ Proto3OptionalTest.java \ com/google/protobuf/FieldPresenceTest.java \ com/google/protobuf/WireFormatTest.java \ @@ -58,6 +59,7 @@ PROTOS = \ package_prefix.proto \ prefix_option.proto \ primitives.proto \ + proto3_enum.proto \ single_file.proto \ size_test.proto \ string_fields.proto \ diff --git a/protobuf/tests/Proto3EnumTest.java b/protobuf/tests/Proto3EnumTest.java new file mode 100644 index 0000000000..acae257070 --- /dev/null +++ b/protobuf/tests/Proto3EnumTest.java @@ -0,0 +1,104 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import static com.google.common.truth.Truth.assertThat; + +import com.google.protobuf.ExtensionRegistry; +import protos.Fruit; +import protos.FruitBox; +import protos.Greetings; +import protos.Text; + +@SuppressWarnings("NanoEnumEvaluator") +public class Proto3EnumTest extends ProtobufTest { + + public void testUnknownEnumConstant() throws Exception { + // Verify UNRECOGNIZED is a valid enum. + assertThat(Fruit.UNRECOGNIZED.getDeclaringClass()).isEqualTo(Fruit.class); + + // Which doesn't have an accessible enum number. + try { + Fruit.UNRECOGNIZED.getNumber(); + fail(); + } catch (IllegalArgumentException e) { + // Exception successfully thrown. + } + + // Or descriptor. + try { + Fruit.UNRECOGNIZED.getValueDescriptor(); + fail(); + } catch (IllegalStateException e) { + // Exception successfully thrown. + } + + // Verify UNRECOGNIZED is returned correctly in the enum's values array. + Fruit[] values = Fruit.values(); + assertThat(values).hasLength(5); + assertThat(values[0]).isEqualTo(Fruit.UNSPECIFIED); + assertThat(values[1]).isEqualTo(Fruit.APPLE); + assertThat(values[2]).isEqualTo(Fruit.BANANA); + assertThat(values[3]).isEqualTo(Fruit.ORANGE); + assertThat(values[4]).isEqualTo(Fruit.UNRECOGNIZED); + } + + // Verify EnumType.forNumber() works same as proto2. + public void testEnumForNumber() throws Exception { + assertThat(Fruit.forNumber(0)).isEqualTo(Fruit.UNSPECIFIED); + assertThat(Fruit.forNumber(1)).isEqualTo(Fruit.APPLE); + assertThat(Fruit.forNumber(2)).isEqualTo(Fruit.BANANA); + assertThat(Fruit.forNumber(3)).isEqualTo(Fruit.ORANGE); + + assertThat(Fruit.forNumber(-1)).isNull(); + assertThat(Fruit.forNumber(10000)).isNull(); + } + + // Verify message containing an enum is parsed correctly. A binary payload is used + // so that an unrecognized enum value is also tested. + public void testUnrecognizedEnum() throws Exception { + FruitBox box = + FruitBox.parseFrom( + new byte[] {0x08, (byte) Fruit.APPLE.getNumber()}, + ExtensionRegistry.getEmptyRegistry()); + assertThat(box.getFruit()).isEqualTo(Fruit.APPLE); + box = + FruitBox.parseFrom( + new byte[] {0x08, (byte) Fruit.BANANA.getNumber()}, + ExtensionRegistry.getEmptyRegistry()); + assertThat(box.getFruit()).isEqualTo(Fruit.BANANA); + box = + FruitBox.parseFrom( + new byte[] {0x08, (byte) Fruit.ORANGE.getNumber()}, + ExtensionRegistry.getEmptyRegistry()); + assertThat(box.getFruit()).isEqualTo(Fruit.ORANGE); + + box = FruitBox.parseFrom(new byte[] {0x08, 0x7f}, ExtensionRegistry.getEmptyRegistry()); + assertThat(box.getFruit()).isSameInstanceAs(Fruit.UNRECOGNIZED); + } + + // Verify that a proto3 enum with a member that has a number value of -1 + // (the same as UNRECOGNIZED), is generated correctly and accessible. + public void testNegativeEnumNumber() throws Exception { + assertThat(Greetings.ENUM_TYPE_NAME_UNKNOWN.getNumber()).isEqualTo(0); + assertThat(Greetings.HELLO.getNumber()).isEqualTo(1); + assertThat(Greetings.GOODBYE.getNumber()).isEqualTo(-1); + + assertThat(Greetings.forNumber(0)).isEqualTo(Greetings.ENUM_TYPE_NAME_UNKNOWN); + assertThat(Greetings.forNumber(1)).isEqualTo(Greetings.HELLO); + assertThat(Greetings.forNumber(-1)).isEqualTo(Greetings.GOODBYE); + + Text text = Text.parseFrom(new byte[] {0x08, 0x7f}, ExtensionRegistry.getEmptyRegistry()); + assertThat(text.getGreeting()).isSameInstanceAs(Greetings.UNRECOGNIZED); + } +} diff --git a/protobuf/tests/protos/enum_fields.proto b/protobuf/tests/protos/enum_fields.proto index 78dbed55bf..ace2dee398 100644 --- a/protobuf/tests/protos/enum_fields.proto +++ b/protobuf/tests/protos/enum_fields.proto @@ -48,7 +48,7 @@ message EnumMsg { repeated Color outer_enum_r = 22; repeated InnerMsg.Utensil inner_enum_r = 23; - repeated Shape enum_p = 41 [packed=true]; + repeated Shape enum_p = 41 [packed = true]; extensions 1000 to max; } @@ -62,5 +62,18 @@ extend EnumMsg { repeated Color outer_enum_re = 1022; repeated EnumMsg.InnerMsg.Utensil inner_enum_re = 1023; - repeated EnumMsg.Shape enum_pe = 1041 [packed=true]; + repeated EnumMsg.Shape enum_pe = 1041 [packed = true]; +} + +message Foo { + optional SomeEnum e = 1; +} + +// Enum to verify proto3 enum support doesn't break proto2 use. +enum SomeEnum { + UNKNOWN = 0; + // This is a doppelgänger meant to make a proto2 enum look like is + // generated for all proto3 enums. + UNRECOGNIZED = -1; + A = 1; } diff --git a/protobuf/tests/protos/proto3_enum.proto b/protobuf/tests/protos/proto3_enum.proto new file mode 100644 index 0000000000..8f60d0e887 --- /dev/null +++ b/protobuf/tests/protos/proto3_enum.proto @@ -0,0 +1,41 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package protos; + +option java_package = "protos"; +option java_multiple_files = true; + +enum Fruit { + UNSPECIFIED = 0; + APPLE = 1; + BANANA = 2; + ORANGE = 3; +} + +message FruitBox { + Fruit fruit = 1; +} + +enum Greetings { + ENUM_TYPE_NAME_UNKNOWN = 0; + HELLO = 1; + // Use an enum value that's the same as the UNRECOGNIZED value, to test + // that they are differentiated by the runtime. + GOODBYE = -1; +} + +message Text { + Greetings greeting = 1; +}