]> git.saurik.com Git - apple/objc4.git/blob - test/classpair.m
objc4-493.9.tar.gz
[apple/objc4.git] / test / classpair.m
1 // TEST_CFLAGS -Wno-deprecated-declarations
2
3 #include "test.h"
4 #include <objc/runtime.h>
5 #include <string.h>
6 #ifndef OBJC_NO_GC
7 #include <objc/objc-auto.h>
8 #include <auto_zone.h>
9 #endif
10
11 @protocol Proto
12 -(void) instanceMethod;
13 +(void) classMethod;
14 @optional
15 -(void) instanceMethod2;
16 +(void) classMethod2;
17 @end
18
19 @protocol Proto2
20 -(void) instanceMethod;
21 +(void) classMethod;
22 @optional
23 -(void) instanceMethod2;
24 +(void) classMethod_that_does_not_exist;
25 @end
26
27 @protocol Proto3
28 -(void) instanceMethod;
29 +(void) classMethod_that_does_not_exist;
30 @optional
31 -(void) instanceMethod2;
32 +(void) classMethod2;
33 @end
34
35 static int super_initialize;
36
37 @interface Super { @public id isa; }
38 @property int superProp;
39 @end
40 @implementation Super
41 @dynamic superProp;
42 +(void)initialize { super_initialize++; }
43 +class { return self; }
44 +(id) new { return class_createInstance(self, 0); }
45 -(void) free { object_dispose(self); }
46
47 +(void) classMethod { fail("+[Super classMethod] called"); }
48 +(void) classMethod2 { fail("+[Super classMethod2] called"); }
49 -(void) instanceMethod { fail("-[Super instanceMethod] called"); }
50 -(void) instanceMethod2 { fail("-[Super instanceMethod2] called"); }
51 @end
52
53 @interface WeakSuper : Super { __weak id weakIvar; } @end
54 @implementation WeakSuper @end
55
56 static int state;
57
58 static void instance_fn(id self, SEL _cmd __attribute__((unused)))
59 {
60 testassert(!class_isMetaClass(self->isa));
61 state++;
62 }
63
64 static void class_fn(id self, SEL _cmd __attribute__((unused)))
65 {
66 testassert(class_isMetaClass(self->isa));
67 state++;
68 }
69
70 static void fail_fn(id self __attribute__((unused)), SEL _cmd)
71 {
72 fail("fail_fn '%s' called", sel_getName(_cmd));
73 }
74
75 static void cycle(void)
76 {
77 Class cls;
78 BOOL ok;
79 objc_property_t prop;
80 char namebuf[256];
81
82 testassert(!objc_getClass("Sub"));
83 testassert([Super class]);
84
85 // Test subclass with bells and whistles
86
87 cls = objc_allocateClassPair([Super class], "Sub", 0);
88 testassert(cls);
89 #ifndef OBJC_NO_GC
90 if (objc_collectingEnabled()) {
91 testassert(auto_zone_size(objc_collectableZone(), cls));
92 testassert(auto_zone_size(objc_collectableZone(), cls->isa));
93 }
94 #endif
95
96 class_addMethod(cls, @selector(instanceMethod),
97 (IMP)&instance_fn, "v@:");
98 class_addMethod(cls->isa, @selector(classMethod),
99 (IMP)&class_fn, "v@:");
100 class_addMethod(cls->isa, @selector(initialize),
101 (IMP)&class_fn, "v@:");
102 class_addMethod(cls->isa, @selector(load),
103 (IMP)&fail_fn, "v@:");
104
105 ok = class_addProtocol(cls, @protocol(Proto));
106 testassert(ok);
107 ok = class_addProtocol(cls, @protocol(Proto));
108 testassert(!ok);
109
110 char attrname[2];
111 char attrvalue[2];
112 objc_property_attribute_t attrs[1];
113 unsigned int attrcount = sizeof(attrs) / sizeof(attrs[0]);
114
115 attrs[0].name = attrname;
116 attrs[0].value = attrvalue;
117 strcpy(attrname, "T");
118 strcpy(attrvalue, "x");
119
120 strcpy(namebuf, "subProp");
121 ok = class_addProperty(cls, namebuf, attrs, attrcount);
122 testassert(ok);
123 strcpy(namebuf, "subProp");
124 ok = class_addProperty(cls, namebuf, attrs, attrcount);
125 testassert(!ok);
126 strcpy(attrvalue, "i");
127 class_replaceProperty(cls, namebuf, attrs, attrcount);
128 strcpy(namebuf, "superProp");
129 ok = class_addProperty(cls, namebuf, attrs, attrcount);
130 testassert(!ok);
131 bzero(namebuf, sizeof(namebuf));
132 bzero(attrs, sizeof(attrs));
133 bzero(attrname, sizeof(attrname));
134 bzero(attrvalue, sizeof(attrvalue));
135
136 #ifndef __LP64__
137 # define size 4
138 # define align 2
139 #else
140 #define size 8
141 # define align 3
142 #endif
143
144 /*
145 {
146 int ivar;
147 id ivarid;
148 id* ivaridstar;
149 Block_t ivarblock;
150 }
151 */
152 ok = class_addIvar(cls, "ivar", 4, 2, "i");
153 testassert(ok);
154 ok = class_addIvar(cls, "ivarid", size, align, "@");
155 testassert(ok);
156 ok = class_addIvar(cls, "ivaridstar", size, align, "^@");
157 testassert(ok);
158 ok = class_addIvar(cls, "ivarblock", size, align, "@?");
159 testassert(ok);
160
161 ok = class_addIvar(cls, "ivar", 4, 2, "i");
162 testassert(!ok);
163 ok = class_addIvar(cls->isa, "classvar", 4, 2, "i");
164 testassert(!ok);
165
166 objc_registerClassPair(cls);
167
168 // should call cls's +initialize, not super's
169 super_initialize = 0;
170 state = 0;
171 [cls class];
172 testassert(super_initialize == 0);
173 testassert(state == 1);
174
175 testassert(cls == [cls class]);
176 testassert(cls == objc_getClass("Sub"));
177
178 testassert(!class_isMetaClass(cls));
179 testassert(class_isMetaClass(cls->isa));
180
181 testassert(class_getSuperclass(cls) == [Super class]);
182 testassert(class_getSuperclass(cls->isa) == [Super class]->isa);
183
184 testassert(class_getInstanceSize(cls) >= sizeof(Class) + 4 + 3*size);
185 testassert(class_conformsToProtocol(cls, @protocol(Proto)));
186
187 if (objc_collectingEnabled()) {
188 testassert(0 == strcmp((char *)class_getIvarLayout(cls), "\x01\x13"));
189 testassert(NULL == class_getWeakIvarLayout(cls));
190 }
191
192 class_addMethod(cls, @selector(instanceMethod2),
193 (IMP)&instance_fn, "v@:");
194 class_addMethod(cls->isa, @selector(classMethod2),
195 (IMP)&class_fn, "v@:");
196
197 ok = class_addIvar(cls, "ivar2", 4, 4, "i");
198 testassert(!ok);
199 ok = class_addIvar(cls->isa, "classvar2", 4, 4, "i");
200 testassert(!ok);
201
202 ok = class_addProtocol(cls, @protocol(Proto2));
203 testassert(ok);
204 ok = class_addProtocol(cls, @protocol(Proto2));
205 testassert(!ok);
206 ok = class_addProtocol(cls, @protocol(Proto));
207 testassert(!ok);
208
209 attrs[0].name = attrname;
210 attrs[0].value = attrvalue;
211 strcpy(attrname, "T");
212 strcpy(attrvalue, "i");
213
214 strcpy(namebuf, "subProp2");
215 ok = class_addProperty(cls, namebuf, attrs, attrcount);
216 testassert(ok);
217 strcpy(namebuf, "subProp");
218 ok = class_addProperty(cls, namebuf, attrs, attrcount);
219 testassert(!ok);
220 strcpy(namebuf, "superProp");
221 ok = class_addProperty(cls, namebuf, attrs, attrcount);
222 testassert(!ok);
223 bzero(namebuf, sizeof(namebuf));
224 bzero(attrs, sizeof(attrs));
225 bzero(attrname, sizeof(attrname));
226 bzero(attrvalue, sizeof(attrvalue));
227
228 prop = class_getProperty(cls, "subProp");
229 testassert(prop);
230 testassert(0 == strcmp(property_getName(prop), "subProp"));
231 testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
232 prop = class_getProperty(cls, "subProp2");
233 testassert(prop);
234 testassert(0 == strcmp(property_getName(prop), "subProp2"));
235 testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
236
237 // note: adding more methods here causes a false leak check failure
238 state = 0;
239 [cls classMethod];
240 [cls classMethod2];
241 testassert(state == 2);
242
243 id obj = [cls new];
244 state = 0;
245 [obj instanceMethod];
246 [obj instanceMethod2];
247 testassert(state == 2);
248 [obj free];
249
250 // Test ivar layouts of sub-subclass
251 Class cls2 = objc_allocateClassPair(cls, "SubSub", 0);
252 testassert(cls2);
253
254 /*
255 {
256 id ivarid2;
257 id idarray[16];
258 void* ptrarray[16];
259 char a;
260 char b;
261 char c;
262 }
263 */
264 ok = class_addIvar(cls2, "ivarid2", size, align, "@");
265 testassert(ok);
266 ok = class_addIvar(cls2, "idarray", 16*sizeof(id), align, "[16@]");
267 testassert(ok);
268 ok = class_addIvar(cls2, "ptrarray", 16*sizeof(void*), align, "[16^]");
269 testassert(ok);
270 ok = class_addIvar(cls2, "a", 1, 0, "c");
271 testassert(ok);
272 ok = class_addIvar(cls2, "b", 1, 0, "c");
273 testassert(ok);
274 ok = class_addIvar(cls2, "c", 1, 0, "c");
275 testassert(ok);
276
277 objc_registerClassPair(cls2);
278
279 if (objc_collectingEnabled()) {
280 testassert(0 == strcmp((char *)class_getIvarLayout(cls2), "\x01\x1f\x05\xf0\x10"));
281 testassert(NULL == class_getWeakIvarLayout(cls2));
282 }
283
284 // 1-byte ivars should be well packed
285 testassert(ivar_getOffset(class_getInstanceVariable(cls2, "b")) ==
286 ivar_getOffset(class_getInstanceVariable(cls2, "a")) + 1);
287 testassert(ivar_getOffset(class_getInstanceVariable(cls2, "c")) ==
288 ivar_getOffset(class_getInstanceVariable(cls2, "b")) + 1);
289
290 objc_disposeClassPair(cls2);
291
292 objc_disposeClassPair(cls);
293
294 testassert(!objc_getClass("Sub"));
295
296
297 // Test unmodified ivar layouts
298
299 cls = objc_allocateClassPair([Super class], "Sub2", 0);
300 testassert(cls);
301 objc_registerClassPair(cls);
302 if (objc_collectingEnabled()) {
303 const char *l1, *l2;
304 l1 = (char *)class_getIvarLayout([Super class]);
305 l2 = (char *)class_getIvarLayout(cls);
306 testassert(l1 == l2 || 0 == strcmp(l1, l2));
307 l1 = (char *)class_getWeakIvarLayout([Super class]);
308 l2 = (char *)class_getWeakIvarLayout(cls);
309 testassert(l1 == l2 || 0 == strcmp(l1, l2));
310 }
311 objc_disposeClassPair(cls);
312
313 cls = objc_allocateClassPair([WeakSuper class], "Sub3", 0);
314 testassert(cls);
315 objc_registerClassPair(cls);
316 if (objc_collectingEnabled()) {
317 const char *l1, *l2;
318 l1 = (char *)class_getIvarLayout([WeakSuper class]);
319 l2 = (char *)class_getIvarLayout(cls);
320 testassert(l1 == l2 || 0 == strcmp(l1, l2));
321 l1 = (char *)class_getWeakIvarLayout([WeakSuper class]);
322 l2 = (char *)class_getWeakIvarLayout(cls);
323 testassert(l1 == l2 || 0 == strcmp(l1, l2));
324 }
325 objc_disposeClassPair(cls);
326
327 // Test layout setters
328 if (objc_collectingEnabled()) {
329 cls = objc_allocateClassPair([Super class], "Sub4", 0);
330 testassert(cls);
331 class_setIvarLayout(cls, (uint8_t *)"foo");
332 class_setWeakIvarLayout(cls, NULL);
333 objc_registerClassPair(cls);
334 testassert(0 == strcmp("foo", (char *)class_getIvarLayout(cls)));
335 testassert(NULL == class_getWeakIvarLayout(cls));
336 objc_disposeClassPair(cls);
337
338 cls = objc_allocateClassPair([Super class], "Sub5", 0);
339 testassert(cls);
340 class_setIvarLayout(cls, NULL);
341 class_setWeakIvarLayout(cls, (uint8_t *)"bar");
342 objc_registerClassPair(cls);
343 testassert(NULL == class_getIvarLayout(cls));
344 testassert(0 == strcmp("bar", (char *)class_getWeakIvarLayout(cls)));
345 objc_disposeClassPair(cls);
346 }
347 }
348
349 int main()
350 {
351 int count = 1000;
352 cycle();
353 leak_mark();
354 while (count--) {
355 cycle();
356 }
357 leak_check(0);
358
359 succeed(__FILE__);
360 }