| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799 |
- // Copyright 2018 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #import <XCTest/XCTest.h>
- #import <objc/runtime.h>
- #import <GoogleUtilities/GULOriginalIMPConvenienceMacros.h>
- #import <GoogleUtilities/GULSwizzler+Unswizzle.h>
- #import <GoogleUtilities/GULSwizzler.h>
- @interface TestObject : NSObject
- @end
- @implementation TestObject
- + (NSString *)description {
- return [[super description] stringByAppendingString:@" and here's my addition: BLAH BLAH"];
- }
- // This method is used to help test swizzling a method that calls super.
- - (NSString *)description {
- return [NSString stringWithFormat:@"TestObject, superclass: %@", [super description]];
- }
- /** This method is used to test invoking an original instance IMP with one argument.
- * @return A description string.
- */
- - (NSString *)descriptionThatSays:(NSString *)something {
- return [@"instance:" stringByAppendingString:something];
- }
- /** This method is used to test invoking an original class IMP with one argument.
- * @return A description string.
- */
- + (NSString *)descriptionThatSays:(NSString *)something {
- return [@"class:" stringByAppendingString:something];
- }
- @end
- @interface TestObjectSubclass : TestObject
- @end
- @implementation TestObjectSubclass
- @end
- @interface GULSwizzlerTest : XCTestCase
- @end
- @implementation GULSwizzlerTest
- /** Tests originalImplementationForClass:selector:isClassSelector: returns the original instance
- * IMP.
- */
- - (void)testOriginalImpInstanceMethod {
- Method method = class_getInstanceMethod([NSObject class], @selector(description));
- IMP originalImp = method_getImplementation(method);
- NSString * (^newImplementation)(void) = ^NSString *() {
- return @"nonsense";
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- IMP returnedImp = [GULSwizzler originalImplementationForClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO];
- XCTAssertEqual(returnedImp, originalImp);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:NO];
- }
- /** Tests currentImplementationForClass:selector:isClassSelector: returns different IMPs for class
- * and instance methods.
- */
- - (void)testCurrentImplementationReturnsDifferentIMPsForClassAndInstanceMethod {
- Class aClass = [NSObject class];
- SEL aSelector = @selector(description);
- IMP descriptionClassIMP = [GULSwizzler currentImplementationForClass:aClass
- selector:aSelector
- isClassSelector:NO];
- IMP descriptionInstanceIMP = [GULSwizzler currentImplementationForClass:aClass
- selector:aSelector
- isClassSelector:YES];
- XCTAssertNotEqual(descriptionClassIMP, descriptionInstanceIMP);
- }
- /** Tests currentImplementationForClass:selector:isClassSelector: returns the same IMP twice when it
- * hasn't been swizzled.
- */
- - (void)testCurrentImplementationReturnsSameIMPsWhenNotSwizzledBetweenInvocations {
- Class aClass = [NSObject class];
- SEL aSelector = @selector(description);
- IMP descriptionClassIMPOne = [GULSwizzler currentImplementationForClass:aClass
- selector:aSelector
- isClassSelector:NO];
- IMP descriptionClassIMPTwo = [GULSwizzler currentImplementationForClass:aClass
- selector:aSelector
- isClassSelector:NO];
- XCTAssertEqual(descriptionClassIMPOne, descriptionClassIMPTwo);
- }
- /** Tests currentImplementationForClass:selector:isClassSelector: returns a different IMP when it
- * has been swizzled.
- */
- - (void)testCurrentImplementationReturnsDifferentIMPsWhenSwizzledBetweenInvocations {
- Class aClass = [NSObject class];
- SEL aSelector = @selector(description);
- IMP originalIMP = [GULSwizzler currentImplementationForClass:aClass
- selector:aSelector
- isClassSelector:NO];
- NSString * (^newImplementation)(id) = ^NSString *(id _self) {
- return @"nonsense";
- };
- [GULSwizzler swizzleClass:aClass
- selector:aSelector
- isClassSelector:NO
- withBlock:newImplementation];
- IMP newIMP = [GULSwizzler currentImplementationForClass:aClass
- selector:aSelector
- isClassSelector:NO];
- XCTAssertNotEqual(newIMP, originalIMP);
- [GULSwizzler unswizzleClass:aClass selector:aSelector isClassSelector:NO];
- }
- /** Tests that invoking an original IMP in a swizzled IMP calls through correctly. */
- - (void)testOriginalImpCallThrough {
- SEL selector = @selector(description);
- Class aClass = [NSObject class];
- id newDescription = ^NSString *(id object) {
- IMP originalImp = [GULSwizzler originalImplementationForClass:aClass
- selector:selector
- isClassSelector:NO];
- NSString *originalDescription =
- GUL_INVOKE_ORIGINAL_IMP0(object, selector, NSString *, originalImp);
- return [originalDescription stringByAppendingString:@"SWIZZLED!"];
- };
- [GULSwizzler swizzleClass:aClass selector:selector isClassSelector:NO withBlock:newDescription];
- NSString *result = [[[NSObject alloc] init] description];
- XCTAssertGreaterThan([result rangeOfString:@"SWIZZLED!"].location, 0);
- [GULSwizzler unswizzleClass:aClass selector:selector isClassSelector:NO];
- }
- /** Tests originalImplementationForClass:selector:isClassSelector: returns the original class IMP.
- */
- - (void)testOriginalImpClassMethod {
- Method method = class_getInstanceMethod([NSObject class], @selector(description));
- IMP originalImp = method_getImplementation(method);
- NSString * (^newImplementation)(void) = ^NSString *() {
- return @"nonsense";
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- IMP returnedImp = [GULSwizzler originalImplementationForClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO];
- XCTAssertEqual(returnedImp, originalImp);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:NO];
- }
- /** Tests originalImplementationForClass:selector:isClassSelector: returns different IMPs for
- * instance methods and class methods of the same name (like -/+ description).
- */
- - (void)testOriginalImpInstanceAndClassImpsAreDifferent {
- Method instanceMethod = class_getInstanceMethod([NSObject class], @selector(description));
- Method classMethod = class_getClassMethod([NSObject class], @selector(description));
- IMP instanceImp = method_getImplementation(instanceMethod);
- IMP classImp = method_getImplementation(classMethod);
- NSString * (^newImplementation)(void) = ^NSString *() {
- return @"nonsense";
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertNotEqual(instanceMethod, classMethod);
- IMP returnedInstanceImp = [GULSwizzler originalImplementationForClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO];
- IMP returnedClassImp = [GULSwizzler originalImplementationForClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:YES];
- XCTAssertNotEqual(instanceImp, classImp);
- XCTAssertNotEqual(returnedInstanceImp, returnedClassImp);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:NO];
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:YES];
- }
- /** Tests swizzling an instance method. */
- - (void)testSwizzleInstanceMethod {
- NSString *swizzledDescription = @"Not what you expected!";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- NSString *returnedDescription = [[[NSObject alloc] init] description];
- XCTAssertEqualObjects(returnedDescription, swizzledDescription);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:NO];
- }
- /** Tests swizzling a class method. */
- - (void)testSwizzleClassMethod {
- NSString *swizzledDescription = @"Swizzled class description";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([NSObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:YES];
- }
- /** Tests unswizzling an instance method. */
- - (void)testUnswizzleInstanceMethod {
- NSObject *object = [[NSObject alloc] init];
- NSString *originalDescription = [object description];
- NSString *swizzledDescription = @"Swizzled description";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- NSString *returnedDescription = [object description];
- XCTAssertEqualObjects(returnedDescription, swizzledDescription);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:NO];
- returnedDescription = [object description];
- XCTAssertEqualObjects(returnedDescription, originalDescription);
- }
- /** Tests unswizzling a class method. */
- - (void)testUnswizzleClassMethod {
- NSString *originalDescription = [NSObject description];
- NSString *swizzledDescription = @"Swizzled class description";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([NSObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:YES];
- XCTAssertEqualObjects([NSObject description], originalDescription);
- }
- /** Tests swizzling a class method doesn't swizzle an instance method of the same name. */
- - (void)testSwizzlingAClassMethodDoesntSwizzleAnInstanceMethod {
- NSString *swizzledDescription = @"Swizzled class description";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([NSObject description], swizzledDescription);
- XCTAssertNotEqualObjects([[[NSObject alloc] init] description], swizzledDescription);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:YES];
- }
- /** Tests swizzling an instance method doesn't swizzle a class method of the same name. */
- - (void)testSwizzlingAnInstanceMethodDoesntSwizzleAClassMethod {
- NSString *swizzledDescription = @"Not what you expected!";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[NSObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- NSString *returnedDescription = [[[NSObject alloc] init] description];
- XCTAssertEqual(returnedDescription, swizzledDescription);
- XCTAssertNotEqualObjects([NSObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[NSObject class] selector:@selector(description) isClassSelector:NO];
- }
- /** Tests swizzling a superclass's instance method. */
- - (void)testSwizzlingSuperclassInstanceMethod {
- NSObject *generalObject = [[NSObject alloc] init];
- BOOL generalObjectIsProxyValue = [generalObject isProxy];
- BOOL (^newImplementation)(void) = ^BOOL() {
- return !generalObjectIsProxyValue;
- };
- [GULSwizzler swizzleClass:[TestObject class]
- selector:@selector(isProxy)
- isClassSelector:NO
- withBlock:newImplementation];
- XCTAssertNotEqual([[[TestObject alloc] init] isProxy], generalObjectIsProxyValue);
- [GULSwizzler unswizzleClass:[TestObject class] selector:@selector(isProxy) isClassSelector:NO];
- }
- /** Tests swizzling a superclass's class method. */
- - (void)testSwizzlingSuperclassClassMethod {
- NSString *swizzledDescription = @"Swizzled class description";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([TestObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:YES];
- }
- /** Tests swizzling an instance method that calls into the superclass implementation. */
- - (void)testSwizzlingInstanceMethodThatCallsSuper {
- TestObject *testObject = [[TestObject alloc] init];
- NSString *originalDescription = [testObject description];
- NSString *swizzledDescription = [originalDescription stringByAppendingString:@"SWIZZLED!"];
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:NO
- withBlock:newImplementation];
- XCTAssertEqualObjects([testObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:NO];
- XCTAssertEqualObjects([testObject description], originalDescription);
- }
- /** Tests swizzling a method and getting the original IMP of that method. */
- - (void)testSwizzleAndGet {
- Class testClass = [NSURL class];
- SEL testSelector = @selector(description);
- IMP baseImp = class_getMethodImplementation(testClass, testSelector);
- [GULSwizzler swizzleClass:testClass
- selector:testSelector
- isClassSelector:NO
- withBlock:^{
- return @"Swizzled Description";
- }];
- IMP origImp = [GULSwizzler originalImplementationForClass:testClass
- selector:testSelector
- isClassSelector:NO];
- XCTAssertEqual(origImp, baseImp, @"Original IMP and base IMP are not equal.");
- [GULSwizzler unswizzleClass:testClass selector:testSelector isClassSelector:NO];
- }
- /** Tests swizzling more than a single method at a time. */
- - (void)testSwizzleMultiple {
- Class testClass = [NSURL class];
- SEL testSelector = @selector(description);
- [GULSwizzler swizzleClass:testClass
- selector:testSelector
- isClassSelector:NO
- withBlock:^{
- return @"Swizzled Description";
- }];
- IMP origImp = [GULSwizzler originalImplementationForClass:testClass
- selector:testSelector
- isClassSelector:NO];
- Class testClass2 = [NSURLRequest class];
- SEL testSelector2 = @selector(debugDescription);
- [GULSwizzler swizzleClass:testClass2
- selector:testSelector2
- isClassSelector:NO
- withBlock:^{
- return @"Swizzled Debug Description";
- }];
- IMP origImp2 = [GULSwizzler originalImplementationForClass:testClass2
- selector:testSelector2
- isClassSelector:NO];
- XCTAssertNotEqual(origImp2, NULL, @"Original IMP is NULL after swizzle.");
- XCTAssertNotEqual(origImp, origImp2, @"Implementations are the same when they should't be.");
- [GULSwizzler unswizzleClass:testClass selector:testSelector isClassSelector:NO];
- [GULSwizzler unswizzleClass:testClass2 selector:testSelector2 isClassSelector:NO];
- }
- /** Tests swizzling multiple instance methods on the same class at the same time */
- - (void)testSwizzleMultipleInstanceMethodsOnSameClass {
- Class testClass = [TestObject class];
- SEL selectorOne = @selector(description);
- SEL selectorTwo = @selector(descriptionThatSays:);
- NSString * (^newImplementationDescription)(id, SEL) = ^NSString *(id _self, SEL cmd) {
- return @"SWIZZLED!";
- };
- NSString * (^newImplementationDescriptionThatSays)(TestObject *, NSString *) =
- ^NSString *(TestObject *_self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- [GULSwizzler swizzleClass:testClass
- selector:selectorOne
- isClassSelector:NO
- withBlock:newImplementationDescription];
- [GULSwizzler swizzleClass:testClass
- selector:selectorTwo
- isClassSelector:NO
- withBlock:newImplementationDescriptionThatSays];
- TestObject *sampleObject = [[TestObject alloc] init];
- XCTAssertEqualObjects([sampleObject description], @"SWIZZLED!");
- XCTAssertEqualObjects([sampleObject descriptionThatSays:@"Name"], @"NameSWIZZLED!");
- [GULSwizzler unswizzleClass:testClass selector:selectorOne isClassSelector:NO];
- [GULSwizzler unswizzleClass:testClass selector:selectorTwo isClassSelector:NO];
- }
- /** Tests swizzling multiple class methods on the same class at the same time */
- - (void)testSwizzleMultipleClassMethodsOnSameClass {
- Class testClass = [TestObject class];
- SEL selectorOne = @selector(description);
- SEL selectorTwo = @selector(descriptionThatSays:);
- NSString * (^newImplementationDescription)(id, SEL) = ^NSString *(id _self, SEL cmd) {
- return @"SWIZZLED!";
- };
- NSString * (^newImplementationDescriptionThatSays)(TestObject *, NSString *) =
- ^NSString *(TestObject *_self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- [GULSwizzler swizzleClass:testClass
- selector:selectorOne
- isClassSelector:YES
- withBlock:newImplementationDescription];
- [GULSwizzler swizzleClass:testClass
- selector:selectorTwo
- isClassSelector:YES
- withBlock:newImplementationDescriptionThatSays];
- XCTAssertEqualObjects([TestObject description], @"SWIZZLED!");
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"Name"], @"NameSWIZZLED!");
- [GULSwizzler unswizzleClass:testClass selector:selectorOne isClassSelector:YES];
- [GULSwizzler unswizzleClass:testClass selector:selectorTwo isClassSelector:YES];
- }
- /** Tests swizzling an instance method is correctly swizzled on multiple instances of the same
- * class.
- */
- - (void)testSwizzlingInstanceMethodIsEffectiveOnMultipleInstancesOfSameClass {
- Class testClass = [TestObject class];
- SEL selector = @selector(description);
- NSString * (^newImplementationDescription)(id, SEL) = ^NSString *(id _self, SEL cmd) {
- return @"SWIZZLED!";
- };
- [GULSwizzler swizzleClass:testClass
- selector:selector
- isClassSelector:NO
- withBlock:newImplementationDescription];
- TestObject *sampleObjectOne = [[TestObject alloc] init];
- TestObject *sampleObjectTwo = [[TestObject alloc] init];
- XCTAssertEqualObjects([sampleObjectOne description], @"SWIZZLED!");
- XCTAssertEqualObjects([sampleObjectTwo description], @"SWIZZLED!");
- [GULSwizzler unswizzleClass:testClass selector:selector isClassSelector:NO];
- }
- /** Tests swizzling a class method that calls into the superclass implementation. */
- - (void)testSwizzlingClassMethodThatCallsSuper {
- NSString *originalDescription = [TestObject description];
- NSString *swizzledDescription = @"Swizzled class description";
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([TestObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:YES];
- XCTAssertEqualObjects([TestObject description], originalDescription);
- }
- /** Tests swizzling an inherited instance method doesn't change the implementation of the
- * superclass's implementation of that same method.
- */
- - (void)testSwizzlingAnInheritedInstanceMethodDoesntAffectTheIMPOfItsSuperclass {
- NSObject *generalObject = [[NSObject alloc] init];
- BOOL originalGeneralObjectValue = [generalObject isProxy];
- BOOL (^newImplementation)(void) = ^BOOL(void) {
- return !originalGeneralObjectValue;
- };
- [GULSwizzler swizzleClass:[TestObject class]
- selector:@selector(isProxy)
- isClassSelector:NO
- withBlock:newImplementation];
- XCTAssertEqual([generalObject isProxy], originalGeneralObjectValue);
- XCTAssertNotEqual([[[TestObject alloc] init] isProxy], originalGeneralObjectValue);
- [GULSwizzler unswizzleClass:[TestObject class] selector:@selector(isProxy) isClassSelector:NO];
- XCTAssertEqual([[[TestObject alloc] init] isProxy], originalGeneralObjectValue);
- }
- /** Tests swizzling an inherited instance method from a superclass a couple of links up in the
- * chain of superclasses doesn't affect the implementation of the superclass's method.
- */
- - (void)testSwizzlingADeeperInheritedInstanceMethodDoesntAffectTheIMPOfItsSuperclass {
- TestObject *testObject = [[TestObject alloc] init];
- BOOL originalTestObjectValue = [testObject isProxy];
- BOOL (^newImplementation)(void) = ^BOOL(void) {
- return !originalTestObjectValue;
- };
- [GULSwizzler swizzleClass:[TestObjectSubclass class]
- selector:@selector(isProxy)
- isClassSelector:NO
- withBlock:newImplementation];
- XCTAssertEqual([testObject isProxy], originalTestObjectValue);
- XCTAssertNotEqual([[[TestObjectSubclass alloc] init] isProxy], originalTestObjectValue);
- [GULSwizzler unswizzleClass:[TestObjectSubclass class]
- selector:@selector(isProxy)
- isClassSelector:NO];
- XCTAssertEqual([[[TestObjectSubclass alloc] init] isProxy], originalTestObjectValue);
- }
- /** Tests swizzling an inherited class method doesn't change the implementation of the
- * superclass's implementation of that same method.
- */
- - (void)testSwizzlingAnInheritedClassMethodDoesntAffectTheIMPOfItsSuperclass {
- // Fun fact, this won't work on +new. Swizzling +new causes a retain to not be placed correctly.
- NSString *originalDescription = [TestObject description];
- NSString *swizzledDescription = [originalDescription stringByAppendingString:@"SWIZZLED!"];
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([TestObject description], swizzledDescription);
- XCTAssertNotEqualObjects([NSObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[TestObject class]
- selector:@selector(description)
- isClassSelector:YES];
- XCTAssertNotEqualObjects([TestObject description], swizzledDescription);
- XCTAssertNotEqualObjects([NSObject description], originalDescription);
- }
- /** Tests swizzling an inherited class method from a superclass a couple of links up in the
- * chain of superclasses doesn't affect the implementation of the superclass's method.
- */
- - (void)testSwizzlingADeeperInheritedClassMethodDoesntAffectTheIMPOfItsSuperclass {
- NSString *originalDescription = [TestObjectSubclass description];
- NSString *swizzledDescription = [originalDescription stringByAppendingString:@"SWIZZLED!"];
- NSString * (^newImplementation)(void) = ^NSString *() {
- return swizzledDescription;
- };
- [GULSwizzler swizzleClass:[TestObjectSubclass class]
- selector:@selector(description)
- isClassSelector:YES
- withBlock:newImplementation];
- XCTAssertEqualObjects([TestObjectSubclass description], swizzledDescription);
- XCTAssertNotEqualObjects([TestObject description], swizzledDescription);
- XCTAssertNotEqualObjects([NSObject description], swizzledDescription);
- [GULSwizzler unswizzleClass:[TestObjectSubclass class]
- selector:@selector(description)
- isClassSelector:YES];
- XCTAssertNotEqualObjects([TestObjectSubclass description], swizzledDescription);
- XCTAssertNotEqualObjects([TestObject description], originalDescription);
- XCTAssertNotEqualObjects([NSObject description], originalDescription);
- }
- /** Tests invoking an original instance IMP that takes one argument. */
- - (void)testInvokingOriginalInstanceIMPWithOneArgument {
- TestObject *testObject = [[TestObject alloc] init];
- NSString * (^replacingBlock)(TestObject *, NSString *) =
- ^NSString *(TestObject *_self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- SEL swizzledSelector = @selector(descriptionThatSays:);
- [GULSwizzler swizzleClass:[TestObject class]
- selector:swizzledSelector
- isClassSelector:NO
- withBlock:replacingBlock];
- XCTAssertEqualObjects([testObject descriptionThatSays:@"something"], @"somethingSWIZZLED!");
- IMP originalIMP = [GULSwizzler originalImplementationForClass:[TestObject class]
- selector:swizzledSelector
- isClassSelector:NO];
- NSString *originalDescriptionThatSaysSomething =
- GUL_INVOKE_ORIGINAL_IMP1(testObject, swizzledSelector, NSString *, originalIMP, @"something");
- XCTAssertEqualObjects(originalDescriptionThatSaysSomething, @"instance:something");
- [GULSwizzler unswizzleClass:[TestObject class] selector:swizzledSelector isClassSelector:NO];
- }
- /** Tests invoking an original class IMP that takes one argument. */
- - (void)testInvokingOriginalClassIMPWithOneArgument {
- NSString * (^replacingBlock)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- SEL swizzledSelector = @selector(descriptionThatSays:);
- [GULSwizzler swizzleClass:[TestObject class]
- selector:swizzledSelector
- isClassSelector:YES
- withBlock:replacingBlock];
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"something"], @"somethingSWIZZLED!");
- IMP originalIMP = [GULSwizzler originalImplementationForClass:[TestObject class]
- selector:swizzledSelector
- isClassSelector:YES];
- NSString *originalDescriptionThatSaysSomething = GUL_INVOKE_ORIGINAL_IMP1(
- [TestObject class], swizzledSelector, NSString *, originalIMP, @"something");
- XCTAssertEqualObjects(originalDescriptionThatSaysSomething, @"class:something");
- [GULSwizzler unswizzleClass:[TestObject class] selector:swizzledSelector isClassSelector:YES];
- }
- /** Tests swizzling the same class SEL pair again works for class methods. */
- - (void)testSwizzlingSameClassSELPairOnClassMethodWorksCorrectly {
- NSString * (^replacingBlock1)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- NSString * (^replacingBlock2)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED2!"];
- };
- SEL swizzledSelector = @selector(descriptionThatSays:);
- Class swizzledClass = [TestObject class];
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:YES
- withBlock:replacingBlock1];
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"something"], @"somethingSWIZZLED!");
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:YES
- withBlock:replacingBlock2];
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"something"], @"somethingSWIZZLED2!");
- [GULSwizzler unswizzleClass:[TestObject class] selector:swizzledSelector isClassSelector:YES];
- }
- /** Tests swizzling the same class SEL pair again works for instance methods. */
- - (void)testSwizzlingSameClassSELPairOnInstanceMethodWorksCorrectly {
- NSString * (^replacingBlock1)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- NSString * (^replacingBlock2)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED2!"];
- };
- TestObject *testObject = [[TestObject alloc] init];
- SEL swizzledSelector = @selector(descriptionThatSays:);
- Class swizzledClass = [TestObject class];
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:NO
- withBlock:replacingBlock1];
- XCTAssertEqualObjects([testObject descriptionThatSays:@"something"], @"somethingSWIZZLED!");
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:NO
- withBlock:replacingBlock2];
- XCTAssertEqualObjects([testObject descriptionThatSays:@"something"], @"somethingSWIZZLED2!");
- [GULSwizzler unswizzleClass:[TestObject class] selector:swizzledSelector isClassSelector:NO];
- }
- /** Tests calling an IMP which was previously put in place by a consumer of GULSwizzler from inside
- * a new IMP that a consumer of GULSwizzler is putting in place of that old IMP works correctly
- * in case of instance methods.
- */
- - (void)testWrappingAPreviouslySwizzledClassSELPairWithANewOneWorksOnInstanceMethods {
- NSString * (^replacingBlock1)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- TestObject *testObject = [[TestObject alloc] init];
- SEL swizzledSelector = @selector(descriptionThatSays:);
- Class swizzledClass = [TestObject class];
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:NO
- withBlock:replacingBlock1];
- XCTAssertEqualObjects([testObject descriptionThatSays:@"something"], @"somethingSWIZZLED!");
- IMP previouslySwizzledIMP = [GULSwizzler currentImplementationForClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:NO];
- NSString * (^replacingBlock2)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- NSString *previousResult = GUL_INVOKE_ORIGINAL_IMP1(testObject, swizzledSelector, NSString *,
- previouslySwizzledIMP, something);
- NSString *currentResult = [something stringByAppendingString:@"SWIZZLED2!"];
- return [previousResult stringByAppendingString:currentResult];
- };
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:NO
- withBlock:replacingBlock2];
- XCTAssertEqualObjects([testObject descriptionThatSays:@"something"],
- @"somethingSWIZZLED!somethingSWIZZLED2!");
- XCTAssertEqualObjects([testObject descriptionThatSays:@"anything"],
- @"anythingSWIZZLED!anythingSWIZZLED2!");
- [GULSwizzler unswizzleClass:[TestObject class] selector:swizzledSelector isClassSelector:NO];
- }
- /** Tests calling an IMP which was previously put in place by a consumer of GULSwizzler from inside
- * a new IMP that a consumer of GULSwizzler is putting in place of that old IMP works correctly
- * in case of class methods.
- */
- - (void)testWrappingAPreviouslySwizzledClassSELPairWithANewOneWorksOnClassMethods {
- NSString * (^replacingBlock1)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- return [something stringByAppendingString:@"SWIZZLED!"];
- };
- SEL swizzledSelector = @selector(descriptionThatSays:);
- Class swizzledClass = [TestObject class];
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:YES
- withBlock:replacingBlock1];
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"something"], @"somethingSWIZZLED!");
- IMP previouslySwizzledIMP = [GULSwizzler currentImplementationForClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:YES];
- NSString * (^replacingBlock2)(id, NSString *) = ^NSString *(id _self, NSString *something) {
- NSString *previousResult = GUL_INVOKE_ORIGINAL_IMP1(
- [TestObject class], swizzledSelector, NSString *, previouslySwizzledIMP, something);
- NSString *currentResult = [something stringByAppendingString:@"SWIZZLED2!"];
- return [previousResult stringByAppendingString:currentResult];
- };
- [GULSwizzler swizzleClass:swizzledClass
- selector:swizzledSelector
- isClassSelector:YES
- withBlock:replacingBlock2];
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"something"],
- @"somethingSWIZZLED!somethingSWIZZLED2!");
- XCTAssertEqualObjects([TestObject descriptionThatSays:@"anything"],
- @"anythingSWIZZLED!anythingSWIZZLED2!");
- [GULSwizzler unswizzleClass:[TestObject class] selector:swizzledSelector isClassSelector:YES];
- }
- @end
|