]> git.saurik.com Git - apple/objc4.git/blob - test/addMethods.m
objc4-779.1.tar.gz
[apple/objc4.git] / test / addMethods.m
1 // TEST_CONFIG
2
3 #include "test.h"
4 #include "testroot.i"
5 #include <objc/runtime.h>
6 #include <objc/objc-internal.h>
7
8 // Macros for array construction.
9 // ten IMPs
10 #define IMPS10 (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4, \
11 (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9
12 // ten method types
13 #define TYPES10 "", "", "", "", "", "", "", "", "", ""
14 // ten selectors of the form name0..name9
15 #define SELS10(name) \
16 @selector(name##0), @selector(name##1), @selector(name##2), \
17 @selector(name##3), @selector(name##4), @selector(name##5), \
18 @selector(name##6), @selector(name##7), @selector(name##8), \
19 @selector(name##9)
20
21
22 @interface Super : TestRoot @end
23 @implementation Super
24 -(int)superMethod0 { return 0; }
25 -(int)superMethod1 { return 0; }
26 -(int)superMethod2 { return 0; }
27 -(int)superMethod3 { return 0; }
28 -(int)superMethod4 { return 0; }
29 -(int)superMethod5 { return 0; }
30 -(int)superMethod6 { return 0; }
31 -(int)superMethod7 { return 0; }
32 -(int)superMethod8 { return 0; }
33 -(int)superMethod9 { return 0; }
34 -(int)bothMethod0 { return 0; }
35 -(int)bothMethod1 { return 0; }
36 -(int)bothMethod2 { return 0; }
37 -(int)bothMethod3 { return 0; }
38 -(int)bothMethod4 { return 0; }
39 -(int)bothMethod5 { return 0; }
40 -(int)bothMethod6 { return 0; }
41 -(int)bothMethod7 { return 0; }
42 -(int)bothMethod8 { return 0; }
43 -(int)bothMethod9 { return 0; }
44 @end
45
46 @interface Sub : Super @end
47 @implementation Sub
48 -(int)subMethod0 { return 0; }
49 -(int)subMethod1 { return 0; }
50 -(int)subMethod2 { return 0; }
51 -(int)subMethod3 { return 0; }
52 -(int)subMethod4 { return 0; }
53 -(int)subMethod5 { return 0; }
54 -(int)subMethod6 { return 0; }
55 -(int)subMethod7 { return 0; }
56 -(int)subMethod8 { return 0; }
57 -(int)subMethod9 { return 0; }
58 -(int)bothMethod0 { return 0; }
59 -(int)bothMethod1 { return 0; }
60 -(int)bothMethod2 { return 0; }
61 -(int)bothMethod3 { return 0; }
62 -(int)bothMethod4 { return 0; }
63 -(int)bothMethod5 { return 0; }
64 -(int)bothMethod6 { return 0; }
65 -(int)bothMethod7 { return 0; }
66 -(int)bothMethod8 { return 0; }
67 -(int)bothMethod9 { return 0; }
68 @end
69
70 @interface Sub2 : Super @end
71 @implementation Sub2
72 -(int)subMethod0 { return 0; }
73 -(int)subMethod1 { return 0; }
74 -(int)subMethod2 { return 0; }
75 -(int)subMethod3 { return 0; }
76 -(int)subMethod4 { return 0; }
77 -(int)subMethod5 { return 0; }
78 -(int)subMethod6 { return 0; }
79 -(int)subMethod7 { return 0; }
80 -(int)subMethod8 { return 0; }
81 -(int)subMethod9 { return 0; }
82 -(int)bothMethod0 { return 0; }
83 -(int)bothMethod1 { return 0; }
84 -(int)bothMethod2 { return 0; }
85 -(int)bothMethod3 { return 0; }
86 -(int)bothMethod4 { return 0; }
87 -(int)bothMethod5 { return 0; }
88 -(int)bothMethod6 { return 0; }
89 -(int)bothMethod7 { return 0; }
90 -(int)bothMethod8 { return 0; }
91 -(int)bothMethod9 { return 0; }
92 @end
93
94
95 id fn0(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
96 return nil;
97 }
98 id fn1(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
99 return nil;
100 }
101 id fn2(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
102 return nil;
103 }
104 id fn3(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
105 return nil;
106 }
107 id fn4(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
108 return nil;
109 }
110 id fn5(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
111 return nil;
112 }
113 id fn6(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
114 return nil;
115 }
116 id fn7(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
117 return nil;
118 }
119 id fn8(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
120 return nil;
121 }
122 id fn9(id self __attribute__((unused)), SEL cmd __attribute__((unused)), ...) {
123 return nil;
124 }
125
126 void testBulkMemoryOnce(void)
127 {
128 Class c = objc_allocateClassPair([TestRoot class], "c", 0);
129 objc_registerClassPair(c);
130
131 SEL sels[10] = {
132 SELS10(method)
133 };
134 IMP imps[10] = {
135 IMPS10
136 };
137 const char *types[10] = {
138 TYPES10
139 };
140
141 uint32_t failureCount = 0;
142 SEL *failed;
143
144 // Test all successes.
145 failed = class_addMethodsBulk(c, sels, imps, types, 4, &failureCount);
146 testassert(failed == NULL);
147 testassert(failureCount == 0);
148
149 // Test mixed success and failure (this overlaps the previous one, so there
150 // will be one of each).
151 failed = class_addMethodsBulk(c, sels + 3, imps + 3, types + 3, 2,
152 &failureCount);
153 testassert(failed != NULL);
154 testassert(failureCount == 1);
155 testassert(failed[0] == sels[3]);
156 free(failed);
157
158 // Test total failure.
159 failed = class_addMethodsBulk(c, sels, imps, types, 5, &failureCount);
160 testassert(failed != NULL);
161 testassert(failureCount == 5);
162 for(int i = 0; i < 5; i++) {
163 testassert(failed[i] == sels[i]);
164 }
165 free(failed);
166
167 class_replaceMethodsBulk(c, sels, imps, types, 10);
168
169 for(int i = 0; i < 10; i++) {
170 testassert(class_getMethodImplementation(c, sels[i]) == imps[i]);
171 }
172
173 objc_disposeClassPair(c);
174 }
175
176 int main()
177 {
178 IMP dummyIMPs[130] = {
179 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
180 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
181 IMPS10, IMPS10, IMPS10,
182 };
183
184 // similar to dummyIMPs but with different values in each slot
185 IMP dummyIMPs2[130] = {
186 (IMP)fn5, (IMP)fn6, (IMP)fn7, (IMP)fn8, (IMP)fn9,
187 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
188 IMPS10, IMPS10, IMPS10, IMPS10, IMPS10,
189 IMPS10, IMPS10,
190 (IMP)fn0, (IMP)fn1, (IMP)fn2, (IMP)fn3, (IMP)fn4,
191 };
192
193 const char *dummyTypes[130] = {
194 TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
195 TYPES10, TYPES10, TYPES10, TYPES10, TYPES10,
196 TYPES10, TYPES10, TYPES10,
197 };
198
199 SEL addSELs[20] = {
200 SELS10(superMethod),
201 SELS10(superMethodAddNew)
202 };
203
204 uint32_t failedCount = 0;
205 SEL *failed;
206
207 failed = class_addMethodsBulk([Super class], addSELs, dummyIMPs, dummyTypes,
208 20, &failedCount);
209
210 // class_addMethodsBulk reports failures for all methods that already exist
211 testassert(failed != NULL);
212 testassert(failedCount == 10);
213
214 // class_addMethodsBulk failed for existing implementations
215 for(int i = 0; i < 10; i++) {
216 testassert(failed[i] == addSELs[i]);
217 testassert(class_getMethodImplementation([Super class], addSELs[i])
218 != dummyIMPs[i]);
219 }
220
221 free(failed);
222
223 // class_addMethodsBulk does add root implementations
224 for(int i = 10; i < 20; i++) {
225 testassert(class_getMethodImplementation([Super class], addSELs[i])
226 == dummyIMPs[i]);
227 }
228
229 // class_addMethod does override superclass implementations
230 failed = class_addMethodsBulk([Sub class], addSELs, dummyIMPs, dummyTypes,
231 10, &failedCount);
232 testassert(failedCount == 0);
233 testassert(failed == NULL);
234 for(int i = 0; i < 10; i++) {
235 testassert(class_getMethodImplementation([Sub class], addSELs[i])
236 == dummyIMPs[i]);
237 }
238
239 SEL subReplaceSELs[40] = {
240 SELS10(superMethod),
241 SELS10(subMethodNew),
242 SELS10(subMethod),
243 SELS10(bothMethod),
244 };
245
246 // class_replaceMethodsBulk adds new implementations or replaces existing
247 // ones for methods that exist on the superclass, the subclass, both, or
248 // neither
249 class_replaceMethodsBulk([Sub2 class], subReplaceSELs, dummyIMPs,
250 dummyTypes, 40);
251 for(int i = 0; i < 40; i++) {
252 IMP newIMP = class_getMethodImplementation([Sub2 class],
253 subReplaceSELs[i]);
254 testassert(newIMP == dummyIMPs[i]);
255 }
256
257 SEL superReplaceSELs[20] = {
258 SELS10(superMethod),
259 SELS10(superMethodNew),
260 };
261
262 // class_replaceMethodsBulk adds new implementations or replaces existing
263 // ones in the superclass
264 class_replaceMethodsBulk([Super class], superReplaceSELs, dummyIMPs,
265 dummyTypes, 20);
266 for(int i = 0; i < 20; i++) {
267 IMP newIMP = class_getMethodImplementation([Super class],
268 superReplaceSELs[i]);
269 testassert(newIMP == dummyIMPs[i]);
270 }
271
272
273 // class_addMethodsBulk, where almost all of the requested additions
274 // already exist and thus can't be added. (They were already added
275 // above by class_replaceMethodsBulk([Sub2 class], subReplaceSELs, ...).)
276
277 // This list is large in the hope of provoking any realloc() of the
278 // new method list inside addMethods().
279 // The runtime doesn't care that the list contains lots of duplicates.
280 SEL subAddMostlyExistingSELs[130] = {
281 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
282 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
283 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
284 SELS10(superMethod), SELS10(subMethodNew), SELS10(subMethod),
285 SELS10(bothMethod),
286 };
287 subAddMostlyExistingSELs[16] = @selector(INDEX_16_IS_DIFFERENT);
288
289 failed = class_addMethodsBulk([Sub2 class], subAddMostlyExistingSELs,
290 dummyIMPs2, dummyTypes, 130, &failedCount);
291 testassert(failedCount == 129);
292 testassert(failed != NULL);
293
294 for(int i = 0; i < 130; i++) {
295 IMP newIMP = class_getMethodImplementation([Sub2 class],
296 subAddMostlyExistingSELs[i]);
297 if (i == 16) {
298 // the only one that was actually added
299 testassert(newIMP != dummyIMPs[i]);
300 testassert(newIMP == dummyIMPs2[i]);
301 } else {
302 // the others should all have failed
303 testassert(newIMP == dummyIMPs[i]);
304 testassert(newIMP != dummyIMPs2[i]);
305 }
306 }
307 for (uint32_t i = 0; i < failedCount; i++) {
308 testassert(failed[i] != NULL);
309 testassert(failed[i] != subAddMostlyExistingSELs[16]);
310 }
311
312
313 // fixme actually try calling them
314
315 // make sure the Bulk functions aren't leaking
316 testBulkMemoryOnce();
317 leak_mark();
318 for(int i = 0; i < 10; i++) {
319 testBulkMemoryOnce();
320 }
321 leak_check(0);
322
323 succeed(__FILE__);
324 }