2 #include <objc/runtime.h>
4 @interface Super { @public id isa; } @end
7 +class { return self; }
8 +(id) new { return class_createInstance(self, 0); }
10 -(int)superMethod { return 0; }
11 -(int)bothMethod { return 0; }
14 @interface Sub : Super @end
16 -(int)subMethod { return 0; }
17 -(int)bothMethod { return 0; }
20 @interface Sub2 : Super @end
22 -(int)subMethod { return 0; }
23 -(int)bothMethod { return 0; }
27 id fn(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) { return nil; }
31 IMP superMethodFromSuper = class_getMethodImplementation([Super class], @selector(superMethod));
32 IMP bothMethodFromSuper = class_getMethodImplementation([Super class], @selector(bothMethod));
33 IMP subMethodFromSub = class_getMethodImplementation([Sub class], @selector(subMethod));
34 IMP bothMethodFromSub = class_getMethodImplementation([Sub class], @selector(bothMethod));
35 IMP subMethodFromSub2 = class_getMethodImplementation([Sub2 class], @selector(subMethod));
36 IMP bothMethodFromSub2 = class_getMethodImplementation([Sub2 class], @selector(bothMethod));
38 testassert(superMethodFromSuper);
39 testassert(bothMethodFromSuper);
40 testassert(subMethodFromSub);
41 testassert(bothMethodFromSub);
42 testassert(subMethodFromSub2);
43 testassert(bothMethodFromSub2);
48 // class_addMethod doesn't replace existing implementations
49 ok = class_addMethod([Super class], @selector(superMethod), &fn, NULL);
51 testassert(class_getMethodImplementation([Super class], @selector(superMethod)) == superMethodFromSuper);
53 // class_addMethod does override superclass implementations
54 ok = class_addMethod([Sub class], @selector(superMethod), &fn, NULL);
56 testassert(class_getMethodImplementation([Sub class], @selector(superMethod)) == &fn);
58 // class_addMethod does add root implementations
59 ok = class_addMethod([Super class], @selector(superMethodNew2), &fn, NULL);
61 testassert(class_getMethodImplementation([Super class], @selector(superMethodNew2)) == &fn);
62 testassert(class_getMethodImplementation([Sub class], @selector(superMethodNew2)) == &fn);
65 // class_replaceMethod does add new implementations,
66 // returning NULL if super has an implementation
67 imp = class_replaceMethod([Sub2 class], @selector(superMethod), &fn, NULL);
68 testassert(imp == NULL);
69 testassert(class_getMethodImplementation([Sub2 class], @selector(superMethod)) == fn);
71 // class_replaceMethod does add new implementations,
72 // returning NULL if super has no implementation
73 imp = class_replaceMethod([Sub2 class], @selector(subMethodNew), &fn, NULL);
74 testassert(imp == NULL);
75 testassert(class_getMethodImplementation([Sub2 class], @selector(subMethodNew)) == fn);
77 // class_replaceMethod does add new implemetations
78 // returning NULL if there is no super class
79 imp = class_replaceMethod([Super class], @selector(superMethodNew), &fn, NULL);
80 testassert(imp == NULL);
81 testassert(class_getMethodImplementation([Super class], @selector(superMethodNew)) == fn);
84 // class_replaceMethod does replace existing implementations,
85 // returning existing implementation (regardless of super)
86 imp = class_replaceMethod([Sub2 class], @selector(subMethod), &fn, NULL);
87 testassert(imp == subMethodFromSub2);
88 testassert(class_getMethodImplementation([Sub2 class], @selector(subMethod)) == fn);
90 // class_replaceMethod does replace existing implemetations,
91 // returning existing implementation (regardless of super)
92 imp = class_replaceMethod([Sub2 class], @selector(bothMethod), &fn, NULL);
93 testassert(imp == bothMethodFromSub2);
94 testassert(class_getMethodImplementation([Sub2 class], @selector(bothMethod)) == fn);
96 // class_replaceMethod does replace existing implemetations,
97 // returning existing implementation (regardless of super)
98 imp = class_replaceMethod([Super class], @selector(superMethod), &fn, NULL);
99 testassert(imp == superMethodFromSuper);
100 testassert(class_getMethodImplementation([Super class], @selector(superMethod)) == fn);
102 // fixme actually try calling them