]> git.saurik.com Git - apple/objc4.git/blob - test/copyMethodList.m
objc4-532.tar.gz
[apple/objc4.git] / test / copyMethodList.m
1 // TEST_CFLAGS -Wl,-no_objc_category_merging
2
3 #include "test.h"
4 #include "testroot.i"
5 #include <malloc/malloc.h>
6 #include <objc/runtime.h>
7
8 @interface SuperMethods : TestRoot { } @end
9 @implementation SuperMethods
10 +(BOOL)SuperMethodClass { return NO; }
11 +(BOOL)SuperMethodClass2 { return NO; }
12 -(BOOL)SuperMethodInstance { return NO; }
13 -(BOOL)SuperMethodInstance2 { return NO; }
14 @end
15
16 @interface SubMethods : SuperMethods { } @end
17 @implementation SubMethods
18 +(BOOL)SubMethodClass { return NO; }
19 +(BOOL)SubMethodClass2 { return NO; }
20 -(BOOL)SubMethodInstance { return NO; }
21 -(BOOL)SubMethodInstance2 { return NO; }
22 @end
23
24 @interface SuperMethods (Category) @end
25 @implementation SuperMethods (Category)
26 +(BOOL)SuperMethodClass { return YES; }
27 +(BOOL)SuperMethodClass2 { return YES; }
28 -(BOOL)SuperMethodInstance { return YES; }
29 -(BOOL)SuperMethodInstance2 { return YES; }
30 @end
31
32 @interface SubMethods (Category) @end
33 @implementation SubMethods (Category)
34 +(BOOL)SubMethodClass { return YES; }
35 +(BOOL)SubMethodClass2 { return YES; }
36 -(BOOL)SubMethodInstance { return YES; }
37 -(BOOL)SubMethodInstance2 { return YES; }
38 @end
39
40
41 @interface FourMethods : TestRoot @end
42 @implementation FourMethods
43 -(void)one { }
44 -(void)two { }
45 -(void)three { }
46 -(void)four { }
47 @end
48
49 @interface NoMethods : TestRoot @end
50 @implementation NoMethods @end
51
52 static void checkReplacement(Method *list, const char *name)
53 {
54 Method first = NULL, second = NULL;
55 SEL sel = sel_registerName(name);
56 int i;
57
58 testassert(list);
59
60 // Find the methods. There should be two.
61 for (i = 0; list[i]; i++) {
62 if (method_getName(list[i]) == sel) {
63 if (!first) first = list[i];
64 else if (!second) second = list[i];
65 else testassert(0);
66 }
67 }
68
69 // Call the methods. The first should be the category (returns YES).
70 BOOL isCat;
71 isCat = ((BOOL(*)(id, Method))method_invoke)(NULL, first);
72 testassert(isCat);
73 isCat = ((BOOL(*)(id, Method))method_invoke)(NULL, second);
74 testassert(! isCat);
75 }
76
77 int main()
78 {
79 // Class SubMethods has not yet been touched, so runtime must attach
80 // the lazy categories
81 Method *methods;
82 unsigned int count;
83 Class cls;
84
85 cls = objc_getClass("SubMethods");
86 testassert(cls);
87
88 testprintf("calling class_copyMethodList(SubMethods) (should be unmethodized)\n");
89
90 count = 100;
91 methods = class_copyMethodList(cls, &count);
92 testassert(methods);
93 testassert(count == 4);
94 // methods[] should be null-terminated
95 testassert(methods[4] == NULL);
96 // Class and category methods may be mixed in the method list thanks
97 // to linker / shared cache sorting, but a category's replacement should
98 // always precede the class's implementation.
99 checkReplacement(methods, "SubMethodInstance");
100 checkReplacement(methods, "SubMethodInstance2");
101 free(methods);
102
103 testprintf("calling class_copyMethodList(SubMethods(meta)) (should be unmethodized)\n");
104
105 count = 100;
106 methods = class_copyMethodList(object_getClass(cls), &count);
107 testassert(methods);
108 testassert(count == 4);
109 // methods[] should be null-terminated
110 testassert(methods[4] == NULL);
111 // Class and category methods may be mixed in the method list thanks
112 // to linker / shared cache sorting, but a category's replacement should
113 // always precede the class's implementation.
114 checkReplacement(methods, "SubMethodClass");
115 checkReplacement(methods, "SubMethodClass2");
116 free(methods);
117
118 // Check null-termination - this method list block would be 16 bytes
119 // if it weren't for the terminator
120 count = 100;
121 cls = objc_getClass("FourMethods");
122 methods = class_copyMethodList(cls, &count);
123 testassert(methods);
124 testassert(count == 4);
125 testassert(malloc_size(methods) >= (4+1) * sizeof(Method));
126 testassert(methods[3] != NULL);
127 testassert(methods[4] == NULL);
128 free(methods);
129
130 // Check NULL count parameter
131 methods = class_copyMethodList(cls, NULL);
132 testassert(methods);
133 testassert(methods[4] == NULL);
134 testassert(methods[3] != NULL);
135 free(methods);
136
137 // Check NULL class parameter
138 count = 100;
139 methods = class_copyMethodList(NULL, &count);
140 testassert(!methods);
141 testassert(count == 0);
142
143 // Check NULL class and count
144 methods = class_copyMethodList(NULL, NULL);
145 testassert(!methods);
146
147 // Check class with no methods
148 count = 100;
149 cls = objc_getClass("NoMethods");
150 methods = class_copyMethodList(cls, &count);
151 testassert(!methods);
152 testassert(count == 0);
153
154 succeed(__FILE__);
155 }