1 // TEST_CFLAGS -Wno-deprecated-declarations
6 #include <objc/runtime.h>
9 #include <objc/objc-auto.h>
10 #include <auto_zone.h>
14 -(void) instanceMethod;
17 -(void) instanceMethod2;
22 -(void) instanceMethod;
25 -(void) instanceMethod2;
26 +(void) classMethod_that_does_not_exist;
30 -(void) instanceMethod;
31 +(void) classMethod_that_does_not_exist;
33 -(void) instanceMethod2;
37 static int super_initialize;
39 @interface Super : TestRoot
40 @property int superProp;
44 +(void)initialize { super_initialize++; }
46 +(void) classMethod { fail("+[Super classMethod] called"); }
47 +(void) classMethod2 { fail("+[Super classMethod2] called"); }
48 -(void) instanceMethod { fail("-[Super instanceMethod] called"); }
49 -(void) instanceMethod2 { fail("-[Super instanceMethod2] called"); }
52 @interface WeakSuper : Super { __weak id weakIvar; } @end
53 @implementation WeakSuper @end
57 static void instance_fn(id self, SEL _cmd __attribute__((unused)))
59 testassert(!class_isMetaClass(object_getClass(self)));
63 static void class_fn(id self, SEL _cmd __attribute__((unused)))
65 testassert(class_isMetaClass(object_getClass(self)));
69 static void fail_fn(id self __attribute__((unused)), SEL _cmd)
71 fail("fail_fn '%s' called", sel_getName(_cmd));
75 static void cycle(void)
82 testassert(!objc_getClass("Sub"));
83 testassert([Super class]);
85 // Test subclass with bells and whistles
87 cls = objc_allocateClassPair([Super class], "Sub", 0);
90 if (objc_collectingEnabled()) {
91 testassert(auto_zone_size(objc_collectableZone(), objc_unretainedPointer(cls)));
92 testassert(auto_zone_size(objc_collectableZone(), objc_unretainedPointer(object_getClass(cls))));
96 class_addMethod(cls, @selector(instanceMethod),
97 (IMP)&instance_fn, "v@:");
98 class_addMethod(object_getClass(cls), @selector(classMethod),
99 (IMP)&class_fn, "v@:");
100 class_addMethod(object_getClass(cls), @selector(initialize),
101 (IMP)&class_fn, "v@:");
102 class_addMethod(object_getClass(cls), @selector(load),
103 (IMP)&fail_fn, "v@:");
105 ok = class_addProtocol(cls, @protocol(Proto));
107 ok = class_addProtocol(cls, @protocol(Proto));
112 objc_property_attribute_t attrs[1];
113 unsigned int attrcount = sizeof(attrs) / sizeof(attrs[0]);
115 attrs[0].name = attrname;
116 attrs[0].value = attrvalue;
117 strcpy(attrname, "T");
118 strcpy(attrvalue, "x");
120 strcpy(namebuf, "subProp");
121 ok = class_addProperty(cls, namebuf, attrs, attrcount);
123 strcpy(namebuf, "subProp");
124 ok = class_addProperty(cls, namebuf, attrs, attrcount);
126 strcpy(attrvalue, "i");
127 class_replaceProperty(cls, namebuf, attrs, attrcount);
128 strcpy(namebuf, "superProp");
129 ok = class_addProperty(cls, namebuf, attrs, attrcount);
131 bzero(namebuf, sizeof(namebuf));
132 bzero(attrs, sizeof(attrs));
133 bzero(attrname, sizeof(attrname));
134 bzero(attrvalue, sizeof(attrvalue));
152 ok = class_addIvar(cls, "ivar", 4, 2, "i");
154 ok = class_addIvar(cls, "ivarid", size, align, "@");
156 ok = class_addIvar(cls, "ivaridstar", size, align, "^@");
158 ok = class_addIvar(cls, "ivarblock", size, align, "@?");
161 ok = class_addIvar(cls, "ivar", 4, 2, "i");
163 ok = class_addIvar(object_getClass(cls), "classvar", 4, 2, "i");
166 objc_registerClassPair(cls);
168 // should call cls's +initialize, not super's
169 // Provoke +initialize using class_getMethodImplementation(class method)
170 // in order to test getNonMetaClass's slow case
171 super_initialize = 0;
173 class_getMethodImplementation(object_getClass(cls), @selector(class));
174 testassert(super_initialize == 0);
175 testassert(state == 1);
177 testassert(cls == [cls class]);
178 testassert(cls == objc_getClass("Sub"));
180 testassert(!class_isMetaClass(cls));
181 testassert(class_isMetaClass(object_getClass(cls)));
183 testassert(class_getSuperclass(cls) == [Super class]);
184 testassert(class_getSuperclass(object_getClass(cls)) == object_getClass([Super class]));
186 testassert(class_getInstanceSize(cls) >= sizeof(Class) + 4 + 3*size);
187 testassert(class_conformsToProtocol(cls, @protocol(Proto)));
189 if (objc_collectingEnabled()) {
190 testassert(0 == strcmp((char *)class_getIvarLayout(cls), "\x01\x13"));
191 testassert(NULL == class_getWeakIvarLayout(cls));
194 class_addMethod(cls, @selector(instanceMethod2),
195 (IMP)&instance_fn, "v@:");
196 class_addMethod(object_getClass(cls), @selector(classMethod2),
197 (IMP)&class_fn, "v@:");
199 ok = class_addIvar(cls, "ivar2", 4, 4, "i");
201 ok = class_addIvar(object_getClass(cls), "classvar2", 4, 4, "i");
204 ok = class_addProtocol(cls, @protocol(Proto2));
206 ok = class_addProtocol(cls, @protocol(Proto2));
208 ok = class_addProtocol(cls, @protocol(Proto));
211 attrs[0].name = attrname;
212 attrs[0].value = attrvalue;
213 strcpy(attrname, "T");
214 strcpy(attrvalue, "i");
216 strcpy(namebuf, "subProp2");
217 ok = class_addProperty(cls, namebuf, attrs, attrcount);
219 strcpy(namebuf, "subProp");
220 ok = class_addProperty(cls, namebuf, attrs, attrcount);
222 strcpy(namebuf, "superProp");
223 ok = class_addProperty(cls, namebuf, attrs, attrcount);
225 bzero(namebuf, sizeof(namebuf));
226 bzero(attrs, sizeof(attrs));
227 bzero(attrname, sizeof(attrname));
228 bzero(attrvalue, sizeof(attrvalue));
230 prop = class_getProperty(cls, "subProp");
232 testassert(0 == strcmp(property_getName(prop), "subProp"));
233 testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
234 prop = class_getProperty(cls, "subProp2");
236 testassert(0 == strcmp(property_getName(prop), "subProp2"));
237 testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
239 // note: adding more methods here causes a false leak check failure
243 testassert(state == 2);
245 // put instance tests on a separate thread so they
246 // are reliably GC'd before class destruction
250 [obj instanceMethod];
251 [obj instanceMethod2];
252 testassert(state == 2);
256 // Test ivar layouts of sub-subclass
257 Class cls2 = objc_allocateClassPair(cls, "SubSub", 0);
270 ok = class_addIvar(cls2, "ivarid2", size, align, "@");
272 ok = class_addIvar(cls2, "idarray", 16*sizeof(id), align, "[16@]");
274 ok = class_addIvar(cls2, "ptrarray", 16*sizeof(void*), align, "[16^]");
276 ok = class_addIvar(cls2, "a", 1, 0, "c");
278 ok = class_addIvar(cls2, "b", 1, 0, "c");
280 ok = class_addIvar(cls2, "c", 1, 0, "c");
283 objc_registerClassPair(cls2);
285 if (objc_collectingEnabled()) {
286 testassert(0 == strcmp((char *)class_getIvarLayout(cls2), "\x01\x1f\x05\xf0\x10"));
287 testassert(NULL == class_getWeakIvarLayout(cls2));
290 // 1-byte ivars should be well packed
291 testassert(ivar_getOffset(class_getInstanceVariable(cls2, "b")) ==
292 ivar_getOffset(class_getInstanceVariable(cls2, "a")) + 1);
293 testassert(ivar_getOffset(class_getInstanceVariable(cls2, "c")) ==
294 ivar_getOffset(class_getInstanceVariable(cls2, "b")) + 1);
296 testcollect(); // GC: finalize "obj" above before disposing its class
297 objc_disposeClassPair(cls2);
298 objc_disposeClassPair(cls);
300 testassert(!objc_getClass("Sub"));
303 // Test unmodified ivar layouts
305 cls = objc_allocateClassPair([Super class], "Sub2", 0);
307 objc_registerClassPair(cls);
308 if (objc_collectingEnabled()) {
310 l1 = (char *)class_getIvarLayout([Super class]);
311 l2 = (char *)class_getIvarLayout(cls);
312 testassert(l1 == l2 || 0 == strcmp(l1, l2));
313 l1 = (char *)class_getWeakIvarLayout([Super class]);
314 l2 = (char *)class_getWeakIvarLayout(cls);
315 testassert(l1 == l2 || 0 == strcmp(l1, l2));
317 objc_disposeClassPair(cls);
319 cls = objc_allocateClassPair([WeakSuper class], "Sub3", 0);
321 objc_registerClassPair(cls);
322 if (objc_collectingEnabled()) {
324 l1 = (char *)class_getIvarLayout([WeakSuper class]);
325 l2 = (char *)class_getIvarLayout(cls);
326 testassert(l1 == l2 || 0 == strcmp(l1, l2));
327 l1 = (char *)class_getWeakIvarLayout([WeakSuper class]);
328 l2 = (char *)class_getWeakIvarLayout(cls);
329 testassert(l1 == l2 || 0 == strcmp(l1, l2));
331 objc_disposeClassPair(cls);
333 // Test layout setters
334 if (objc_collectingEnabled()) {
335 cls = objc_allocateClassPair([Super class], "Sub4", 0);
337 class_setIvarLayout(cls, (uint8_t *)"foo");
338 class_setWeakIvarLayout(cls, NULL);
339 objc_registerClassPair(cls);
340 testassert(0 == strcmp("foo", (char *)class_getIvarLayout(cls)));
341 testassert(NULL == class_getWeakIvarLayout(cls));
342 objc_disposeClassPair(cls);
344 cls = objc_allocateClassPair([Super class], "Sub5", 0);
346 class_setIvarLayout(cls, NULL);
347 class_setWeakIvarLayout(cls, (uint8_t *)"bar");
348 objc_registerClassPair(cls);
349 testassert(NULL == class_getIvarLayout(cls));
350 testassert(0 == strcmp("bar", (char *)class_getWeakIvarLayout(cls)));
351 objc_disposeClassPair(cls);
364 testonthread(^{ cycle(); });
366 leak_check(256); // fixme should be 0