Minor fix for autocreated object repeated fields and maps.
- If setting/clearing a repeated field/map that was objects, check the class before checking the autocreator. - Just to be paranoid, don’t mutate within copy/mutableCopy for the autocreated classes to ensure there is less chance of issues if someone does something really crazy threading wise. - Some more tests for the internal AutocreatedArray/AutocreatedDictionary classes to ensure things are working as expected. - Add Xcode 8.2 to the full_mac_build.sh supported list.
This commit is contained in:
parent
4cb113a91b
commit
988ffe0a78
@ -525,6 +525,7 @@ objectivec_EXTRA_DIST= \
|
||||
objectivec/Tests/GPBDictionaryTests+String.m \
|
||||
objectivec/Tests/GPBDictionaryTests+UInt32.m \
|
||||
objectivec/Tests/GPBDictionaryTests+UInt64.m \
|
||||
objectivec/Tests/GPBDictionaryTests.m \
|
||||
objectivec/Tests/GPBDictionaryTests.pddm \
|
||||
objectivec/Tests/GPBMessageTests+Merge.m \
|
||||
objectivec/Tests/GPBMessageTests+Runtime.m \
|
||||
|
@ -265,6 +265,14 @@ if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then
|
||||
-destination "platform=iOS Simulator,name=iPad Pro (9.7 inch),OS=10.1" # 64bit
|
||||
)
|
||||
;;
|
||||
8.2* )
|
||||
XCODEBUILD_TEST_BASE_IOS+=(
|
||||
-destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit
|
||||
-destination "platform=iOS Simulator,name=iPhone 7,OS=10.2" # 64bit
|
||||
-destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit
|
||||
-destination "platform=iOS Simulator,name=iPad Pro (9.7 inch),OS=10.2" # 64bit
|
||||
)
|
||||
;;
|
||||
* )
|
||||
echo "Time to update the simulator targets for Xcode ${XCODE_VERSION}"
|
||||
exit 2
|
||||
|
@ -2519,14 +2519,14 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) {
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
if (_array == nil) {
|
||||
_array = [[NSMutableArray alloc] init];
|
||||
return [[NSMutableArray allocWithZone:zone] init];
|
||||
}
|
||||
return [_array copyWithZone:zone];
|
||||
}
|
||||
|
||||
- (id)mutableCopyWithZone:(NSZone *)zone {
|
||||
if (_array == nil) {
|
||||
_array = [[NSMutableArray alloc] init];
|
||||
return [[NSMutableArray allocWithZone:zone] init];
|
||||
}
|
||||
return [_array mutableCopyWithZone:zone];
|
||||
}
|
||||
|
@ -13579,22 +13579,26 @@ void GPBDictionaryReadEntry(id mapDictionary,
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
if (_dictionary == nil) {
|
||||
_dictionary = [[NSMutableDictionary alloc] init];
|
||||
return [[NSMutableDictionary allocWithZone:zone] init];
|
||||
}
|
||||
return [_dictionary copyWithZone:zone];
|
||||
}
|
||||
|
||||
- (id)mutableCopyWithZone:(NSZone *)zone {
|
||||
if (_dictionary == nil) {
|
||||
_dictionary = [[NSMutableDictionary alloc] init];
|
||||
return [[NSMutableDictionary allocWithZone:zone] init];
|
||||
}
|
||||
return [_dictionary mutableCopyWithZone:zone];
|
||||
}
|
||||
|
||||
// Not really needed, but subscripting is likely common enough it doesn't hurt
|
||||
// to ensure it goes directly to the real NSMutableDictionary.
|
||||
- (id)objectForKeyedSubscript:(id)key {
|
||||
return [_dictionary objectForKeyedSubscript:key];
|
||||
}
|
||||
|
||||
// Not really needed, but subscripting is likely common enough it doesn't hurt
|
||||
// to ensure it goes directly to the real NSMutableDictionary.
|
||||
- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
|
||||
if (_dictionary == nil) {
|
||||
_dictionary = [[NSMutableDictionary alloc] init];
|
||||
|
@ -1023,9 +1023,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
|
||||
if (arrayOrMap) {
|
||||
if (field.fieldType == GPBFieldTypeRepeated) {
|
||||
if (GPBFieldDataTypeIsObject(field)) {
|
||||
GPBAutocreatedArray *autoArray = arrayOrMap;
|
||||
if (autoArray->_autocreator == self) {
|
||||
autoArray->_autocreator = nil;
|
||||
if ([arrayOrMap isKindOfClass:[GPBAutocreatedArray class]]) {
|
||||
GPBAutocreatedArray *autoArray = arrayOrMap;
|
||||
if (autoArray->_autocreator == self) {
|
||||
autoArray->_autocreator = nil;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Type doesn't matter, it is a GPB*Array.
|
||||
@ -1037,9 +1039,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) {
|
||||
} else {
|
||||
if ((field.mapKeyDataType == GPBDataTypeString) &&
|
||||
GPBFieldDataTypeIsObject(field)) {
|
||||
GPBAutocreatedDictionary *autoDict = arrayOrMap;
|
||||
if (autoDict->_autocreator == self) {
|
||||
autoDict->_autocreator = nil;
|
||||
if ([arrayOrMap isKindOfClass:[GPBAutocreatedDictionary class]]) {
|
||||
GPBAutocreatedDictionary *autoDict = arrayOrMap;
|
||||
if (autoDict->_autocreator == self) {
|
||||
autoDict->_autocreator = nil;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Type doesn't matter, it is a GPB*Dictionary.
|
||||
|
@ -408,9 +408,11 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
|
||||
if (field.fieldType == GPBFieldTypeRepeated) {
|
||||
// If the old array was autocreated by us, then clear it.
|
||||
if (GPBDataTypeIsObject(fieldType)) {
|
||||
GPBAutocreatedArray *autoArray = oldValue;
|
||||
if (autoArray->_autocreator == self) {
|
||||
autoArray->_autocreator = nil;
|
||||
if ([oldValue isKindOfClass:[GPBAutocreatedArray class]]) {
|
||||
GPBAutocreatedArray *autoArray = oldValue;
|
||||
if (autoArray->_autocreator == self) {
|
||||
autoArray->_autocreator = nil;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Type doesn't matter, it is a GPB*Array.
|
||||
@ -423,9 +425,11 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self,
|
||||
// If the old map was autocreated by us, then clear it.
|
||||
if ((field.mapKeyDataType == GPBDataTypeString) &&
|
||||
GPBDataTypeIsObject(fieldType)) {
|
||||
GPBAutocreatedDictionary *autoDict = oldValue;
|
||||
if (autoDict->_autocreator == self) {
|
||||
autoDict->_autocreator = nil;
|
||||
if ([oldValue isKindOfClass:[GPBAutocreatedDictionary class]]) {
|
||||
GPBAutocreatedDictionary *autoDict = oldValue;
|
||||
if (autoDict->_autocreator == self) {
|
||||
autoDict->_autocreator = nil;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Type doesn't matter, it is a GPB*Dictionary.
|
||||
|
@ -57,6 +57,7 @@
|
||||
F47476E51D21A524007C7B1A /* Duration.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */; };
|
||||
F47476E61D21A524007C7B1A /* Timestamp.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */; };
|
||||
F4B51B1E1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1D1BBC610700744318 /* GPBObjectiveCPlusPlusTest.mm */; };
|
||||
F4C4B9E41E1D976300D3B61D /* GPBDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4C4B9E21E1D974F00D3B61D /* GPBDictionaryTests.m */; };
|
||||
F4E675971B21D0000054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675871B21D0000054530B /* Any.pbobjc.m */; };
|
||||
F4E675991B21D0000054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675891B21D0000054530B /* Api.pbobjc.m */; };
|
||||
F4E6759B1B21D0000054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E6758B1B21D0000054530B /* Empty.pbobjc.m */; };
|
||||
@ -187,6 +188,7 @@
|
||||
F4B6B8B21A9CCBDA00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; };
|
||||
F4B6B8B61A9CD1DE00892426 /* GPBExtensionInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionInternals.h; sourceTree = "<group>"; };
|
||||
F4B6B8B81A9CD1DE00892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; };
|
||||
F4C4B9E21E1D974F00D3B61D /* GPBDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionaryTests.m; sourceTree = "<group>"; };
|
||||
F4CF31701B162ED800BD9B06 /* unittest_objc_startup.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc_startup.proto; sourceTree = "<group>"; };
|
||||
F4E675861B21D0000054530B /* Any.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Any.pbobjc.h; path = google/protobuf/Any.pbobjc.h; sourceTree = "<group>"; };
|
||||
F4E675871B21D0000054530B /* Any.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Any.pbobjc.m; path = google/protobuf/Any.pbobjc.m; sourceTree = "<group>"; };
|
||||
@ -393,6 +395,7 @@
|
||||
7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */,
|
||||
5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */,
|
||||
F4353D1C1AB8822D005A6198 /* GPBDescriptorTests.m */,
|
||||
F4C4B9E21E1D974F00D3B61D /* GPBDictionaryTests.m */,
|
||||
F4353D2C1AC06F10005A6198 /* GPBDictionaryTests.pddm */,
|
||||
F4353D2D1AC06F10005A6198 /* GPBDictionaryTests+Bool.m */,
|
||||
F4353D2E1AC06F10005A6198 /* GPBDictionaryTests+Int32.m */,
|
||||
@ -677,6 +680,7 @@
|
||||
F4353D371AC06F10005A6198 /* GPBDictionaryTests+String.m in Sources */,
|
||||
F4353D381AC06F10005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,
|
||||
8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */,
|
||||
F4C4B9E41E1D976300D3B61D /* GPBDictionaryTests.m in Sources */,
|
||||
8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */,
|
||||
8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */,
|
||||
8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */,
|
||||
|
@ -65,6 +65,7 @@
|
||||
F47476E91D21A537007C7B1A /* Duration.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */; };
|
||||
F47476EA1D21A537007C7B1A /* Timestamp.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B4248E01A929C7D00BC1EC6 /* Timestamp.pbobjc.m */; };
|
||||
F4B51B1C1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4B51B1B1BBC5C7100744318 /* GPBObjectiveCPlusPlusTest.mm */; };
|
||||
F4C4B9E71E1D97BF00D3B61D /* GPBDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F4C4B9E51E1D97BB00D3B61D /* GPBDictionaryTests.m */; };
|
||||
F4E675D01B21D1620054530B /* Any.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B71B21D1440054530B /* Any.pbobjc.m */; };
|
||||
F4E675D11B21D1620054530B /* Api.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675B91B21D1440054530B /* Api.pbobjc.m */; };
|
||||
F4E675D21B21D1620054530B /* Empty.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E675BC1B21D1440054530B /* Empty.pbobjc.m */; };
|
||||
@ -209,6 +210,7 @@
|
||||
F4B6B8B11A9CCBBB00892426 /* GPBUnknownFieldSet_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBUnknownFieldSet_PackagePrivate.h; sourceTree = "<group>"; };
|
||||
F4B6B8B31A9CD1C600892426 /* GPBExtensionInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBExtensionInternals.h; sourceTree = "<group>"; };
|
||||
F4B6B8B51A9CD1C600892426 /* GPBRootObject_PackagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRootObject_PackagePrivate.h; sourceTree = "<group>"; };
|
||||
F4C4B9E51E1D97BB00D3B61D /* GPBDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBDictionaryTests.m; sourceTree = "<group>"; };
|
||||
F4CF31711B162EF500BD9B06 /* unittest_objc_startup.proto */ = {isa = PBXFileReference; lastKnownFileType = text; path = unittest_objc_startup.proto; sourceTree = "<group>"; };
|
||||
F4E675B61B21D1440054530B /* Any.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Any.pbobjc.h; path = google/protobuf/Any.pbobjc.h; sourceTree = "<group>"; };
|
||||
F4E675B71B21D1440054530B /* Any.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Any.pbobjc.m; path = google/protobuf/Any.pbobjc.m; sourceTree = "<group>"; };
|
||||
@ -431,6 +433,7 @@
|
||||
7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */,
|
||||
5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */,
|
||||
F4353D1E1AB88243005A6198 /* GPBDescriptorTests.m */,
|
||||
F4C4B9E51E1D97BB00D3B61D /* GPBDictionaryTests.m */,
|
||||
F4353D3A1AC06F31005A6198 /* GPBDictionaryTests.pddm */,
|
||||
F4353D3B1AC06F31005A6198 /* GPBDictionaryTests+Bool.m */,
|
||||
F4353D3C1AC06F31005A6198 /* GPBDictionaryTests+Int32.m */,
|
||||
@ -773,6 +776,7 @@
|
||||
F4353D451AC06F31005A6198 /* GPBDictionaryTests+String.m in Sources */,
|
||||
F4353D461AC06F31005A6198 /* GPBDictionaryTests+UInt32.m in Sources */,
|
||||
8BBEA4B7147C727D00C4ADB7 /* GPBUtilitiesTests.m in Sources */,
|
||||
F4C4B9E71E1D97BF00D3B61D /* GPBDictionaryTests.m in Sources */,
|
||||
8BBEA4B8147C727D00C4ADB7 /* GPBWireFormatTests.m in Sources */,
|
||||
8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */,
|
||||
8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "GPBArray.h"
|
||||
#import "GPBArray_PackagePrivate.h"
|
||||
|
||||
#import "GPBTestUtilities.h"
|
||||
|
||||
@ -3436,3 +3437,175 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - GPBAutocreatedArray Tests
|
||||
|
||||
// These are hand written tests to double check some behaviors of the
|
||||
// GPBAutocreatedArray.
|
||||
|
||||
// NOTE: GPBAutocreatedArray is private to the library, users of the library
|
||||
// should never have to directly deal with this class.
|
||||
|
||||
@interface GPBAutocreatedArrayTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation GPBAutocreatedArrayTests
|
||||
|
||||
- (void)testEquality {
|
||||
GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init];
|
||||
|
||||
XCTAssertTrue([array isEqual:@[]]);
|
||||
XCTAssertTrue([array isEqualToArray:@[]]);
|
||||
|
||||
XCTAssertFalse([array isEqual:@[ @"foo" ]]);
|
||||
XCTAssertFalse([array isEqualToArray:@[ @"foo" ]]);
|
||||
|
||||
[array addObject:@"foo"];
|
||||
|
||||
XCTAssertFalse([array isEqual:@[]]);
|
||||
XCTAssertFalse([array isEqualToArray:@[]]);
|
||||
XCTAssertTrue([array isEqual:@[ @"foo" ]]);
|
||||
XCTAssertTrue([array isEqualToArray:@[ @"foo" ]]);
|
||||
XCTAssertFalse([array isEqual:@[ @"bar" ]]);
|
||||
XCTAssertFalse([array isEqualToArray:@[ @"bar" ]]);
|
||||
|
||||
GPBAutocreatedArray *array2 = [[GPBAutocreatedArray alloc] init];
|
||||
|
||||
XCTAssertFalse([array isEqual:array2]);
|
||||
XCTAssertFalse([array isEqualToArray:array2]);
|
||||
|
||||
[array2 addObject:@"bar"];
|
||||
XCTAssertFalse([array isEqual:array2]);
|
||||
XCTAssertFalse([array isEqualToArray:array2]);
|
||||
|
||||
[array2 replaceObjectAtIndex:0 withObject:@"foo"];
|
||||
XCTAssertTrue([array isEqual:array2]);
|
||||
XCTAssertTrue([array isEqualToArray:array2]);
|
||||
|
||||
[array2 release];
|
||||
[array release];
|
||||
}
|
||||
|
||||
- (void)testCopy {
|
||||
{
|
||||
GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init];
|
||||
|
||||
NSArray *cpy = [array copy];
|
||||
XCTAssertTrue(cpy != array); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSArray class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)0);
|
||||
|
||||
NSArray *cpy2 = [array copy];
|
||||
XCTAssertTrue(cpy2 != array); // Ptr compare
|
||||
// Can't compare cpy and cpy2 because NSArray has a singleton empty
|
||||
// array it uses, so the ptrs are the same.
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)0);
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[array release];
|
||||
}
|
||||
|
||||
{
|
||||
GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init];
|
||||
|
||||
NSMutableArray *cpy = [array mutableCopy];
|
||||
XCTAssertTrue(cpy != array); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSMutableArray class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)0);
|
||||
|
||||
NSMutableArray *cpy2 = [array mutableCopy];
|
||||
XCTAssertTrue(cpy2 != array); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSMutableArray class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)0);
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[array release];
|
||||
}
|
||||
|
||||
{
|
||||
GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init];
|
||||
[array addObject:@"foo"];
|
||||
[array addObject:@"bar"];
|
||||
|
||||
NSArray *cpy = [array copy];
|
||||
XCTAssertTrue(cpy != array); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSArray class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy[0], @"foo");
|
||||
XCTAssertEqualObjects(cpy[1], @"bar");
|
||||
|
||||
NSArray *cpy2 = [array copy];
|
||||
XCTAssertTrue(cpy2 != array); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy2[0], @"foo");
|
||||
XCTAssertEqualObjects(cpy2[1], @"bar");
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[array release];
|
||||
}
|
||||
|
||||
{
|
||||
GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init];
|
||||
[array addObject:@"foo"];
|
||||
[array addObject:@"bar"];
|
||||
|
||||
NSMutableArray *cpy = [array mutableCopy];
|
||||
XCTAssertTrue(cpy != array); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSArray class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy[0], @"foo");
|
||||
XCTAssertEqualObjects(cpy[1], @"bar");
|
||||
|
||||
NSMutableArray *cpy2 = [array mutableCopy];
|
||||
XCTAssertTrue(cpy2 != array); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy2[0], @"foo");
|
||||
XCTAssertEqualObjects(cpy2[1], @"bar");
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[array release];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testIndexedSubscriptSupport {
|
||||
// The base NSArray/NSMutableArray behaviors for *IndexedSubscript methods
|
||||
// should still work via the methods that one has to override to make an
|
||||
// NSMutableArray subclass. i.e. - this should "just work" and if these
|
||||
// crash/fail, then something is wrong in how NSMutableArray is subclassed.
|
||||
|
||||
GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init];
|
||||
|
||||
[array addObject:@"foo"];
|
||||
[array addObject:@"bar"];
|
||||
XCTAssertEqual(array.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(array[0], @"foo");
|
||||
XCTAssertEqualObjects(array[1], @"bar");
|
||||
array[0] = @"foo2";
|
||||
array[2] = @"baz";
|
||||
XCTAssertEqual(array.count, (NSUInteger)3);
|
||||
XCTAssertEqualObjects(array[0], @"foo2");
|
||||
XCTAssertEqualObjects(array[1], @"bar");
|
||||
XCTAssertEqualObjects(array[2], @"baz");
|
||||
|
||||
[array release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
186
objectivec/Tests/GPBDictionaryTests.m
Normal file
186
objectivec/Tests/GPBDictionaryTests.m
Normal file
@ -0,0 +1,186 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "GPBDictionary.h"
|
||||
#import "GPBDictionary_PackagePrivate.h"
|
||||
|
||||
#import "GPBTestUtilities.h"
|
||||
|
||||
#pragma mark - GPBAutocreatedDictionary Tests
|
||||
|
||||
// These are hand written tests to double check some behaviors of the
|
||||
// GPBAutocreatedDictionary. The GPBDictionary+[type]Tests files are generate
|
||||
// tests.
|
||||
|
||||
// NOTE: GPBAutocreatedDictionary is private to the library, users of the
|
||||
// library should never have to directly deal with this class.
|
||||
|
||||
@interface GPBAutocreatedDictionaryTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation GPBAutocreatedDictionaryTests
|
||||
|
||||
- (void)testEquality {
|
||||
GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init];
|
||||
|
||||
XCTAssertTrue([dict isEqual:@{}]);
|
||||
XCTAssertTrue([dict isEqualToDictionary:@{}]);
|
||||
|
||||
XCTAssertFalse([dict isEqual:@{ @"foo" : @"bar" }]);
|
||||
XCTAssertFalse([dict isEqualToDictionary:@{ @"foo" : @"bar" }]);
|
||||
|
||||
[dict setObject:@"bar" forKey:@"foo"];
|
||||
|
||||
XCTAssertFalse([dict isEqual:@{}]);
|
||||
XCTAssertFalse([dict isEqualToDictionary:@{}]);
|
||||
XCTAssertTrue([dict isEqual:@{ @"foo" : @"bar" }]);
|
||||
XCTAssertTrue([dict isEqualToDictionary:@{ @"foo" : @"bar" }]);
|
||||
XCTAssertFalse([dict isEqual:@{ @"bar" : @"baz" }]);
|
||||
XCTAssertFalse([dict isEqualToDictionary:@{ @"bar" : @"baz" }]);
|
||||
|
||||
GPBAutocreatedDictionary *dict2 = [[GPBAutocreatedDictionary alloc] init];
|
||||
|
||||
XCTAssertFalse([dict isEqual:dict2]);
|
||||
XCTAssertFalse([dict isEqualToDictionary:dict2]);
|
||||
|
||||
[dict2 setObject:@"mumble" forKey:@"foo"];
|
||||
XCTAssertFalse([dict isEqual:dict2]);
|
||||
XCTAssertFalse([dict isEqualToDictionary:dict2]);
|
||||
|
||||
[dict2 setObject:@"bar" forKey:@"foo"];
|
||||
XCTAssertTrue([dict isEqual:dict2]);
|
||||
XCTAssertTrue([dict isEqualToDictionary:dict2]);
|
||||
|
||||
[dict2 release];
|
||||
[dict release];
|
||||
}
|
||||
|
||||
- (void)testCopy {
|
||||
{
|
||||
GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init];
|
||||
|
||||
NSDictionary *cpy = [dict copy];
|
||||
XCTAssertTrue(cpy != dict); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSDictionary class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)0);
|
||||
|
||||
NSDictionary *cpy2 = [dict copy];
|
||||
XCTAssertTrue(cpy2 != dict); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSDictionary class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)0);
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[dict release];
|
||||
}
|
||||
|
||||
{
|
||||
GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init];
|
||||
|
||||
NSMutableDictionary *cpy = [dict mutableCopy];
|
||||
XCTAssertTrue(cpy != dict); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSMutableDictionary class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)0);
|
||||
|
||||
NSMutableDictionary *cpy2 = [dict mutableCopy];
|
||||
XCTAssertTrue(cpy2 != dict); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSMutableDictionary class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)0);
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[dict release];
|
||||
}
|
||||
|
||||
{
|
||||
GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init];
|
||||
dict[@"foo"] = @"bar";
|
||||
dict[@"baz"] = @"mumble";
|
||||
|
||||
NSDictionary *cpy = [dict copy];
|
||||
XCTAssertTrue(cpy != dict); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSDictionary class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy[@"foo"], @"bar");
|
||||
XCTAssertEqualObjects(cpy[@"baz"], @"mumble");
|
||||
|
||||
NSDictionary *cpy2 = [dict copy];
|
||||
XCTAssertTrue(cpy2 != dict); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSDictionary class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy2[@"foo"], @"bar");
|
||||
XCTAssertEqualObjects(cpy2[@"baz"], @"mumble");
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[dict release];
|
||||
}
|
||||
|
||||
{
|
||||
GPBAutocreatedDictionary *dict = [[GPBAutocreatedDictionary alloc] init];
|
||||
dict[@"foo"] = @"bar";
|
||||
dict[@"baz"] = @"mumble";
|
||||
|
||||
NSMutableDictionary *cpy = [dict mutableCopy];
|
||||
XCTAssertTrue(cpy != dict); // Ptr compare
|
||||
XCTAssertTrue([cpy isKindOfClass:[NSMutableDictionary class]]);
|
||||
XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy[@"foo"], @"bar");
|
||||
XCTAssertEqualObjects(cpy[@"baz"], @"mumble");
|
||||
|
||||
NSMutableDictionary *cpy2 = [dict mutableCopy];
|
||||
XCTAssertTrue(cpy2 != dict); // Ptr compare
|
||||
XCTAssertTrue(cpy2 != cpy); // Ptr compare
|
||||
XCTAssertTrue([cpy2 isKindOfClass:[NSMutableDictionary class]]);
|
||||
XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedDictionary class]]);
|
||||
XCTAssertEqual(cpy2.count, (NSUInteger)2);
|
||||
XCTAssertEqualObjects(cpy2[@"foo"], @"bar");
|
||||
XCTAssertEqualObjects(cpy2[@"baz"], @"mumble");
|
||||
|
||||
[cpy2 release];
|
||||
[cpy release];
|
||||
[dict release];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1082,6 +1082,20 @@
|
||||
[repeatedStringArray release];
|
||||
}
|
||||
|
||||
- (void)testSetOverAutocreatedArrayAndSetAgain {
|
||||
// Ensure when dealing with replacing an array it is handled being either
|
||||
// an autocreated one or a straight NSArray.
|
||||
|
||||
// The real test here is that nothing crashes while doing the work.
|
||||
TestAllTypes *message = [TestAllTypes message];
|
||||
[message.repeatedStringArray addObject:@"foo"];
|
||||
XCTAssertEqual(message.repeatedStringArray_Count, (NSUInteger)1);
|
||||
message.repeatedStringArray = [NSMutableArray arrayWithObjects:@"bar", @"bar2", nil];
|
||||
XCTAssertEqual(message.repeatedStringArray_Count, (NSUInteger)2);
|
||||
message.repeatedStringArray = [NSMutableArray arrayWithObject:@"baz"];
|
||||
XCTAssertEqual(message.repeatedStringArray_Count, (NSUInteger)1);
|
||||
}
|
||||
|
||||
- (void)testReplaceAutocreatedArray {
|
||||
// Replacing array should orphan the old one and cause its creator to become
|
||||
// visible.
|
||||
@ -1281,6 +1295,23 @@
|
||||
[strToStr release];
|
||||
}
|
||||
|
||||
- (void)testSetOverAutocreatedMapAndSetAgain {
|
||||
// Ensure when dealing with replacing a map it is handled being either
|
||||
// an autocreated one or a straight NSDictionary.
|
||||
|
||||
// The real test here is that nothing crashes while doing the work.
|
||||
TestRecursiveMessageWithRepeatedField *message =
|
||||
[TestRecursiveMessageWithRepeatedField message];
|
||||
message.strToStr[@"foo"] = @"bar";
|
||||
XCTAssertEqual(message.strToStr_Count, (NSUInteger)1);
|
||||
message.strToStr =
|
||||
[NSMutableDictionary dictionaryWithObjectsAndKeys:@"bar", @"key1", @"baz", @"key2", nil];
|
||||
XCTAssertEqual(message.strToStr_Count, (NSUInteger)2);
|
||||
message.strToStr =
|
||||
[NSMutableDictionary dictionaryWithObject:@"baz" forKey:@"mumble"];
|
||||
XCTAssertEqual(message.strToStr_Count, (NSUInteger)1);
|
||||
}
|
||||
|
||||
- (void)testReplaceAutocreatedMap {
|
||||
// Replacing map should orphan the old one and cause its creator to become
|
||||
// visible.
|
||||
|
Loading…
Reference in New Issue
Block a user