/core/externals/google-toolbox-for-mac/Foundation/GTMObjC2RuntimeTest.m

http://macfuse.googlecode.com/ · Objective C · 445 lines · 292 code · 74 blank · 79 comment · 9 complexity · 30091c25119cec3818d3a293efba1a4a MD5 · raw file

  1. //
  2. // GTMObjC2RuntimeTest.m
  3. //
  4. // Copyright 2007-2008 Google Inc.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7. // use this file except in compliance with the License. You may obtain a copy
  8. // of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  14. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  15. // License for the specific language governing permissions and limitations under
  16. // the License.
  17. //
  18. #import "GTMObjC2Runtime.h"
  19. #import "GTMSenTestCase.h"
  20. #import "GTMSystemVersion.h"
  21. #import "GTMTypeCasting.h"
  22. #import <string.h>
  23. @protocol GTMObjC2Runtime_TestProtocol
  24. @end
  25. @protocol GTMObjC2Runtime_Test2Protocol
  26. AT_OPTIONAL
  27. - (NSString*)optional;
  28. AT_REQUIRED
  29. - (NSString*)required;
  30. AT_OPTIONAL
  31. + (NSString*)class_optional;
  32. AT_REQUIRED
  33. + (NSString*)class_required;
  34. @end
  35. @interface GTMObjC2RuntimeTest : GTMTestCase {
  36. Class cls_;
  37. }
  38. @end
  39. @interface GTMObjC2Runtime_TestClass : NSObject <GTMObjC2Runtime_TestProtocol>
  40. - (NSString*)kwyjibo;
  41. @end
  42. @interface GTMObjC2Runtime_TestClass (GMObjC2Runtime_TestClassCategory)
  43. - (NSString*)eatMyShorts;
  44. @end
  45. @implementation GTMObjC2Runtime_TestClass
  46. + (NSString*)dontHaveACow {
  47. return @"dontHaveACow";
  48. }
  49. - (NSString*)kwyjibo {
  50. return @"kwyjibo";
  51. }
  52. @end
  53. @implementation GTMObjC2Runtime_TestClass (GMObjC2Runtime_TestClassCategory)
  54. - (NSString*)eatMyShorts {
  55. return @"eatMyShorts";
  56. }
  57. + (NSString*)brokeHisBrain {
  58. return @"brokeHisBrain";
  59. }
  60. @end
  61. @interface GTMObjC2NotificationWatcher : NSObject
  62. - (void)startedTest:(NSNotification *)notification;
  63. @end
  64. @implementation GTMObjC2NotificationWatcher
  65. - (id)init {
  66. if ((self = [super init])) {
  67. NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
  68. // We release ourselves when we are notified.
  69. [self retain];
  70. [nc addObserver:self
  71. selector:@selector(startedTest:)
  72. name:SenTestSuiteDidStartNotification
  73. object:nil];
  74. }
  75. return self;
  76. }
  77. - (void)startedTest:(NSNotification *)notification {
  78. // Logs if we are testing on Tiger or Leopard runtime.
  79. SenTestSuiteRun *suiteRun = GTM_STATIC_CAST(SenTestSuiteRun,
  80. [notification object]);
  81. NSString *testName = [[suiteRun test] name];
  82. NSString *className = NSStringFromClass([GTMObjC2RuntimeTest class]);
  83. if ([testName isEqualToString:className]) {
  84. NSString *runtimeString;
  85. #ifndef OBJC2_UNAVAILABLE
  86. runtimeString = @"ObjC1";
  87. #else
  88. runtimeString = @"ObjC2";
  89. #endif
  90. NSLog(@"Running GTMObjC2RuntimeTests using %@ runtime.", runtimeString);
  91. NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
  92. [nc removeObserver:self];
  93. [self autorelease];
  94. }
  95. }
  96. @end
  97. @implementation GTMObjC2RuntimeTest
  98. + (void)initialize {
  99. // This allows us to track which runtime we are actually testing.
  100. [[[GTMObjC2NotificationWatcher alloc] init] autorelease];
  101. }
  102. - (void)setUp {
  103. cls_ = [[GTMObjC2Runtime_TestClass class] retain];
  104. }
  105. - (void)tearDown {
  106. [cls_ release];
  107. }
  108. - (void)test_object_getClass {
  109. // Nil Checks
  110. STAssertNil(object_getClass(nil), nil);
  111. // Standard use check
  112. GTMObjC2Runtime_TestClass *test = [[[cls_ alloc] init] autorelease];
  113. Class cls = object_getClass(test);
  114. STAssertEqualObjects(cls, cls_, nil);
  115. }
  116. - (void)test_class_getName {
  117. // Nil Checks
  118. const char *name = class_getName(nil);
  119. STAssertEqualCStrings(name, "nil", nil);
  120. // Standard use check
  121. STAssertEqualCStrings(class_getName(cls_), "GTMObjC2Runtime_TestClass", nil);
  122. }
  123. - (void)test_class_conformsToProtocol {
  124. // Nil Checks
  125. STAssertFalse(class_conformsToProtocol(cls_, @protocol(NSObject)), nil);
  126. STAssertFalse(class_conformsToProtocol(cls_, nil), nil);
  127. // The following two tests intentionally commented out as they fail on
  128. // Leopard with a crash, so we fail on Tiger intentionally as well.
  129. // STAssertFalse(class_conformsToProtocol(nil, @protocol(NSObject)), nil);
  130. // STAssertFalse(class_conformsToProtocol(nil, nil), nil);
  131. // Standard use check
  132. STAssertTrue(class_conformsToProtocol(cls_,
  133. @protocol(GTMObjC2Runtime_TestProtocol)),
  134. nil);
  135. }
  136. - (void)test_class_respondsToSelector {
  137. // Nil Checks
  138. STAssertFalse(class_respondsToSelector(cls_, @selector(setUp)), nil);
  139. STAssertFalse(class_respondsToSelector(cls_, nil), nil);
  140. // Standard use check
  141. STAssertTrue(class_respondsToSelector(cls_, @selector(kwyjibo)), nil);
  142. }
  143. - (void)test_class_getSuperclass {
  144. // Nil Checks
  145. STAssertNil(class_getSuperclass(nil), nil);
  146. // Standard use check
  147. STAssertEqualObjects(class_getSuperclass(cls_), [NSObject class], nil);
  148. }
  149. - (void)test_class_copyMethodList {
  150. // Nil Checks
  151. Method *list = class_copyMethodList(nil, nil);
  152. STAssertNULL(list, nil);
  153. // Standard use check
  154. list = class_copyMethodList(cls_, nil);
  155. STAssertNotNULL(list, nil);
  156. free(list);
  157. unsigned int count = 0;
  158. list = class_copyMethodList(cls_, &count);
  159. STAssertNotNULL(list, nil);
  160. STAssertEquals(count, 2U, nil);
  161. STAssertNULL(list[count], nil);
  162. free(list);
  163. // Now test meta class
  164. count = 0;
  165. list = class_copyMethodList((Class)objc_getMetaClass(class_getName(cls_)),
  166. &count);
  167. STAssertNotNULL(list, nil);
  168. STAssertEquals(count, 2U, nil);
  169. STAssertNULL(list[count], nil);
  170. free(list);
  171. }
  172. - (void)test_method_getName {
  173. // Nil Checks
  174. STAssertNULL(method_getName(nil), nil);
  175. // Standard use check
  176. Method *list = class_copyMethodList(cls_, nil);
  177. STAssertNotNULL(list, nil);
  178. const char* selName1 = sel_getName(method_getName(list[0]));
  179. const char* selName2 = sel_getName(@selector(kwyjibo));
  180. const char* selName3 = sel_getName(@selector(eatMyShorts));
  181. BOOL isGood = ((strcmp(selName1, selName2)) == 0 || (strcmp(selName1, selName3) == 0));
  182. STAssertTrue(isGood, nil);
  183. free(list);
  184. }
  185. - (void)test_method_exchangeImplementations {
  186. // nil checks
  187. method_exchangeImplementations(nil, nil);
  188. // Standard use check
  189. GTMObjC2Runtime_TestClass *test = [[GTMObjC2Runtime_TestClass alloc] init];
  190. STAssertNotNil(test, nil);
  191. // Get initial values
  192. NSString *val1 = [test kwyjibo];
  193. STAssertNotNil(val1, nil);
  194. NSString *val2 = [test eatMyShorts];
  195. STAssertNotNil(val2, nil);
  196. NSString *val3 = [GTMObjC2Runtime_TestClass dontHaveACow];
  197. STAssertNotNil(val3, nil);
  198. NSString *val4 = [GTMObjC2Runtime_TestClass brokeHisBrain];
  199. STAssertNotNil(val4, nil);
  200. // exchange the imps
  201. Method *list = class_copyMethodList(cls_, nil);
  202. STAssertNotNULL(list, nil);
  203. method_exchangeImplementations(list[0], list[1]);
  204. // test against initial values
  205. NSString *val5 = [test kwyjibo];
  206. STAssertNotNil(val5, nil);
  207. NSString *val6 = [test eatMyShorts];
  208. STAssertNotNil(val6, nil);
  209. STAssertEqualStrings(val1, val6, nil);
  210. STAssertEqualStrings(val2, val5, nil);
  211. // Check that other methods not affected
  212. STAssertEqualStrings([GTMObjC2Runtime_TestClass dontHaveACow], val3, nil);
  213. STAssertEqualStrings([GTMObjC2Runtime_TestClass brokeHisBrain], val4, nil);
  214. // exchange the imps back
  215. method_exchangeImplementations(list[0], list[1]);
  216. // and test against initial values again
  217. NSString *val7 = [test kwyjibo];
  218. STAssertNotNil(val7, nil);
  219. NSString *val8 = [test eatMyShorts];
  220. STAssertNotNil(val8, nil);
  221. STAssertEqualStrings(val1, val7, nil);
  222. STAssertEqualStrings(val2, val8, nil);
  223. method_exchangeImplementations(list[0], nil);
  224. method_exchangeImplementations(nil, list[0]);
  225. val7 = [test kwyjibo];
  226. STAssertNotNil(val7, nil);
  227. val8 = [test eatMyShorts];
  228. STAssertNotNil(val8, nil);
  229. STAssertEqualStrings(val1, val7, nil);
  230. STAssertEqualStrings(val2, val8, nil);
  231. free(list);
  232. [test release];
  233. }
  234. - (void)test_method_getImplementation {
  235. // Nil Checks
  236. STAssertNULL(method_getImplementation(nil), nil);
  237. // Standard use check
  238. Method *list = class_copyMethodList(cls_, nil);
  239. STAssertNotNULL(list, nil);
  240. STAssertNotNULL(method_getImplementation(list[0]), nil);
  241. free(list);
  242. }
  243. - (void)test_method_setImplementation {
  244. // Standard use check
  245. GTMObjC2Runtime_TestClass *test = [[GTMObjC2Runtime_TestClass alloc] init];
  246. Method *list = class_copyMethodList(cls_, nil);
  247. // Get initial value
  248. NSString *str1 = objc_msgSend(test, method_getName(list[0]));
  249. STAssertNotNil(str1, nil);
  250. // set the imp to something else
  251. IMP oldImp = method_setImplementation(list[0], method_getImplementation(list[1]));
  252. STAssertNotNULL(oldImp, nil);
  253. // make sure they are different
  254. NSString *str2 = objc_msgSend(test,method_getName(list[0]));
  255. STAssertNotNil(str2, nil);
  256. STAssertNotEqualStrings(str1, str2, nil);
  257. // reset the imp
  258. IMP newImp = method_setImplementation(list[0], oldImp);
  259. STAssertNotEquals(oldImp, newImp, nil);
  260. // test nils
  261. // Apparently it was a bug that we could call setImplementation with a nil
  262. // so we now test to make sure that setting to nil works as expected on
  263. // all systems.
  264. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  265. // Built for less then leopard gives us the behaviors we defined...
  266. // (doesn't take nil)
  267. IMP nullImp = method_setImplementation(list[0], nil);
  268. STAssertNULL(nullImp, nil);
  269. IMP testImp = method_setImplementation(list[0], newImp);
  270. STAssertEquals(testImp, oldImp, nil);
  271. #else
  272. // Built for leopard or later means we get the os runtime behavior...
  273. if ([GTMSystemVersion isLeopard]) {
  274. // (takes nil)
  275. oldImp = method_setImplementation(list[0], nil);
  276. STAssertNotNULL(oldImp, nil);
  277. newImp = method_setImplementation(list[0], oldImp);
  278. STAssertNULL(newImp, nil);
  279. } else {
  280. // (doesn't take nil)
  281. IMP nullImp = method_setImplementation(list[0], nil);
  282. STAssertNULL(nullImp, nil);
  283. IMP testImp = method_setImplementation(list[0], newImp);
  284. STAssertEquals(testImp, oldImp, nil);
  285. }
  286. #endif
  287. // This case intentionally not tested. Passing nil to method_setImplementation
  288. // on Leopard crashes. It does on Tiger as well. Half works on SnowLeopard.
  289. // We made our Tiger implementation the same as the SnowLeopard
  290. // implementation.
  291. // Logged as radar 5572981.
  292. if (![GTMSystemVersion isLeopardOrGreater]) {
  293. STAssertNULL(method_setImplementation(nil, nil), nil);
  294. }
  295. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  296. if ([GTMSystemVersion isSnowLeopardOrGreater]) {
  297. STAssertNULL(method_setImplementation(nil, newImp), nil);
  298. }
  299. #endif
  300. [test release];
  301. free(list);
  302. }
  303. - (void)test_protocol_getMethodDescription {
  304. // Check nil cases
  305. struct objc_method_description desc = protocol_getMethodDescription(nil, nil,
  306. YES, YES);
  307. STAssertNULL(desc.name, nil);
  308. desc = protocol_getMethodDescription(nil, @selector(optional), YES, YES);
  309. STAssertNULL(desc.name, nil);
  310. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  311. nil, YES, YES);
  312. STAssertNULL(desc.name, nil);
  313. // Instance Methods
  314. // Check Required case. Only OBJC2 supports required.
  315. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  316. @selector(optional), YES, YES);
  317. #if OBJC_API_VERSION >= 2
  318. STAssertNULL(desc.name, nil);
  319. #else
  320. STAssertNotNULL(desc.name, nil);
  321. #endif
  322. // Check Required case. Only OBJC2 supports required.
  323. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  324. @selector(required), YES, YES);
  325. STAssertNotNULL(desc.name, nil);
  326. // Check Optional case. Only OBJC2 supports optional.
  327. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  328. @selector(optional), NO, YES);
  329. STAssertNotNULL(desc.name, nil);
  330. // Check Optional case. Only OBJC2 supports optional.
  331. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  332. @selector(required), NO, YES);
  333. #if OBJC_API_VERSION >= 2
  334. STAssertNULL(desc.name, nil);
  335. #else
  336. STAssertNotNULL(desc.name, nil);
  337. #endif
  338. // Class Methods
  339. // Check Required case. Only OBJC2 supports required.
  340. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  341. @selector(class_optional), YES, NO);
  342. #if OBJC_API_VERSION >= 2
  343. STAssertNULL(desc.name, nil);
  344. #else
  345. STAssertNotNULL(desc.name, nil);
  346. #endif
  347. // Check Required case. Only OBJC2 supports required.
  348. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  349. @selector(class_required), YES, NO);
  350. STAssertNotNULL(desc.name, nil);
  351. // Check Optional case. Only OBJC2 supports optional.
  352. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  353. @selector(class_optional), NO, NO);
  354. STAssertNotNULL(desc.name, nil);
  355. // Check Optional case. Only OBJC2 supports optional.
  356. desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
  357. @selector(class_required), NO, NO);
  358. #if OBJC_API_VERSION >= 2
  359. STAssertNULL(desc.name, nil);
  360. #else
  361. STAssertNotNULL(desc.name, nil);
  362. #endif
  363. }
  364. - (void)test_sel_isEqual {
  365. STAssertTrue(sel_isEqual(@selector(kwyjibo), @selector(kwyjibo)), nil);
  366. STAssertFalse(sel_isEqual(@selector(kwyjibo), @selector(dontHaveACow)), nil);
  367. STAssertTrue(sel_isEqual(_cmd, @selector(test_sel_isEqual)), nil);
  368. STAssertTrue(sel_isEqual(_cmd, _cmd), nil);
  369. STAssertFalse(sel_isEqual(_cmd, @selector(kwyjibo)), nil);
  370. }
  371. @end