Permalink
Browse files

Re-add JRSwizzle as a fake submodule.

  • Loading branch information...
1 parent 7e74696 commit cc98db287d33156d5712c815870e6f61d9c1a2af @rentzsch committed Jul 21, 2011
@@ -0,0 +1,11 @@
+// Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
+// Some rights reserved: http://opensource.org/licenses/mit-license.php
+
+#import <Foundation/Foundation.h>
+
+@interface NSObject (JRSwizzle)
+
++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_;
++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_;
+
+@end
@@ -0,0 +1,118 @@
+// Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
+// Some rights reserved: http://opensource.org/licenses/mit-license.php
+
+#import "JRSwizzle.h"
+#import <objc/objc-class.h>
+
+#define SetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \
+ if (ERROR_VAR) { \
+ NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \
+ *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \
+ code:-1 \
+ userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \
+ }
+#define SetNSError(ERROR_VAR, FORMAT,...) SetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__)
+
+#if OBJC_API_VERSION >= 2
+#define GetClass(obj) object_getClass(obj)
+#else
+#define GetClass(obj) (obj ? obj->isa : Nil)
+#endif
+
+@implementation NSObject (JRSwizzle)
+
++ (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ {
+#if OBJC_API_VERSION >= 2
+ Method origMethod = class_getInstanceMethod(self, origSel_);
+ if (!origMethod) {
+ SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
+ return NO;
+ }
+
+ Method altMethod = class_getInstanceMethod(self, altSel_);
+ if (!altMethod) {
+ SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
+ return NO;
+ }
+
+ class_addMethod(self,
+ origSel_,
+ class_getMethodImplementation(self, origSel_),
+ method_getTypeEncoding(origMethod));
+ class_addMethod(self,
+ altSel_,
+ class_getMethodImplementation(self, altSel_),
+ method_getTypeEncoding(altMethod));
+
+ method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_));
+ return YES;
+#else
+ // Scan for non-inherited methods.
+ Method directOriginalMethod = NULL, directAlternateMethod = NULL;
+
+ void *iterator = NULL;
+ struct objc_method_list *mlist = class_nextMethodList(self, &iterator);
+ while (mlist) {
+ int method_index = 0;
+ for (; method_index < mlist->method_count; method_index++) {
+ if (mlist->method_list[method_index].method_name == origSel_) {
+ assert(!directOriginalMethod);
+ directOriginalMethod = &mlist->method_list[method_index];
+ }
+ if (mlist->method_list[method_index].method_name == altSel_) {
+ assert(!directAlternateMethod);
+ directAlternateMethod = &mlist->method_list[method_index];
+ }
+ }
+ mlist = class_nextMethodList(self, &iterator);
+ }
+
+ // If either method is inherited, copy it up to the target class to make it non-inherited.
+ if (!directOriginalMethod || !directAlternateMethod) {
+ Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL;
+ if (!directOriginalMethod) {
+ inheritedOriginalMethod = class_getInstanceMethod(self, origSel_);
+ if (!inheritedOriginalMethod) {
+ SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]);
+ return NO;
+ }
+ }
+ if (!directAlternateMethod) {
+ inheritedAlternateMethod = class_getInstanceMethod(self, altSel_);
+ if (!inheritedAlternateMethod) {
+ SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]);
+ return NO;
+ }
+ }
+
+ int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1;
+ struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1)));
+ hoisted_method_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind
+ hoisted_method_list->method_count = hoisted_method_count;
+ Method hoisted_method = hoisted_method_list->method_list;
+
+ if (!directOriginalMethod) {
+ bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method));
+ directOriginalMethod = hoisted_method++;
+ }
+ if (!directAlternateMethod) {
+ bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method));
+ directAlternateMethod = hoisted_method;
+ }
+ class_addMethods(self, hoisted_method_list);
+ }
+
+ // Swizzle.
+ IMP temp = directOriginalMethod->method_imp;
+ directOriginalMethod->method_imp = directAlternateMethod->method_imp;
+ directAlternateMethod->method_imp = temp;
+
+ return YES;
+#endif
+}
+
++ (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ {
+ return [GetClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_];
+}
+
+@end
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.10.3 Test</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.10.4 Test</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.10.5 32-bit Test</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.10.5 64-bit Test</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
@@ -0,0 +1,10 @@
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface AppleSwizzleTest : SenTestCase {
+
+}
+
+- (void)testAppleSwizzleOfDirectMethod;
+- (void)testAppleSwizzleOfInheritedMethod;
+
+@end
@@ -0,0 +1,129 @@
+#import "AppleSwizzleTest.h"
+#import <objc/runtime.h>
+
+BOOL aFooCalled, bFooCalled, bAltFooCalled;
+
+@interface A5 : NSObject {}
+- (void)foo5;
+@end
+@implementation A5
+- (void)foo5 {
+ aFooCalled = YES;
+}
+@end
+
+@interface B5 : A5 {}
+@end
+@implementation B5
+- (void)foo5 {
+ bFooCalled = YES;
+}
+@end
+
+@interface B5 (altFoo5)
+- (void)altFoo5;
+@end
+@implementation B5 (altFoo5)
+- (void)altFoo5 {
+ bAltFooCalled = YES;
+}
+@end
+
+@interface A6 : NSObject {}
+- (void)foo6;
+@end
+@implementation A6
+- (void)foo6 {
+ aFooCalled = YES;
+}
+@end
+
+@interface B6 : A6 {}
+@end
+@implementation B6
+@end
+
+@interface B6 (altFoo6)
+- (void)altFoo6;
+@end
+@implementation B6 (altFoo6)
+- (void)altFoo6 {
+ bAltFooCalled = YES;
+}
+@end
+
+@implementation AppleSwizzleTest
+
+- (void)testAppleSwizzleOfDirectMethod {
+ A5 *a = [[[A5 alloc] init] autorelease];
+ B5 *b = [[[B5 alloc] init] autorelease];
+
+ {
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [a foo5];
+ STAssertTrue(aFooCalled, nil);
+ STAssertFalse(bFooCalled, nil);
+ STAssertFalse(bAltFooCalled, nil);
+
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [b foo5];
+ STAssertFalse(aFooCalled, nil);
+ STAssertTrue(bFooCalled, nil);
+ STAssertFalse(bAltFooCalled, nil);
+ }
+
+ method_exchangeImplementations(class_getInstanceMethod([B5 class], @selector(foo5)),
+ class_getInstanceMethod([B5 class], @selector(altFoo5)));
+
+ {
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [a foo5];
+ STAssertTrue(aFooCalled, nil);
+ STAssertFalse(bFooCalled, nil);
+ STAssertFalse(bAltFooCalled, nil);
+
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [b foo5];
+ STAssertFalse(aFooCalled, nil);
+ STAssertFalse(bFooCalled, nil);
+ STAssertTrue(bAltFooCalled, nil);
+ }
+}
+
+- (void)testAppleSwizzleOfInheritedMethod {
+ A6 *a = [[[A6 alloc] init] autorelease];
+ B6 *b = [[[B6 alloc] init] autorelease];
+
+ {
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [a foo6];
+ STAssertTrue(aFooCalled, nil);
+ STAssertFalse(bFooCalled, nil);
+ STAssertFalse(bAltFooCalled, nil);
+
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [b foo6];
+ STAssertTrue(aFooCalled, nil);
+ STAssertFalse(bFooCalled, nil);
+ STAssertFalse(bAltFooCalled, nil);
+ }
+
+ method_exchangeImplementations(class_getInstanceMethod([B6 class], @selector(foo6)),
+ class_getInstanceMethod([B6 class], @selector(altFoo6)));
+
+ {
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [a foo6];
+ STAssertFalse(aFooCalled, nil); // KNOWN INCORRECT BEHAVIOR: [a foo6] resulted in calling B6(altFoo6)'s -altFoo6!
+ STAssertFalse(bFooCalled, nil);
+ STAssertTrue(bAltFooCalled, nil);
+
+ aFooCalled = bFooCalled = bAltFooCalled = NO;
+ [b foo6];
+ STAssertFalse(aFooCalled, nil);
+ STAssertFalse(bFooCalled, nil);
+ STAssertTrue(bAltFooCalled, nil);
+ }
+}
+
+@end
@@ -0,0 +1,10 @@
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface BallardSwizzleTest : SenTestCase {
+
+}
+
+- (void)testBallardSwizzleOfDirectMethod;
+- (void)testBallardSwizzleOfInheritedMethod;
+
+@end
Oops, something went wrong.

0 comments on commit cc98db2

Please sign in to comment.