[ObjC] Add ability to introspect list of enum values (#4678)

Added new API to GPBEnumDescriptor to enable introspection of enum values.

Refactored implementation so that this contains a minimum of added code.

Clarified comments regarding behavior in the presence of the alias_allowed option.

Added unit tests for new functionality and for the alias case.
pull/4697/head
leovitch 7 years ago committed by Thomas Van Lenten
parent 264e615e8e
commit 2804902446
  1. 34
      objectivec/GPBDescriptor.h
  2. 35
      objectivec/GPBDescriptor.m
  3. 7
      objectivec/README.md
  4. 57
      objectivec/Tests/GPBDescriptorTests.m

@ -223,9 +223,12 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
/**
* Returns the enum value name for the given raw enum.
*
* Note that there can be more than one name corresponding to a given value
* if the allow_alias option is used.
*
* @param number The raw enum value.
*
* @return The name of the enum value passed, or nil if not valid.
* @return The first name that matches the enum value passed, or nil if not valid.
**/
- (nullable NSString *)enumNameForValue:(int32_t)number;
@ -244,7 +247,7 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
*
* @param number The raw enum value.
*
* @return The text format name for the raw enum value, or nil if not valid.
* @return The first text format name which matches the enum value, or nil if not valid.
**/
- (nullable NSString *)textFormatNameForValue:(int32_t)number;
@ -258,6 +261,33 @@ typedef NS_ENUM(uint8_t, GPBFieldType) {
**/
- (BOOL)getValue:(nullable int32_t *)outValue forEnumTextFormatName:(NSString *)textFormatName;
/**
* Gets the number of defined enum names.
*
* @return Count of the number of enum names, including any aliases.
*/
@property(nonatomic, readonly) uint32_t enumNameCount;
/**
* Gets the enum name corresponding to the given index.
*
* @param index Index into the available names. The defined range is from 0
* to self.enumNameCount - 1.
*
* @returns The enum name at the given index, or nil if the index is out of range.
*/
- (nullable NSString *)getEnumNameForIndex:(uint32_t)index;
/**
* Gets the enum text format name corresponding to the given index.
*
* @param index Index into the available names. The defined range is from 0
* to self.enumNameCount - 1.
*
* @returns The text format name at the given index, or nil if the index is out of range.
*/
- (nullable NSString *)getEnumTextFormatNameForIndex:(uint32_t)index;
@end
/**

@ -830,13 +830,9 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
}
- (NSString *)enumNameForValue:(int32_t)number {
if (nameOffsets_ == NULL) [self calcValueNameOffsets];
for (uint32_t i = 0; i < valueCount_; ++i) {
if (values_[i] == number) {
const char *valueName = valueNames_ + nameOffsets_[i];
NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
return fullName;
return [self getEnumNameForIndex:i];
}
}
return nil;
@ -886,8 +882,6 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
}
- (NSString *)textFormatNameForValue:(int32_t)number {
if (nameOffsets_ == NULL) [self calcValueNameOffsets];
// Find the EnumValue descriptor and its index.
BOOL foundIt = NO;
uint32_t valueDescriptorIndex;
@ -902,16 +896,39 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) {
if (!foundIt) {
return nil;
}
return [self getEnumTextFormatNameForIndex:valueDescriptorIndex];
}
- (uint32_t)enumNameCount {
return valueCount_;
}
- (NSString *)getEnumNameForIndex:(uint32_t)index {
if (nameOffsets_ == NULL) [self calcValueNameOffsets];
if (index >= valueCount_) {
return nil;
}
const char *valueName = valueNames_ + nameOffsets_[index];
NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName];
return fullName;
}
- (NSString *)getEnumTextFormatNameForIndex:(uint32_t)index {
if (nameOffsets_ == NULL) [self calcValueNameOffsets];
if (index >= valueCount_) {
return nil;
}
NSString *result = nil;
// Naming adds an underscore between enum name and value name, skip that also.
const char *valueName = valueNames_ + nameOffsets_[valueDescriptorIndex];
const char *valueName = valueNames_ + nameOffsets_[index];
NSString *shortName = @(valueName);
// See if it is in the map of special format handling.
if (extraTextFormatInfo_) {
result = GPBDecodeTextFormatName(extraTextFormatInfo_,
(int32_t)valueDescriptorIndex, shortName);
(int32_t)index, shortName);
}
// Logic here needs to match what objectivec_enum.cc does in the proto
// compiler.

@ -20,9 +20,10 @@ The Objective C implementation requires:
Installation
------------
The full distribution pulled from github includes the sources for both the
compiler (protoc) and the runtime (this directory). To build the compiler
and run the runtime tests, you can use:
The distribution pulled from github includes the sources for both the
compiler (protoc) and the runtime (this directory). After cloning the distribution
and needed submodules ([see the src directory's README](../src/README.md)),
to build the compiler and run the runtime tests, you can use:
$ objectivec/DevTools/full_mac_build.sh

@ -190,6 +190,63 @@
XCTAssertFalse([descriptor getValue:&value forEnumTextFormatName:@"Unknown"]);
}
- (void)testEnumDescriptorIntrospection {
GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor();
XCTAssertEqual(descriptor.enumNameCount, 4U);
XCTAssertEqualObjects([descriptor getEnumNameForIndex:0],
@"TestAllTypes_NestedEnum_Foo");
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:0], @"FOO");
XCTAssertEqualObjects([descriptor getEnumNameForIndex:1],
@"TestAllTypes_NestedEnum_Bar");
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:1], @"BAR");
XCTAssertEqualObjects([descriptor getEnumNameForIndex:2],
@"TestAllTypes_NestedEnum_Baz");
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:2], @"BAZ");
XCTAssertEqualObjects([descriptor getEnumNameForIndex:3],
@"TestAllTypes_NestedEnum_Neg");
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:3], @"NEG");
}
- (void)testEnumDescriptorIntrospectionWithAlias {
GPBEnumDescriptor *descriptor = TestEnumWithDupValue_EnumDescriptor();
NSString *enumName;
int32_t value;
XCTAssertEqual(descriptor.enumNameCount, 5U);
enumName = [descriptor getEnumNameForIndex:0];
XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Foo1");
XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
XCTAssertEqual(value, 1);
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:0], @"FOO1");
enumName = [descriptor getEnumNameForIndex:1];
XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Bar1");
XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
XCTAssertEqual(value, 2);
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:1], @"BAR1");
enumName = [descriptor getEnumNameForIndex:2];
XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Baz");
XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
XCTAssertEqual(value, 3);
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:2], @"BAZ");
enumName = [descriptor getEnumNameForIndex:3];
XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Foo2");
XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
XCTAssertEqual(value, 1);
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:3], @"FOO2");
enumName = [descriptor getEnumNameForIndex:4];
XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Bar2");
XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]);
XCTAssertEqual(value, 2);
XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:4], @"BAR2");
}
- (void)testEnumValueValidator {
GPBDescriptor *descriptor = [TestAllTypes descriptor];
GPBFieldDescriptor *fieldDescriptor =

Loading…
Cancel
Save