diff --git a/objectivec/BUILD.bazel b/objectivec/BUILD.bazel index 7f154ffff9..11dd63041d 100644 --- a/objectivec/BUILD.bazel +++ b/objectivec/BUILD.bazel @@ -59,6 +59,10 @@ staleness_test( objc_library( name = "objectivec", + srcs = [ + # Private headers that aren't used from the generated sources. + "GPBUnknownFields_PackagePrivate.h", + ], hdrs = [ "GPBAny.pbobjc.h", "GPBApi.pbobjc.h", diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h index 12908ebaeb..e9889925ac 100644 --- a/objectivec/GPBMessage.h +++ b/objectivec/GPBMessage.h @@ -16,6 +16,7 @@ @class GPBExtensionDescriptor; @class GPBFieldDescriptor; @class GPBUnknownFieldSet; +@class GPBUnknownFields; NS_ASSUME_NONNULL_BEGIN @@ -502,6 +503,18 @@ CF_EXTERN_C_END **/ - (void)clearUnknownFields; +/** + * Merges in the data from an `GPBUnknownFields`, meaning the data from the unknown fields gets + * re-parsed so any known fields will be propertly set. + * + * If the intent is to replace the message's unknown fields, call `-clearUnknownFields` first. + * + * @param unknownFields The unknown fields to merge the data from. + * @param extensionRegistry The extension registry to use to look up extensions, can be `nil`. + **/ +- (void)mergeUnknownFields:(GPBUnknownFields *)unknownFields + extensionRegistry:(nullable id)extensionRegistry; + @end NS_ASSUME_NONNULL_END diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 516f0d7057..b2c3ba77c4 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -22,6 +22,7 @@ #import "GPBExtensionRegistry.h" #import "GPBRootObject_PackagePrivate.h" #import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUnknownFields_PackagePrivate.h" #import "GPBUtilities_PackagePrivate.h" // Returns a new instance that was automatically created by |autocreator| for @@ -1255,6 +1256,16 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { self.unknownFields = nil; } +- (void)mergeUnknownFields:(GPBUnknownFields *)unknownFields + extensionRegistry:(nullable id)extensionRegistry { + NSData *data = [unknownFields serializeAsData]; + if (![self mergeFromData:data extensionRegistry:extensionRegistry error:NULL]) { +#if defined(DEBUG) && DEBUG + NSAssert(0, @"Internal error within the library, failed to parse data from unknown fields."); +#endif + }; +} + - (BOOL)isInitialized { GPBDescriptor *descriptor = [self descriptor]; for (GPBFieldDescriptor *field in descriptor->fields_) { diff --git a/objectivec/GPBUnknownField.m b/objectivec/GPBUnknownField.m index 767bc5b12d..f98de4ca5a 100644 --- a/objectivec/GPBUnknownField.m +++ b/objectivec/GPBUnknownField.m @@ -7,10 +7,12 @@ #import "GPBUnknownField.h" #import "GPBUnknownField_PackagePrivate.h" +#import "GPBWireFormat.h" #import "GPBArray.h" #import "GPBCodedOutputStream_PackagePrivate.h" #import "GPBUnknownFieldSet.h" +#import "GPBUnknownFields_PackagePrivate.h" #define ASSERT_FIELD_TYPE(type) \ if (type_ != type) { \ @@ -287,57 +289,90 @@ } - (void)writeToOutput:(GPBCodedOutputStream *)output { - ASSERT_FIELD_TYPE(GPBUnknownFieldTypeLegacy); - NSUInteger count = storage_.legacy.mutableVarintList.count; - if (count > 0) { - [output writeUInt64Array:number_ values:storage_.legacy.mutableVarintList tag:0]; - } - count = storage_.legacy.mutableFixed32List.count; - if (count > 0) { - [output writeFixed32Array:number_ values:storage_.legacy.mutableFixed32List tag:0]; - } - count = storage_.legacy.mutableFixed64List.count; - if (count > 0) { - [output writeFixed64Array:number_ values:storage_.legacy.mutableFixed64List tag:0]; - } - count = storage_.legacy.mutableLengthDelimitedList.count; - if (count > 0) { - [output writeBytesArray:number_ values:storage_.legacy.mutableLengthDelimitedList]; - } - count = storage_.legacy.mutableGroupList.count; - if (count > 0) { - [output writeUnknownGroupArray:number_ values:storage_.legacy.mutableGroupList]; + switch (type_) { + case GPBUnknownFieldTypeVarint: + [output writeUInt64:number_ value:storage_.intValue]; + break; + case GPBUnknownFieldTypeFixed32: + [output writeFixed32:number_ value:(uint32_t)storage_.intValue]; + break; + case GPBUnknownFieldTypeFixed64: + [output writeFixed64:number_ value:storage_.intValue]; + break; + case GPBUnknownFieldTypeLengthDelimited: + [output writeBytes:number_ value:storage_.lengthDelimited]; + break; + case GPBUnknownFieldTypeGroup: + [output writeRawVarint32:GPBWireFormatMakeTag(number_, GPBWireFormatStartGroup)]; + [storage_.group writeToCodedOutputStream:output]; + [output writeRawVarint32:GPBWireFormatMakeTag(number_, GPBWireFormatEndGroup)]; + break; + case GPBUnknownFieldTypeLegacy: { + NSUInteger count = storage_.legacy.mutableVarintList.count; + if (count > 0) { + [output writeUInt64Array:number_ values:storage_.legacy.mutableVarintList tag:0]; + } + count = storage_.legacy.mutableFixed32List.count; + if (count > 0) { + [output writeFixed32Array:number_ values:storage_.legacy.mutableFixed32List tag:0]; + } + count = storage_.legacy.mutableFixed64List.count; + if (count > 0) { + [output writeFixed64Array:number_ values:storage_.legacy.mutableFixed64List tag:0]; + } + count = storage_.legacy.mutableLengthDelimitedList.count; + if (count > 0) { + [output writeBytesArray:number_ values:storage_.legacy.mutableLengthDelimitedList]; + } + count = storage_.legacy.mutableGroupList.count; + if (count > 0) { + [output writeUnknownGroupArray:number_ values:storage_.legacy.mutableGroupList]; + } + } } } - (size_t)serializedSize { - ASSERT_FIELD_TYPE(GPBUnknownFieldTypeLegacy); - __block size_t result = 0; - int32_t number = number_; - [storage_.legacy.mutableVarintList - enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { - result += GPBComputeUInt64Size(number, value); - }]; - - [storage_.legacy.mutableFixed32List - enumerateValuesWithBlock:^(uint32_t value, __unused NSUInteger idx, __unused BOOL *stop) { - result += GPBComputeFixed32Size(number, value); - }]; - - [storage_.legacy.mutableFixed64List - enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { - result += GPBComputeFixed64Size(number, value); - }]; + switch (type_) { + case GPBUnknownFieldTypeVarint: + return GPBComputeUInt64Size(number_, storage_.intValue); + case GPBUnknownFieldTypeFixed32: + return GPBComputeFixed32Size(number_, (uint32_t)storage_.intValue); + case GPBUnknownFieldTypeFixed64: + return GPBComputeFixed64Size(number_, storage_.intValue); + case GPBUnknownFieldTypeLengthDelimited: + return GPBComputeBytesSize(number_, storage_.lengthDelimited); + case GPBUnknownFieldTypeGroup: + return (GPBComputeTagSize(number_) * 2) + [storage_.group serializedSize]; + case GPBUnknownFieldTypeLegacy: { + __block size_t result = 0; + int32_t number = number_; + [storage_.legacy.mutableVarintList + enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { + result += GPBComputeUInt64Size(number, value); + }]; - for (NSData *data in storage_.legacy.mutableLengthDelimitedList) { - result += GPBComputeBytesSize(number, data); - } + [storage_.legacy.mutableFixed32List + enumerateValuesWithBlock:^(uint32_t value, __unused NSUInteger idx, __unused BOOL *stop) { + result += GPBComputeFixed32Size(number, value); + }]; - for (GPBUnknownFieldSet *set in storage_.legacy.mutableGroupList) { - result += GPBComputeUnknownGroupSize(number, set); - } + [storage_.legacy.mutableFixed64List + enumerateValuesWithBlock:^(uint64_t value, __unused NSUInteger idx, __unused BOOL *stop) { + result += GPBComputeFixed64Size(number, value); + }]; - return result; + for (NSData *data in storage_.legacy.mutableLengthDelimitedList) { + result += GPBComputeBytesSize(number, data); + } + + for (GPBUnknownFieldSet *set in storage_.legacy.mutableGroupList) { + result += GPBComputeUnknownGroupSize(number, set); + } + + return result; + } + } } - (void)writeAsMessageSetExtensionToOutput:(GPBCodedOutputStream *)output { diff --git a/objectivec/GPBUnknownFields.m b/objectivec/GPBUnknownFields.m index aed1bc93e9..8856ac551f 100644 --- a/objectivec/GPBUnknownFields.m +++ b/objectivec/GPBUnknownFields.m @@ -6,6 +6,8 @@ // https://developers.google.com/open-source/licenses/bsd #import "GPBUnknownFields.h" +#import "GPBCodedOutputStream.h" +#import "GPBCodedOutputStream_PackagePrivate.h" #import "GPBUnknownField_PackagePrivate.h" #define CHECK_FIELD_NUMBER(number) \ @@ -137,6 +139,44 @@ return [fields_ countByEnumeratingWithState:state objects:stackbuf count:len]; } +#pragma mark - Internal Methods + +- (size_t)serializedSize { + size_t result = 0; + for (GPBUnknownField *field in self->fields_) { + result += [field serializedSize]; + } + return result; +} + +- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output { + for (GPBUnknownField *field in fields_) { + [field writeToOutput:output]; + } +} + +- (NSData *)serializeAsData { + if (fields_.count == 0) { + return [NSData data]; + } + size_t expectedSize = [self serializedSize]; + NSMutableData *data = [NSMutableData dataWithLength:expectedSize]; + GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithData:data]; + @try { + [self writeToCodedOutputStream:stream]; + [stream flush]; + } @catch (NSException *exception) { +#if defined(DEBUG) && DEBUG + NSLog(@"Internal exception while building GPBUnknownFields serialized data: %@", exception); +#endif + } +#if defined(DEBUG) && DEBUG + NSAssert([stream bytesWritten] == expectedSize, @"Internal error within the library"); +#endif + [stream release]; + return data; +} + @end @implementation GPBUnknownFields (AccessHelpers) diff --git a/objectivec/GPBUnknownFields_PackagePrivate.h b/objectivec/GPBUnknownFields_PackagePrivate.h new file mode 100644 index 0000000000..dc63d3a217 --- /dev/null +++ b/objectivec/GPBUnknownFields_PackagePrivate.h @@ -0,0 +1,20 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2024 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#import + +#import "GPBUnknownFields.h" + +@class GPBCodedOutputStream; + +@interface GPBUnknownFields () + +- (size_t)serializedSize; +- (nonnull NSData *)serializeAsData; +- (void)writeToCodedOutputStream:(nonnull GPBCodedOutputStream *)output; + +@end diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj index 32bfb22a3c..850e26b428 100644 --- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj @@ -76,6 +76,7 @@ F43ADD432C2F381F005312E5 /* GPBCompileTest25.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD422C2F381F005312E5 /* GPBCompileTest25.m */; }; F43ADD502C333D6C005312E5 /* GPBUnknownFields+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD4F2C333D6B005312E5 /* GPBUnknownFields+Additions.swift */; }; F43ADD562C345CED005312E5 /* GPBUnknownField+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD552C345CED005312E5 /* GPBUnknownField+Additions.swift */; }; + F43ADD5C2C35A6CC005312E5 /* GPBUnknownFields_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = F43ADD5B2C35A6CC005312E5 /* GPBUnknownFields_PackagePrivate.h */; }; F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; }; F4487C4D1A9F8E0200531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; F4487C521A9F8E4D00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; }; @@ -218,6 +219,7 @@ F43ADD422C2F381F005312E5 /* GPBCompileTest25.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest25.m; sourceTree = ""; }; F43ADD4F2C333D6B005312E5 /* GPBUnknownFields+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPBUnknownFields+Additions.swift"; sourceTree = ""; }; F43ADD552C345CED005312E5 /* GPBUnknownField+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPBUnknownField+Additions.swift"; sourceTree = ""; }; + F43ADD5B2C35A6CC005312E5 /* GPBUnknownFields_PackagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFields_PackagePrivate.h; sourceTree = ""; }; F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = ""; }; F4411BE71AF12FD700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = ""; }; F4487C511A9F8E0200531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -422,6 +424,7 @@ 7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */, 7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */, F43ADD552C345CED005312E5 /* GPBUnknownField+Additions.swift */, + F43ADD5B2C35A6CC005312E5 /* GPBUnknownFields_PackagePrivate.h */, F43ADD2F2C2F2B91005312E5 /* GPBUnknownFields.h */, F43ADD2E2C2F2B91005312E5 /* GPBUnknownFields.m */, F43ADD4F2C333D6B005312E5 /* GPBUnknownFields+Additions.swift */, @@ -582,6 +585,7 @@ buildActionMask = 2147483647; files = ( F43ADD312C2F2B91005312E5 /* GPBUnknownFields.h in Headers */, + F43ADD5C2C35A6CC005312E5 /* GPBUnknownFields_PackagePrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj index a01147a03b..63516bfd2d 100644 --- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj @@ -75,6 +75,7 @@ F43ADD472C2F387A005312E5 /* GPBCompileTest25.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD462C2F387A005312E5 /* GPBCompileTest25.m */; }; F43ADD522C333E58005312E5 /* GPBUnknownFields+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD512C333E58005312E5 /* GPBUnknownFields+Additions.swift */; }; F43ADD582C345D0D005312E5 /* GPBUnknownField+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD572C345D0D005312E5 /* GPBUnknownField+Additions.swift */; }; + F43ADD5E2C35A6E1005312E5 /* GPBUnknownFields_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = F43ADD5D2C35A6E1005312E5 /* GPBUnknownFields_PackagePrivate.h */; }; F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; }; F4487C6A1A9F8F8100531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; F4487C6F1A9F8FFF00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; }; @@ -218,6 +219,7 @@ F43ADD462C2F387A005312E5 /* GPBCompileTest25.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest25.m; sourceTree = ""; }; F43ADD512C333E58005312E5 /* GPBUnknownFields+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPBUnknownFields+Additions.swift"; sourceTree = ""; }; F43ADD572C345D0D005312E5 /* GPBUnknownField+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPBUnknownField+Additions.swift"; sourceTree = ""; }; + F43ADD5D2C35A6E1005312E5 /* GPBUnknownFields_PackagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFields_PackagePrivate.h; sourceTree = ""; }; F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = ""; }; F4411BE81AF1301700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = ""; }; F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -427,6 +429,7 @@ 7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */, 7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */, F43ADD572C345D0D005312E5 /* GPBUnknownField+Additions.swift */, + F43ADD5D2C35A6E1005312E5 /* GPBUnknownFields_PackagePrivate.h */, F43ADD372C2F2D06005312E5 /* GPBUnknownFields.h */, F43ADD362C2F2D06005312E5 /* GPBUnknownFields.m */, F43ADD512C333E58005312E5 /* GPBUnknownFields+Additions.swift */, @@ -586,6 +589,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + F43ADD5E2C35A6E1005312E5 /* GPBUnknownFields_PackagePrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj index 76c44664d2..7910048629 100644 --- a/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_tvOS.xcodeproj/project.pbxproj @@ -76,6 +76,7 @@ F43ADD492C2F389D005312E5 /* GPBCompileTest25.m in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD482C2F389D005312E5 /* GPBCompileTest25.m */; }; F43ADD542C333EE5005312E5 /* GPBUnknownFields+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD532C333EE5005312E5 /* GPBUnknownFields+Additions.swift */; }; F43ADD5A2C345D36005312E5 /* GPBUnknownField+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F43ADD592C345D36005312E5 /* GPBUnknownField+Additions.swift */; }; + F43ADD602C35A6F4005312E5 /* GPBUnknownFields_PackagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = F43ADD5F2C35A6F4005312E5 /* GPBUnknownFields_PackagePrivate.h */; }; F43C88D0191D77FC009E917D /* text_format_unittest_data.txt in Resources */ = {isa = PBXBuildFile; fileRef = F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */; }; F4487C6A1A9F8F8100531423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; F4487C6F1A9F8FFF00531423 /* GPBProtocolBuffers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */; }; @@ -219,6 +220,7 @@ F43ADD482C2F389D005312E5 /* GPBCompileTest25.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBCompileTest25.m; sourceTree = ""; }; F43ADD532C333EE5005312E5 /* GPBUnknownFields+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPBUnknownFields+Additions.swift"; sourceTree = ""; }; F43ADD592C345D36005312E5 /* GPBUnknownField+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "GPBUnknownField+Additions.swift"; sourceTree = ""; }; + F43ADD5F2C35A6F4005312E5 /* GPBUnknownFields_PackagePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFields_PackagePrivate.h; sourceTree = ""; }; F43C88CF191D77FC009E917D /* text_format_unittest_data.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = text_format_unittest_data.txt; sourceTree = ""; }; F4411BE81AF1301700324B4A /* GPBArray_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBArray_PackagePrivate.h; sourceTree = ""; }; F4487C6E1A9F8F8100531423 /* libTestSingleSourceBuild.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTestSingleSourceBuild.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -428,6 +430,7 @@ 7461B4AE0F94F99000A0C422 /* GPBUnknownField.h */, 7461B4AF0F94F99000A0C422 /* GPBUnknownField.m */, F43ADD592C345D36005312E5 /* GPBUnknownField+Additions.swift */, + F43ADD5F2C35A6F4005312E5 /* GPBUnknownFields_PackagePrivate.h */, F43ADD3C2C2F2D3D005312E5 /* GPBUnknownFields.h */, F43ADD3B2C2F2D3D005312E5 /* GPBUnknownFields.m */, F43ADD532C333EE5005312E5 /* GPBUnknownFields+Additions.swift */, @@ -588,6 +591,7 @@ buildActionMask = 2147483647; files = ( F43ADD3E2C2F2D3D005312E5 /* GPBUnknownFields.h in Headers */, + F43ADD602C35A6F4005312E5 /* GPBUnknownFields_PackagePrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/objectivec/Tests/GPBTestUtilities.h b/objectivec/Tests/GPBTestUtilities.h index 1072f889d3..03ac8f92cd 100644 --- a/objectivec/Tests/GPBTestUtilities.h +++ b/objectivec/Tests/GPBTestUtilities.h @@ -20,6 +20,22 @@ static inline NSData *DataFromCStr(const char *str) { return [NSData dataWithBytes:str length:strlen(str)]; } +static inline NSData *_DataFromBytesInternal(int32_t unused, ...) { + NSMutableData *values = [NSMutableData dataWithCapacity:0]; + va_list list; + va_start(list, unused); + int32_t n; + while ((n = va_arg(list, int32_t)) != 256) { + NSCAssert(n >= 0 && n < 256, @"Only 8 bit values"); + uint8_t u = (uint8_t)n; + [values appendBytes:&u length:1]; + } + va_end(list); + return values; +} + +#define DataFromBytes(...) _DataFromBytesInternal(0, __VA_ARGS__, 256) + // Helper for uses of C arrays in tests cases. #ifndef GPBARRAYSIZE #define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) diff --git a/objectivec/Tests/GPBUnknownFieldsTest.m b/objectivec/Tests/GPBUnknownFieldsTest.m index 552c21d651..01f36689db 100644 --- a/objectivec/Tests/GPBUnknownFieldsTest.m +++ b/objectivec/Tests/GPBUnknownFieldsTest.m @@ -5,9 +5,12 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd +#import + #import "GPBTestUtilities.h" #import "GPBUnknownField.h" #import "GPBUnknownFields.h" +#import "GPBUnknownFields_PackagePrivate.h" #import "objectivec/Tests/Unittest.pbobjc.h" @interface UnknownFieldsTest : GPBTestCase @@ -511,4 +514,66 @@ XCTAssertThrowsSpecificNamed([ufs fields:-1], NSException, NSInvalidArgumentException); } +- (void)testSerialize { + // Don't need to test CodedOutputStream, just make sure things basically end up there. + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + XCTAssertEqualObjects([ufs serializeAsData], [NSData data]); + } + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addFieldNumber:1 varint:1]; + XCTAssertEqualObjects([ufs serializeAsData], DataFromBytes(0x08, 0x01)); + } + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addFieldNumber:1 fixed32:1]; + XCTAssertEqualObjects([ufs serializeAsData], DataFromBytes(0x0d, 0x01, 0x00, 0x00, 0x00)); + } + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addFieldNumber:1 fixed64:1]; + XCTAssertEqualObjects([ufs serializeAsData], + DataFromBytes(0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); + } + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addFieldNumber:1 lengthDelimited:DataFromCStr("foo")]; + XCTAssertEqualObjects([ufs serializeAsData], DataFromBytes(0x0a, 0x03, 0x66, 0x6f, 0x6f)); + } + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addGroupWithFieldNumber:1]; // Empty group + XCTAssertEqualObjects([ufs serializeAsData], DataFromBytes(0x0b, 0x0c)); + } + { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + GPBUnknownFields* group = [ufs addGroupWithFieldNumber:1]; // With some fields + [group addFieldNumber:10 varint:10]; + [group addFieldNumber:11 fixed32:32]; + [group addFieldNumber:12 fixed32:32]; + XCTAssertEqualObjects([ufs serializeAsData], + DataFromBytes(0x0b, 0x50, 0x0a, 0x5d, 0x20, 0x00, 0x00, 0x00, 0x65, 0x20, + 0x00, 0x00, 0x00, 0x0c)); + } +} + +- (void)testMessageMergeUnknowns { + GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease]; + [ufs addFieldNumber:TestAllTypes_FieldNumber_OptionalInt64 varint:100]; + [ufs addFieldNumber:TestAllTypes_FieldNumber_OptionalFixed32 fixed32:200]; + [ufs addFieldNumber:TestAllTypes_FieldNumber_OptionalFixed64 fixed64:300]; + [ufs addFieldNumber:TestAllTypes_FieldNumber_OptionalBytes lengthDelimited:DataFromCStr("foo")]; + GPBUnknownFields* group = [ufs addGroupWithFieldNumber:TestAllTypes_FieldNumber_OptionalGroup]; + [group addFieldNumber:TestAllTypes_OptionalGroup_FieldNumber_A varint:55]; + + TestAllTypes* msg = [TestAllTypes message]; + [msg mergeUnknownFields:ufs extensionRegistry:nil]; + XCTAssertEqual(msg.optionalInt64, 100); + XCTAssertEqual(msg.optionalFixed32, 200); + XCTAssertEqual(msg.optionalFixed64, 300); + XCTAssertEqualObjects(msg.optionalBytes, DataFromCStr("foo")); + XCTAssertEqual(msg.optionalGroup.a, 55); +} + @end