Skip to content

Instantly share code, notes, and snippets.

@amleszk
Created November 12, 2013 14:24
Show Gist options
  • Save amleszk/7431624 to your computer and use it in GitHub Desktop.
Save amleszk/7431624 to your computer and use it in GitHub Desktop.
#import <XCTest/XCTest.h>
typedef id (^OperationToExchangeForClass)(void);
@interface RCTestCase : XCTestCase
- (void) exchangeClassMethodForClass:(Class)clazz selector:(SEL)selector operation:(OperationToExchangeForClass)operation;
@property (nonatomic) NSBundle *unitTestBundle;
@end
#import "RCTestCase.h"
#import <objc/runtime.h>
static NSMutableArray *classMethodExchanges;
static NSMutableArray *classMethodBlocks;
@implementation RCTestCase
-(void) setUp
{
_unitTestBundle = [NSBundle bundleForClass:[self class]];
}
-(void) tearDown
{
[super tearDown];
[self restoreSwizzles];
}
- (void) exchangeClassMethodForClass:(Class)clazz selector:(SEL)selector operation:(OperationToExchangeForClass)operation
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
classMethodExchanges = [NSMutableArray array];
classMethodBlocks = [NSMutableArray array];
});
NSAssert(classMethodExchanges.count<=1, @"");
NSAssert(classMethodBlocks.count<=1, @"");
Method originalClassMethod = class_getClassMethod(clazz, selector);
NSAssert(originalClassMethod, @"Method not found");
Method mockMethod = class_getInstanceMethod([self class], @selector(classMethodExchangeCallBlock));
NSAssert(mockMethod, @"Method not found");
//Swizzle
method_exchangeImplementations(originalClassMethod, mockMethod);
//Store for de-swizzle
{
NSValue *originalClassMethodValue = [NSValue valueWithBytes:&originalClassMethod objCType:@encode(Method)];
NSValue *mockMethodValue = [NSValue valueWithBytes:&mockMethod objCType:@encode(Method)];
[classMethodExchanges addObject:@[originalClassMethodValue,mockMethodValue]];
}
//Store callback
[classMethodBlocks addObject:operation];
}
- (void) restoreSwizzles
{
for (NSArray *exchanges in classMethodExchanges) {
NSValue *originalClassMethodValue = exchanges[0];
NSValue *mockMethodValue = exchanges[1];
Method originalClassMethod;
Method mockMethod;
[originalClassMethodValue getValue:&originalClassMethod];
[mockMethodValue getValue:&mockMethod];
method_exchangeImplementations(mockMethod, originalClassMethod);
}
[classMethodExchanges removeAllObjects];
[classMethodBlocks removeAllObjects];
}
-(id) classMethodExchangeCallBlock
{
NSAssert(classMethodBlocks.count == 1, @"");
OperationToExchangeForClass op = (OperationToExchangeForClass)classMethodBlocks[0];
return op();
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment