FBRetainCycleDetectorTests/FBObjectiveCObjectTests.m (196 lines of code) (raw):
/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <XCTest/XCTest.h>
#import <FBRetainCycleDetector/FBObjectiveCGraphElement+Internal.h>
#import <FBRetainCycleDetector/FBObjectiveCObject.h>
#import <FBRetainCycleDetector/FBRetainCycleDetector.h>
@interface _RCDObjectWrapperTestClass : NSObject
- (instancetype)initWithOtherObject:(_RCDObjectWrapperTestClass *)object;
@property (nonatomic, strong) NSObject *someObject;
@property (nonatomic, copy) NSString *someString;
@property (nonatomic, weak) NSObject *irrelevantObject;
@property (nonatomic, strong) id aCls;
@end
@implementation _RCDObjectWrapperTestClass
{
_RCDObjectWrapperTestClass *_someTestClassInstance;
}
- (instancetype)initWithOtherObject:(_RCDObjectWrapperTestClass *)object
{
if (self = [super init]) {
_someTestClassInstance = object;
}
return self;
}
@end
@interface _RCDObjectWrapperTestClassSubclass : _RCDObjectWrapperTestClass
@end
@implementation _RCDObjectWrapperTestClassSubclass
@end
@interface FBObjectiveCObjectTests : XCTestCase
@end
@implementation FBObjectiveCObjectTests
#if _INTERNAL_RCD_ENABLED
- (void)testObjectsRetainedBySomeObjectWillBeFetched
{
NSObject *someObject = [NSObject new];
NSString *someString = @"someString";
NSObject *irrelevant = [NSObject new];
_RCDObjectWrapperTestClass *verifyObject = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *testObject = [[_RCDObjectWrapperTestClass alloc] initWithOtherObject:verifyObject];
testObject.someObject = someObject;
testObject.someString = someString;
testObject.irrelevantObject = irrelevant;
FBObjectiveCObject *object = [[FBObjectiveCObject alloc] initWithObject:testObject];
NSSet *retainedObjects = [object allRetainedObjects];
XCTAssertFalse([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:irrelevant]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someString]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:verifyObject]]);
}
- (void)testObjectsRetainedByArrayWillBeFetched
{
NSString *someString = @"someString";
NSObject *someObject = [NSObject new];
NSDictionary *someDictionary = [NSDictionary new];
NSArray *testedArray = @[someString, someObject, someDictionary];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:testedArray];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someString]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someDictionary]]);
}
- (void)testObjectsRetainedByDictionaryWillBeFetched
{
NSString *someString = @"someString";
NSObject *someObject = [NSObject new];
NSDictionary *someDictionary = @{someString:someObject};
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:someDictionary];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someString]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject]]);
}
- (void)testObjectsRetainedBySetWillBeFetched
{
NSString *someString = @"someString";
NSObject *someObject = [NSObject new];
NSSet *someSet = [NSSet setWithObjects:someString, someObject, nil];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:someSet];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someString]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject]]);
}
- (void)testThatIfObjectHasStrongPropertyWithNilThenItWontFetchIt
{
_RCDObjectWrapperTestClass *someObject = [_RCDObjectWrapperTestClass new];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:someObject];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 0);
}
- (void)testObjectThatSubclassesFromObjectWithStrongPropertiesWillFetchPropertiesFromParentClass
{
_RCDObjectWrapperTestClassSubclass *testObject = [_RCDObjectWrapperTestClassSubclass new];
NSObject *someObject = [NSObject new];
NSObject *irrelevantObject = [NSObject new];
NSString *someString = @"someString";
testObject.someObject = someObject;
testObject.irrelevantObject = irrelevantObject;
testObject.someString = someString;
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:testObject];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someString]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject]]);
XCTAssertFalse([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:irrelevantObject]]);
}
- (void)testObjectRetainingClassConformingToFastEnumerationWillNotCrash
{
_RCDObjectWrapperTestClass *someObject = [_RCDObjectWrapperTestClass new];
someObject.aCls = [NSArray class];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:someObject];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:[NSArray class]]]);
}
- (void)testHashTableWithWeakObjectsWillNotFetchThoseObjects
{
NSHashTable *hashTable = [NSHashTable weakObjectsHashTable];
_RCDObjectWrapperTestClass *someObject1 = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *someObject2 = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *someObject3 = [_RCDObjectWrapperTestClass new];
[hashTable addObject:someObject1];
[hashTable addObject:someObject2];
[hashTable addObject:someObject3];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:hashTable];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 0);
}
- (void)testHashTableWithStrongObjectsWillFetchThoseObjects
{
NSHashTable *hashTable = [NSHashTable new];
_RCDObjectWrapperTestClass *someObject1 = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *someObject2 = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *someObject3 = [_RCDObjectWrapperTestClass new];
[hashTable addObject:someObject1];
[hashTable addObject:someObject2];
[hashTable addObject:someObject3];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:hashTable];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject1]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject2]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:someObject3]]);
}
- (void)testMapTableWithWeakKeysAndValueWillNotFetchAnything
{
NSMapTable *mapTable = [NSMapTable weakToWeakObjectsMapTable];
_RCDObjectWrapperTestClass *keyObject = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *valueObject = [_RCDObjectWrapperTestClass new];
[mapTable setObject:valueObject forKey:keyObject];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:mapTable];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 0);
}
- (void)testMapTableWithWeakKeysAndStrongValuesWillFetchOnlyValues
{
NSMapTable *mapTable = [NSMapTable weakToStrongObjectsMapTable];
_RCDObjectWrapperTestClass *keyObject = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *valueObject = [_RCDObjectWrapperTestClass new];
[mapTable setObject:valueObject forKey:keyObject];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:mapTable];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 1);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:valueObject]]);
}
- (void)testMapTableWithStrongKeysAndWeakValuesWillFetchOnlyKeys
{
NSMapTable *mapTable = [NSMapTable strongToWeakObjectsMapTable];
_RCDObjectWrapperTestClass *keyObject = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *valueObject = [_RCDObjectWrapperTestClass new];
[mapTable setObject:valueObject forKey:keyObject];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:mapTable];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 1);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:keyObject]]);
}
- (void)testMapTableWithStrongKeysAndStrongValuesWillFetchBothKeysAndValues
{
NSMapTable *mapTable = [NSMapTable strongToStrongObjectsMapTable];
_RCDObjectWrapperTestClass *keyObject = [_RCDObjectWrapperTestClass new];
_RCDObjectWrapperTestClass *valueObject = [_RCDObjectWrapperTestClass new];
[mapTable setObject:valueObject forKey:keyObject];
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:mapTable];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 2);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:keyObject]]);
XCTAssertTrue([retainedObjects containsObject:[[FBObjectiveCObject alloc] initWithObject:valueObject]]);
}
- (void)testTollFreeBridgedDictionaryWillNotCrash
{
CFDictionaryValueCallBacks cb = kCFTypeDictionaryValueCallBacks;
cb.retain = NULL;
cb.release = NULL;
NSMutableDictionary *dictionary = (__bridge_transfer id)CFDictionaryCreateMutable(NULL, 0, NULL, &cb);
NSInteger intV = 5;
CFDictionarySetValue((CFMutableDictionaryRef)dictionary, (__bridge const void *)@"key", (const void *)intV);
FBObjectiveCObject *abstractedObject = [[FBObjectiveCObject alloc] initWithObject:dictionary];
NSSet *retainedObjects = [abstractedObject allRetainedObjects];
XCTAssertEqual([retainedObjects count], 0);
}
#endif //_INTERNAL_RCD_ENABLED
@end