FIRObjectSwizzlerTest.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2017 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import <XCTest/XCTest.h>
  15. #import "FirebaseCommunity/FIRObjectSwizzler.h"
  16. #import "FirebaseCommunity/FIRSwizzledObject.h"
  17. @interface FIRObjectSwizzlerTest : XCTestCase
  18. @end
  19. @implementation FIRObjectSwizzlerTest
  20. /** Exists just as a donor method. */
  21. - (void)donorMethod {
  22. }
  23. - (void)testRetainedAssociatedObjects {
  24. NSObject *object = [[NSObject alloc] init];
  25. NSObject *associatedObject = [[NSObject alloc] init];
  26. size_t addressOfAssociatedObject = (size_t)&associatedObject;
  27. [FIRObjectSwizzler setAssociatedObject:object
  28. key:@"test"
  29. value:associatedObject
  30. association:FIR_ASSOCIATION_RETAIN];
  31. associatedObject = nil;
  32. associatedObject = [FIRObjectSwizzler getAssociatedObject:object key:@"test"];
  33. XCTAssertEqual((size_t)&associatedObject, addressOfAssociatedObject);
  34. XCTAssertNotNil(associatedObject);
  35. }
  36. /** Tests that creating an object swizzler works. */
  37. - (void)testObjectSwizzlerInit {
  38. NSObject *object = [[NSObject alloc] init];
  39. FIRObjectSwizzler *objectSwizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  40. XCTAssertNotNil(objectSwizzler);
  41. }
  42. /** Tests that you're able to swizzle an object. */
  43. - (void)testSwizzle {
  44. NSObject *object = [[NSObject alloc] init];
  45. FIRObjectSwizzler *objectSwizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  46. XCTAssertEqual([object class], [NSObject class]);
  47. [objectSwizzler swizzle];
  48. XCTAssertNotEqual([object class], [NSObject class]);
  49. XCTAssertTrue([[object class] isSubclassOfClass:[NSObject class]]);
  50. XCTAssertTrue([object respondsToSelector:@selector(fpr_class)]);
  51. }
  52. /** Tests that swizzling a nil object fails. */
  53. - (void)testSwizzleNil {
  54. NSObject *object = [[NSObject alloc] init];
  55. FIRObjectSwizzler *objectSwizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  56. XCTAssertEqual([object class], [NSObject class]);
  57. object = nil;
  58. XCTAssertThrows([objectSwizzler swizzle]);
  59. }
  60. /** Tests the ability to copy a selector from one class to the swizzled object's generated class. */
  61. - (void)testCopySelectorFromClassIsClassSelectorAndSwizzle {
  62. NSObject *object = [[NSObject alloc] init];
  63. FIRObjectSwizzler *objectSwizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  64. [objectSwizzler copySelector:@selector(donorMethod) fromClass:[self class] isClassSelector:NO];
  65. XCTAssertFalse([object respondsToSelector:@selector(donorMethod)]);
  66. XCTAssertFalse([[object class] instancesRespondToSelector:@selector(donorMethod)]);
  67. [objectSwizzler swizzle];
  68. XCTAssertTrue([object respondsToSelector:@selector(donorMethod)]);
  69. // [object class] should return the original class, not the swizzled class.
  70. XCTAssertTrue(
  71. [[(FIRSwizzledObject *)object fpr_class] instancesRespondToSelector:@selector(donorMethod)]);
  72. }
  73. /** Tests that some helper methods are always added to swizzled objects. */
  74. - (void)testCommonSelectorsAddedUponSwizzling {
  75. NSObject *object = [[NSObject alloc] init];
  76. FIRObjectSwizzler *objectSwizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  77. XCTAssertFalse([object respondsToSelector:@selector(fpr_class)]);
  78. [objectSwizzler swizzle];
  79. XCTAssertTrue([object respondsToSelector:@selector(fpr_class)]);
  80. }
  81. /** Tests that there's no retain cycle and that -dealloc causes unswizzling. */
  82. - (void)testRetainCycleDoesntExistAndDeallocCausesUnswizzling {
  83. NSObject *object = [[NSObject alloc] init];
  84. FIRObjectSwizzler *objectSwizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  85. [objectSwizzler copySelector:@selector(donorMethod) fromClass:[self class] isClassSelector:NO];
  86. [objectSwizzler swizzle];
  87. // If objectSwizzler were used, the strong reference would make it live to the end of this test.
  88. // We want to make sure it dies when the object dies, hence the weak reference.
  89. __weak FIRObjectSwizzler *weakObjectSwizzler = objectSwizzler;
  90. objectSwizzler = nil;
  91. XCTAssertNotNil(weakObjectSwizzler);
  92. object = nil;
  93. XCTAssertNil(weakObjectSwizzler);
  94. }
  95. /** Tests the class get/set associated object methods. */
  96. - (void)testClassSetAssociatedObjectCopy {
  97. NSObject *object = [[NSObject alloc] init];
  98. NSDictionary *objectToBeAssociated = [[NSDictionary alloc] init];
  99. [FIRObjectSwizzler setAssociatedObject:object
  100. key:@"fpr_key"
  101. value:objectToBeAssociated
  102. association:FIR_ASSOCIATION_COPY];
  103. NSDictionary *returnedObject = [FIRObjectSwizzler getAssociatedObject:object key:@"fpr_key"];
  104. XCTAssertEqualObjects(returnedObject, objectToBeAssociated);
  105. }
  106. /** Tests the class get/set associated object methods. */
  107. - (void)testClassSetAssociatedObjectAssign {
  108. NSObject *object = [[NSObject alloc] init];
  109. NSDictionary *objectToBeAssociated = [[NSDictionary alloc] init];
  110. [FIRObjectSwizzler setAssociatedObject:object
  111. key:@"fpr_key"
  112. value:objectToBeAssociated
  113. association:FIR_ASSOCIATION_ASSIGN];
  114. NSDictionary *returnedObject = [FIRObjectSwizzler getAssociatedObject:object key:@"fpr_key"];
  115. XCTAssertEqualObjects(returnedObject, objectToBeAssociated);
  116. }
  117. /** Tests the class get/set associated object methods. */
  118. - (void)testClassSetAssociatedObjectRetain {
  119. NSObject *object = [[NSObject alloc] init];
  120. NSDictionary *objectToBeAssociated = [[NSDictionary alloc] init];
  121. [FIRObjectSwizzler setAssociatedObject:object
  122. key:@"fpr_key"
  123. value:objectToBeAssociated
  124. association:FIR_ASSOCIATION_RETAIN];
  125. NSDictionary *returnedObject = [FIRObjectSwizzler getAssociatedObject:object key:@"fpr_key"];
  126. XCTAssertEqualObjects(returnedObject, objectToBeAssociated);
  127. }
  128. /** Tests the class get/set associated object methods. */
  129. - (void)testClassSetAssociatedObjectCopyNonatomic {
  130. NSObject *object = [[NSObject alloc] init];
  131. NSDictionary *objectToBeAssociated = [[NSDictionary alloc] init];
  132. [FIRObjectSwizzler setAssociatedObject:object
  133. key:@"fpr_key"
  134. value:objectToBeAssociated
  135. association:FIR_ASSOCIATION_COPY_NONATOMIC];
  136. NSDictionary *returnedObject = [FIRObjectSwizzler getAssociatedObject:object key:@"fpr_key"];
  137. XCTAssertEqualObjects(returnedObject, objectToBeAssociated);
  138. }
  139. /** Tests the class get/set associated object methods. */
  140. - (void)testClassSetAssociatedObjectRetainNonatomic {
  141. NSObject *object = [[NSObject alloc] init];
  142. NSDictionary *objectToBeAssociated = [[NSDictionary alloc] init];
  143. [FIRObjectSwizzler setAssociatedObject:object
  144. key:@"fpr_key"
  145. value:objectToBeAssociated
  146. association:FIR_ASSOCIATION_RETAIN_NONATOMIC];
  147. NSDictionary *returnedObject = [FIRObjectSwizzler getAssociatedObject:object key:@"fpr_key"];
  148. XCTAssertEqualObjects(returnedObject, objectToBeAssociated);
  149. }
  150. /** Tests the swizzler get/set associated object methods. */
  151. - (void)testSetGetAssociatedObjectCopy {
  152. NSObject *object = [[NSObject alloc] init];
  153. NSDictionary *associatedObject = [[NSDictionary alloc] init];
  154. FIRObjectSwizzler *swizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  155. [swizzler setAssociatedObjectWithKey:@"key"
  156. value:associatedObject
  157. association:FIR_ASSOCIATION_COPY];
  158. NSDictionary *returnedObject = [swizzler getAssociatedObjectForKey:@"key"];
  159. XCTAssertEqualObjects(returnedObject, associatedObject);
  160. }
  161. /** Tests the swizzler get/set associated object methods. */
  162. - (void)testSetGetAssociatedObjectAssign {
  163. NSObject *object = [[NSObject alloc] init];
  164. NSDictionary *associatedObject = [[NSDictionary alloc] init];
  165. FIRObjectSwizzler *swizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  166. [swizzler setAssociatedObjectWithKey:@"key"
  167. value:associatedObject
  168. association:FIR_ASSOCIATION_ASSIGN];
  169. NSDictionary *returnedObject = [swizzler getAssociatedObjectForKey:@"key"];
  170. XCTAssertEqualObjects(returnedObject, associatedObject);
  171. }
  172. /** Tests the swizzler get/set associated object methods. */
  173. - (void)testSetGetAssociatedObjectRetain {
  174. NSObject *object = [[NSObject alloc] init];
  175. NSDictionary *associatedObject = [[NSDictionary alloc] init];
  176. FIRObjectSwizzler *swizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  177. [swizzler setAssociatedObjectWithKey:@"key"
  178. value:associatedObject
  179. association:FIR_ASSOCIATION_RETAIN];
  180. NSDictionary *returnedObject = [swizzler getAssociatedObjectForKey:@"key"];
  181. XCTAssertEqualObjects(returnedObject, associatedObject);
  182. }
  183. /** Tests the swizzler get/set associated object methods. */
  184. - (void)testSetGetAssociatedObjectCopyNonatomic {
  185. NSObject *object = [[NSObject alloc] init];
  186. NSDictionary *associatedObject = [[NSDictionary alloc] init];
  187. FIRObjectSwizzler *swizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  188. [swizzler setAssociatedObjectWithKey:@"key"
  189. value:associatedObject
  190. association:FIR_ASSOCIATION_COPY_NONATOMIC];
  191. NSDictionary *returnedObject = [swizzler getAssociatedObjectForKey:@"key"];
  192. XCTAssertEqualObjects(returnedObject, associatedObject);
  193. }
  194. /** Tests the swizzler get/set associated object methods. */
  195. - (void)testSetGetAssociatedObjectRetainNonatomic {
  196. NSObject *object = [[NSObject alloc] init];
  197. NSDictionary *associatedObject = [[NSDictionary alloc] init];
  198. FIRObjectSwizzler *swizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  199. [swizzler setAssociatedObjectWithKey:@"key"
  200. value:associatedObject
  201. association:FIR_ASSOCIATION_RETAIN_NONATOMIC];
  202. NSDictionary *returnedObject = [swizzler getAssociatedObjectForKey:@"key"];
  203. XCTAssertEqualObjects(returnedObject, associatedObject);
  204. }
  205. - (void)testSetGetAssociatedObjectWithoutProperAssociation {
  206. NSObject *object = [[NSObject alloc] init];
  207. NSDictionary *associatedObject = [[NSDictionary alloc] init];
  208. FIRObjectSwizzler *swizzler = [[FIRObjectSwizzler alloc] initWithObject:object];
  209. [swizzler setAssociatedObjectWithKey:@"key" value:associatedObject association:1337];
  210. NSDictionary *returnedObject = [swizzler getAssociatedObjectForKey:@"key"];
  211. XCTAssertEqualObjects(returnedObject, associatedObject);
  212. }
  213. @end