1// TEST_CONFIG
2
3#include "test.h"
4#include "testroot.i"
5#include <objc/runtime.h>
6#include <objc/message.h>
7
8static int state = 0;
9
10@interface Super : TestRoot @end
11@implementation Super
12+(void)classMethod { state = 1; }
13-(void)instanceMethod { state = 4; } 
14+(void)classMethodSuperOnly { state = 3; }
15-(void)instanceMethodSuperOnly { state = 6; } 
16@end
17
18@interface Sub : Super @end
19@implementation Sub
20+(void)classMethod { state = 2; }
21-(void)instanceMethod { state = 5; } 
22@end
23
24typedef void (*imp_t)(id, SEL);
25
26int main()
27{
28    Class Super_cls, Sub_cls;
29    Class buf[10];
30    Method m;
31    SEL sel;
32    IMP imp;
33
34    // don't use [Super class] to check laziness handing
35    Super_cls = objc_getClass("Super");
36    Sub_cls = objc_getClass("Sub");
37
38    sel = sel_registerName("classMethod");
39    m = class_getClassMethod(Super_cls, sel);
40    testassert(m);
41    testassert(sel == method_getName(m));
42    imp = method_getImplementation(m);
43    testassert(imp == class_getMethodImplementation(object_getClass(Super_cls), sel));
44    testassert(imp == object_getMethodImplementation(Super_cls, sel));
45    state = 0;
46    (*(imp_t)imp)(Super_cls, sel);
47    testassert(state == 1);
48
49    sel = sel_registerName("classMethod");
50    m = class_getClassMethod(Sub_cls, sel);
51    testassert(m);
52    testassert(sel == method_getName(m));
53    imp = method_getImplementation(m);
54    testassert(imp == class_getMethodImplementation(object_getClass(Sub_cls), sel));
55    testassert(imp == object_getMethodImplementation(Sub_cls, sel));
56    state = 0;
57    (*(imp_t)imp)(Sub_cls, sel);
58    testassert(state == 2);
59
60    sel = sel_registerName("classMethodSuperOnly");
61    m = class_getClassMethod(Sub_cls, sel);
62    testassert(m);
63    testassert(sel == method_getName(m));
64    imp = method_getImplementation(m);
65    testassert(imp == class_getMethodImplementation(object_getClass(Sub_cls), sel));
66    testassert(imp == object_getMethodImplementation(Sub_cls, sel));
67    state = 0;
68    (*(imp_t)imp)(Sub_cls, sel);
69    testassert(state == 3);
70    
71    sel = sel_registerName("instanceMethod");
72    m = class_getInstanceMethod(Super_cls, sel);
73    testassert(m);
74    testassert(sel == method_getName(m));
75    imp = method_getImplementation(m);
76    testassert(imp == class_getMethodImplementation(Super_cls, sel));
77    buf[0] = Super_cls;
78    testassert(imp == object_getMethodImplementation(objc_unretainedObject(buf), sel));
79    state = 0;
80    (*(imp_t)imp)(objc_unretainedObject(buf), sel);
81    testassert(state == 4);
82
83    sel = sel_registerName("instanceMethod");
84    m = class_getInstanceMethod(Sub_cls, sel);
85    testassert(m);
86    testassert(sel == method_getName(m));
87    imp = method_getImplementation(m);
88    testassert(imp == class_getMethodImplementation(Sub_cls, sel));
89    buf[0] = Sub_cls;
90    testassert(imp == object_getMethodImplementation(objc_unretainedObject(buf), sel));
91    state = 0;
92    (*(imp_t)imp)(objc_unretainedObject(buf), sel);
93    testassert(state == 5);
94
95    sel = sel_registerName("instanceMethodSuperOnly");
96    m = class_getInstanceMethod(Sub_cls, sel);
97    testassert(m);
98    testassert(sel == method_getName(m));
99    imp = method_getImplementation(m);
100    testassert(imp == class_getMethodImplementation(Sub_cls, sel));
101    buf[0] = Sub_cls;
102    testassert(imp == object_getMethodImplementation(objc_unretainedObject(buf), sel));
103    state = 0;
104    (*(imp_t)imp)(objc_unretainedObject(buf), sel);
105    testassert(state == 6);
106
107    // check class_getClassMethod(cls) == class_getInstanceMethod(cls->isa)
108    sel = sel_registerName("classMethod");
109    testassert(class_getClassMethod(Sub_cls, sel) == class_getInstanceMethod(object_getClass(Sub_cls), sel));
110
111    sel = sel_registerName("nonexistent");
112    testassert(! class_getInstanceMethod(Sub_cls, sel));
113    testassert(! class_getClassMethod(Sub_cls, sel));
114    testassert(class_getMethodImplementation(Sub_cls, sel) == (IMP)&_objc_msgForward);
115    buf[0] = Sub_cls;
116    testassert(object_getMethodImplementation(objc_unretainedObject(buf), sel) == (IMP)&_objc_msgForward);
117    testassert(class_getMethodImplementation_stret(Sub_cls, sel) == (IMP)&_objc_msgForward_stret);
118    testassert(object_getMethodImplementation_stret(objc_unretainedObject(buf), sel) == (IMP)&_objc_msgForward_stret);
119
120    testassert(! class_getInstanceMethod(NULL, NULL));
121    testassert(! class_getInstanceMethod(NULL, sel));
122    testassert(! class_getInstanceMethod(Sub_cls, NULL));
123    testassert(! class_getClassMethod(NULL, NULL));
124    testassert(! class_getClassMethod(NULL, sel));
125    testassert(! class_getClassMethod(Sub_cls, NULL));
126
127    succeed(__FILE__);
128}
129