Skip to content

Commit

Permalink
Minor fix for autocreated object repeated fields and maps.
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
thomasvl committed Jan 5, 2017
1 parent 4cb113a commit 988ffe0
Show file tree
Hide file tree
Showing 11 changed files with 435 additions and 16 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
8 changes: 8 additions & 0 deletions objectivec/DevTools/full_mac_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions objectivec/GPBArray.m
Original file line number Diff line number Diff line change
Expand Up @@ -2519,14 +2519,14 @@ - (void)replaceObjectAtIndex:(NSUInteger)idx withObject:(id)anObject {

- (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];
}
Expand Down
8 changes: 6 additions & 2 deletions objectivec/GPBDictionary.m
Original file line number Diff line number Diff line change
Expand Up @@ -13579,22 +13579,26 @@ - (void)removeObjectForKey:(id)aKey {

- (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];
Expand Down
16 changes: 10 additions & 6 deletions objectivec/GPBMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -1023,9 +1023,11 @@ - (void)internalClear:(BOOL)zeroStorage {
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.
Expand All @@ -1037,9 +1039,11 @@ - (void)internalClear:(BOOL)zeroStorage {
} 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.
Expand Down
16 changes: 10 additions & 6 deletions objectivec/GPBUtilities.m
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down
4 changes: 4 additions & 0 deletions objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down
173 changes: 173 additions & 0 deletions objectivec/Tests/GPBArrayTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#import <XCTest/XCTest.h>

#import "GPBArray.h"
#import "GPBArray_PackagePrivate.h"

#import "GPBTestUtilities.h"

Expand Down Expand Up @@ -3436,3 +3437,175 @@ - (void)testRawInternalResizing {
}

@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
Loading

0 comments on commit 988ffe0

Please sign in to comment.