]>
Commit | Line | Data |
---|---|---|
bc4fafce A |
1 | // TEST_CFLAGS -std=c++11 |
2 | ||
3 | #include "methodListSmall.h" | |
4 | ||
5 | void testClass(Class c) { | |
6 | id foo = [c new]; | |
7 | [foo myMethod1]; | |
8 | testassert(ranMyMethod1); | |
9 | [foo myMethod2]; | |
10 | testassert(ranMyMethod2); | |
11 | [foo myMethod3]; | |
12 | testassert(ranMyMethod3); | |
13 | ||
14 | Method m1 = class_getInstanceMethod(c, @selector(myMethod1)); | |
15 | testassert(m1); | |
16 | testassert(method_getName(m1) == @selector(myMethod1)); | |
17 | testassert(strcmp(method_getTypeEncoding(m1), "v16@0:8") == 0); | |
18 | testassert(method_getImplementation(m1) == (IMP)myMethod1); | |
19 | ||
20 | method_setImplementation(m1, (IMP)myReplacedMethod1); | |
21 | testassert(method_getImplementation(m1) == (IMP)myReplacedMethod1); | |
22 | [foo myMethod1]; | |
23 | testassert(ranMyReplacedMethod1); | |
24 | ||
25 | Method m2 = class_getInstanceMethod(c, @selector(myMethod2)); | |
26 | auto method_invoke_cast = (void (*)(id, Method))method_invoke; | |
27 | ||
28 | ranMyMethod2 = 0; | |
29 | method_invoke_cast(foo, m2); | |
30 | testassert(ranMyMethod2); | |
31 | ||
32 | method_setImplementation(m2, (IMP)myReplacedMethod2); | |
33 | method_invoke_cast(foo, m2); | |
34 | testassert(ranMyReplacedMethod2); | |
35 | ||
36 | Method mstret = class_getInstanceMethod(c, @selector(myMethodStret)); | |
37 | #if __arm64__ | |
38 | // No _stret variant on ARM64. We'll test struct return through | |
39 | // method_invoke anyway just to be thorough. | |
40 | auto method_invoke_stret_cast = (BigStruct (*)(id, Method))method_invoke; | |
41 | #else | |
42 | auto method_invoke_stret_cast = (BigStruct (*)(id, Method))method_invoke_stret; | |
43 | #endif | |
44 | ||
45 | [foo myMethodStret]; | |
46 | testassert(ranMyMethodStret); | |
47 | ||
48 | ranMyMethodStret = 0; | |
49 | method_invoke_stret_cast(foo, mstret); | |
50 | testassert(ranMyMethodStret); | |
51 | ||
52 | method_setImplementation(mstret, (IMP)myReplacedMethodStret); | |
53 | [foo myMethodStret]; | |
54 | testassert(ranMyReplacedMethodStret); | |
55 | ||
56 | ranMyReplacedMethodStret = 0; | |
57 | method_invoke_stret_cast(foo, mstret); | |
58 | testassert(ranMyReplacedMethodStret); | |
59 | ||
60 | auto *desc1 = method_getDescription(m1); | |
61 | testassert(desc1->name == @selector(myMethod1)); | |
62 | testassert(desc1->types == method_getTypeEncoding(m1)); | |
63 | ||
64 | auto *desc2 = method_getDescription(m2); | |
65 | testassert(desc2->name == @selector(myMethod2)); | |
66 | testassert(desc2->types == method_getTypeEncoding(m2)); | |
67 | ||
68 | auto *descstret = method_getDescription(mstret); | |
69 | testassert(descstret->name == @selector(myMethodStret)); | |
70 | testassert(descstret->types == method_getTypeEncoding(mstret)); | |
34d5b5e8 A |
71 | |
72 | Method nullTypeMethod = class_getInstanceMethod(c, @selector(myMethodNullTypes)); | |
73 | testassert(nullTypeMethod); | |
74 | testassert(method_getName(nullTypeMethod) == @selector(myMethodNullTypes)); | |
75 | testassertequal(method_getTypeEncoding(nullTypeMethod), NULL); | |
76 | testassertequal(method_getImplementation(nullTypeMethod), (IMP)myMethod1); | |
bc4fafce A |
77 | } |
78 | ||
79 | int main() { | |
80 | Class fooClass = (__bridge Class)&FooClass; | |
81 | ||
82 | // Make sure this class can be duplicated and works as expected. | |
83 | // Duplicate it before testClass mucks around with the methods. | |
84 | // Need to realize fooClass before duplicating it, hence the | |
85 | // class message. | |
86 | Class dupedClass = objc_duplicateClass([fooClass class], "FooDup", 0); | |
87 | ||
88 | testprintf("Testing class.\n"); | |
89 | testClass(fooClass); | |
90 | ||
91 | testprintf("Testing duplicate class.\n"); | |
92 | testClass(dupedClass); | |
93 | ||
94 | succeed(__FILE__); | |
95 | } |