aboutsummaryrefslogtreecommitdiffhomepage
path: root/objectivec
diff options
context:
space:
mode:
authorGravatar Thomas Van Lenten <thomasvl@google.com>2017-02-23 12:29:00 -0500
committerGravatar Thomas Van Lenten <thomasvl@google.com>2017-02-23 15:04:06 -0500
commitd07176654b0b151eedb6b9dee37bfa3332e855c8 (patch)
tree1b49c9cb7d9cbf31a3d79b6f277f85610dc8d5aa /objectivec
parent17174b54ddd040a326dec6db75d1bfb5e5b3caa9 (diff)
Add GPBMessageDropUnknownFieldsRecursively() and tests.
GPBMessageDropUnknownFieldsRecursively() is a new helper to drop the unknownFields from a message and all sub messages (in fields or extensions).
Diffstat (limited to 'objectivec')
-rw-r--r--objectivec/GPBUtilities.h5
-rw-r--r--objectivec/GPBUtilities.m119
-rw-r--r--objectivec/Tests/GPBUtilitiesTests.m200
3 files changed, 324 insertions, 0 deletions
diff --git a/objectivec/GPBUtilities.h b/objectivec/GPBUtilities.h
index 52e7d2e0..5464dfb3 100644
--- a/objectivec/GPBUtilities.h
+++ b/objectivec/GPBUtilities.h
@@ -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
diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m
index 68aadb77..1843478c 100644
--- a/objectivec/GPBUtilities.m
+++ b/objectivec/GPBUtilities.m
@@ -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
diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m
index dfaca660..2e206a54 100644
--- a/objectivec/Tests/GPBUtilitiesTests.m
+++ b/objectivec/Tests/GPBUtilitiesTests.m
@@ -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