Add GPBMessageDropUnknownFieldsRecursively() and tests.
GPBMessageDropUnknownFieldsRecursively() is a new helper to drop the unknownFields from a message and all sub messages (in fields or extensions).
This commit is contained in:
parent
17174b54dd
commit
d07176654b
@ -392,6 +392,11 @@ void GPBSetMessageMapField(GPBMessage *self,
|
||||
**/
|
||||
NSData *GPBEmptyNSData(void) __attribute__((pure));
|
||||
|
||||
/**
|
||||
* Drops the `unknownFields` from the given message and from all sub message.
|
||||
**/
|
||||
void GPBMessageDropUnknownFieldsRecursively(GPBMessage *message);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
CF_EXTERN_C_END
|
||||
|
@ -58,6 +58,125 @@ NSData *GPBEmptyNSData(void) {
|
||||
return defaultNSData;
|
||||
}
|
||||
|
||||
void GPBMessageDropUnknownFieldsRecursively(GPBMessage *initialMessage) {
|
||||
if (!initialMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use an array as a list to process to avoid recursion.
|
||||
NSMutableArray *todo = [NSMutableArray arrayWithObject:initialMessage];
|
||||
|
||||
while (todo.count) {
|
||||
GPBMessage *msg = todo.lastObject;
|
||||
[todo removeLastObject];
|
||||
|
||||
// Clear unknowns.
|
||||
msg.unknownFields = nil;
|
||||
|
||||
// Handle the message fields.
|
||||
GPBDescriptor *descriptor = [[msg class] descriptor];
|
||||
for (GPBFieldDescriptor *field in descriptor->fields_) {
|
||||
if (!GPBFieldDataTypeIsMessage(field)) {
|
||||
continue;
|
||||
}
|
||||
switch (field.fieldType) {
|
||||
case GPBFieldTypeSingle:
|
||||
if (GPBGetHasIvarField(msg, field)) {
|
||||
GPBMessage *fieldMessage = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
|
||||
[todo addObject:fieldMessage];
|
||||
}
|
||||
break;
|
||||
|
||||
case GPBFieldTypeRepeated: {
|
||||
NSArray *fieldMessages = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
|
||||
if (fieldMessages.count) {
|
||||
[todo addObjectsFromArray:fieldMessages];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GPBFieldTypeMap: {
|
||||
id rawFieldMap = GPBGetObjectIvarWithFieldNoAutocreate(msg, field);
|
||||
switch (field.mapKeyDataType) {
|
||||
case GPBDataTypeBool:
|
||||
[(GPBBoolObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
BOOL key, id _Nonnull object, BOOL * _Nonnull stop) {
|
||||
#pragma unused(key, stop)
|
||||
[todo addObject:object];
|
||||
}];
|
||||
break;
|
||||
case GPBDataTypeFixed32:
|
||||
case GPBDataTypeUInt32:
|
||||
[(GPBUInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
uint32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
|
||||
#pragma unused(key, stop)
|
||||
[todo addObject:object];
|
||||
}];
|
||||
break;
|
||||
case GPBDataTypeInt32:
|
||||
case GPBDataTypeSFixed32:
|
||||
case GPBDataTypeSInt32:
|
||||
[(GPBInt32ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
int32_t key, id _Nonnull object, BOOL * _Nonnull stop) {
|
||||
#pragma unused(key, stop)
|
||||
[todo addObject:object];
|
||||
}];
|
||||
break;
|
||||
case GPBDataTypeFixed64:
|
||||
case GPBDataTypeUInt64:
|
||||
[(GPBUInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
uint64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
|
||||
#pragma unused(key, stop)
|
||||
[todo addObject:object];
|
||||
}];
|
||||
break;
|
||||
case GPBDataTypeInt64:
|
||||
case GPBDataTypeSFixed64:
|
||||
case GPBDataTypeSInt64:
|
||||
[(GPBInt64ObjectDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
int64_t key, id _Nonnull object, BOOL * _Nonnull stop) {
|
||||
#pragma unused(key, stop)
|
||||
[todo addObject:object];
|
||||
}];
|
||||
break;
|
||||
case GPBDataTypeString:
|
||||
[(NSDictionary*)rawFieldMap enumerateKeysAndObjectsUsingBlock:^(
|
||||
NSString * _Nonnull key, GPBMessage * _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
#pragma unused(key, stop)
|
||||
[todo addObject:obj];
|
||||
}];
|
||||
break;
|
||||
case GPBDataTypeFloat:
|
||||
case GPBDataTypeDouble:
|
||||
case GPBDataTypeEnum:
|
||||
case GPBDataTypeBytes:
|
||||
case GPBDataTypeGroup:
|
||||
case GPBDataTypeMessage:
|
||||
NSCAssert(NO, @"Aren't valid key types.");
|
||||
}
|
||||
break;
|
||||
} // switch(field.mapKeyDataType)
|
||||
} // switch(field.fieldType)
|
||||
} // for(fields)
|
||||
|
||||
// Handle any extensions holding messages.
|
||||
for (GPBExtensionDescriptor *extension in [msg extensionsCurrentlySet]) {
|
||||
if (!GPBDataTypeIsMessage(extension.dataType)) {
|
||||
continue;
|
||||
}
|
||||
if (extension.isRepeated) {
|
||||
NSArray *extMessages = [msg getExtension:extension];
|
||||
[todo addObjectsFromArray:extMessages];
|
||||
} else {
|
||||
GPBMessage *extMessage = [msg getExtension:extension];
|
||||
[todo addObject:extMessage];
|
||||
}
|
||||
} // for(extensionsCurrentlySet)
|
||||
|
||||
} // while(todo.count)
|
||||
}
|
||||
|
||||
|
||||
// -- About Version Checks --
|
||||
// There's actually 3 places these checks all come into play:
|
||||
// 1. When the generated source is compile into .o files, the header check
|
||||
|
@ -39,6 +39,7 @@
|
||||
#import "GPBDescriptor.h"
|
||||
#import "GPBDescriptor_PackagePrivate.h"
|
||||
#import "GPBMessage.h"
|
||||
#import "GPBUnknownField_PackagePrivate.h"
|
||||
|
||||
#import "google/protobuf/MapUnittest.pbobjc.h"
|
||||
#import "google/protobuf/Unittest.pbobjc.h"
|
||||
@ -197,4 +198,203 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to make an unknown field set with something in it.
|
||||
static GPBUnknownFieldSet *UnknownFieldsSetHelper(int num) {
|
||||
GPBUnknownFieldSet *result =
|
||||
[[[GPBUnknownFieldSet alloc] init] autorelease];
|
||||
|
||||
GPBUnknownField *field =
|
||||
[[[GPBUnknownField alloc] initWithNumber:num] autorelease];
|
||||
[field addVarint:num];
|
||||
[result addField:field];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)testDropMessageUnknownFieldsRecursively {
|
||||
TestAllExtensions *message = [TestAllExtensions message];
|
||||
|
||||
// Give it unknownFields.
|
||||
message.unknownFields = UnknownFieldsSetHelper(777);
|
||||
|
||||
// Given it extensions that include a message with unknown fields of its own.
|
||||
{
|
||||
// Int
|
||||
[message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
|
||||
|
||||
// Group
|
||||
OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message];
|
||||
optionalGroup.a = 123;
|
||||
optionalGroup.unknownFields = UnknownFieldsSetHelper(779);
|
||||
[message setExtension:[UnittestRoot optionalGroupExtension]
|
||||
value:optionalGroup];
|
||||
|
||||
// Message
|
||||
TestAllTypes_NestedMessage *nestedMessage =
|
||||
[TestAllTypes_NestedMessage message];
|
||||
nestedMessage.bb = 456;
|
||||
nestedMessage.unknownFields = UnknownFieldsSetHelper(778);
|
||||
[message setExtension:[UnittestRoot optionalNestedMessageExtension]
|
||||
value:nestedMessage];
|
||||
|
||||
// Repeated Group
|
||||
RepeatedGroup_extension *repeatedGroup =
|
||||
[[RepeatedGroup_extension alloc] init];
|
||||
repeatedGroup.a = 567;
|
||||
repeatedGroup.unknownFields = UnknownFieldsSetHelper(780);
|
||||
[message addExtension:[UnittestRoot repeatedGroupExtension]
|
||||
value:repeatedGroup];
|
||||
[repeatedGroup release];
|
||||
|
||||
// Repeated Message
|
||||
nestedMessage = [[TestAllTypes_NestedMessage alloc] init];
|
||||
nestedMessage.bb = 678;
|
||||
nestedMessage.unknownFields = UnknownFieldsSetHelper(781);
|
||||
[message addExtension:[UnittestRoot repeatedNestedMessageExtension]
|
||||
value:nestedMessage];
|
||||
[nestedMessage release];
|
||||
}
|
||||
|
||||
// Confirm everything is there.
|
||||
|
||||
XCTAssertNotNil(message);
|
||||
XCTAssertNotNil(message.unknownFields);
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
|
||||
OptionalGroup_extension *optionalGroup =
|
||||
[message getExtension:[UnittestRoot optionalGroupExtension]];
|
||||
XCTAssertNotNil(optionalGroup);
|
||||
XCTAssertEqual(optionalGroup.a, 123);
|
||||
XCTAssertNotNil(optionalGroup.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
|
||||
TestAllTypes_NestedMessage *nestedMessage =
|
||||
[message getExtension:[UnittestRoot optionalNestedMessageExtension]];
|
||||
XCTAssertNotNil(nestedMessage);
|
||||
XCTAssertEqual(nestedMessage.bb, 456);
|
||||
XCTAssertNotNil(nestedMessage.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]);
|
||||
NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]];
|
||||
XCTAssertEqual(repeatedGroups.count, (NSUInteger)1);
|
||||
RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject;
|
||||
XCTAssertNotNil(repeatedGroup);
|
||||
XCTAssertEqual(repeatedGroup.a, 567);
|
||||
XCTAssertNotNil(repeatedGroup.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]);
|
||||
NSArray *repeatedNestedMessages = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
|
||||
XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1);
|
||||
TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject;
|
||||
XCTAssertNotNil(repeatedNestedMessage);
|
||||
XCTAssertEqual(repeatedNestedMessage.bb, 678);
|
||||
XCTAssertNotNil(repeatedNestedMessage.unknownFields);
|
||||
}
|
||||
|
||||
// Drop them.
|
||||
GPBMessageDropUnknownFieldsRecursively(message);
|
||||
|
||||
// Confirm unknowns are gone from within the messages.
|
||||
|
||||
XCTAssertNotNil(message);
|
||||
XCTAssertNil(message.unknownFields);
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
|
||||
OptionalGroup_extension *optionalGroup =
|
||||
[message getExtension:[UnittestRoot optionalGroupExtension]];
|
||||
XCTAssertNotNil(optionalGroup);
|
||||
XCTAssertEqual(optionalGroup.a, 123);
|
||||
XCTAssertNil(optionalGroup.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
|
||||
TestAllTypes_NestedMessage *nestedMessage =
|
||||
[message getExtension:[UnittestRoot optionalNestedMessageExtension]];
|
||||
XCTAssertNotNil(nestedMessage);
|
||||
XCTAssertEqual(nestedMessage.bb, 456);
|
||||
XCTAssertNil(nestedMessage.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]);
|
||||
NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]];
|
||||
XCTAssertEqual(repeatedGroups.count, (NSUInteger)1);
|
||||
RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject;
|
||||
XCTAssertNotNil(repeatedGroup);
|
||||
XCTAssertEqual(repeatedGroup.a, 567);
|
||||
XCTAssertNil(repeatedGroup.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]);
|
||||
NSArray *repeatedNestedMessages = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
|
||||
XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1);
|
||||
TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject;
|
||||
XCTAssertNotNil(repeatedNestedMessage);
|
||||
XCTAssertEqual(repeatedNestedMessage.bb, 678);
|
||||
XCTAssertNil(repeatedNestedMessage.unknownFields);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)testDropMessageUnknownFieldsRecursively_Maps {
|
||||
TestMap *message = [TestMap message];
|
||||
|
||||
{
|
||||
ForeignMessage *foreignMessage = [ForeignMessage message];
|
||||
foreignMessage.unknownFields = UnknownFieldsSetHelper(100);
|
||||
[message.mapInt32ForeignMessage setObject:foreignMessage forKey:100];
|
||||
|
||||
foreignMessage = [ForeignMessage message];
|
||||
foreignMessage.unknownFields = UnknownFieldsSetHelper(101);
|
||||
[message.mapStringForeignMessage setObject:foreignMessage forKey:@"101"];
|
||||
}
|
||||
|
||||
// Confirm everything is there.
|
||||
|
||||
XCTAssertNotNil(message);
|
||||
|
||||
{
|
||||
ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100];
|
||||
XCTAssertNotNil(foreignMessage);
|
||||
XCTAssertNotNil(foreignMessage.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"];
|
||||
XCTAssertNotNil(foreignMessage);
|
||||
XCTAssertNotNil(foreignMessage.unknownFields);
|
||||
}
|
||||
|
||||
GPBMessageDropUnknownFieldsRecursively(message);
|
||||
|
||||
// Confirm unknowns are gone from within the messages.
|
||||
|
||||
XCTAssertNotNil(message);
|
||||
|
||||
{
|
||||
ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100];
|
||||
XCTAssertNotNil(foreignMessage);
|
||||
XCTAssertNil(foreignMessage.unknownFields);
|
||||
}
|
||||
|
||||
{
|
||||
ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"];
|
||||
XCTAssertNotNil(foreignMessage);
|
||||
XCTAssertNil(foreignMessage.unknownFields);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
Loading…
Reference in New Issue
Block a user