]> git.saurik.com Git - apple/objc4.git/blob - test/classpair.m
objc4-756.2.tar.gz
[apple/objc4.git] / test / classpair.m
1 // TEST_CONFIG
2
3 #include "test.h"
4
5 #include "testroot.i"
6 #include <objc/runtime.h>
7 #include <string.h>
8
9 @protocol Proto
10 -(void) instanceMethod;
11 +(void) classMethod;
12 @optional
13 -(void) instanceMethod2;
14 +(void) classMethod2;
15 @end
16
17 @protocol Proto2
18 -(void) instanceMethod;
19 +(void) classMethod;
20 @optional
21 -(void) instanceMethod2;
22 +(void) classMethod_that_does_not_exist;
23 @end
24
25 @protocol Proto3
26 -(void) instanceMethod;
27 +(void) classMethod_that_does_not_exist;
28 @optional
29 -(void) instanceMethod2;
30 +(void) classMethod2;
31 @end
32
33 static int super_initialize;
34
35 @interface Super : TestRoot
36 @property int superProp;
37 @end
38 @implementation Super
39 @dynamic superProp;
40 +(void)initialize { super_initialize++; }
41
42 +(void) classMethod { fail("+[Super classMethod] called"); }
43 +(void) classMethod2 { fail("+[Super classMethod2] called"); }
44 -(void) instanceMethod { fail("-[Super instanceMethod] called"); }
45 -(void) instanceMethod2 { fail("-[Super instanceMethod2] called"); }
46 @end
47
48 static int state;
49
50 static void instance_fn(id self, SEL _cmd __attribute__((unused)))
51 {
52 testassert(!class_isMetaClass(object_getClass(self)));
53 state++;
54 }
55
56 static void class_fn(id self, SEL _cmd __attribute__((unused)))
57 {
58 testassert(class_isMetaClass(object_getClass(self)));
59 state++;
60 }
61
62 static void fail_fn(id self __attribute__((unused)), SEL _cmd)
63 {
64 fail("fail_fn '%s' called", sel_getName(_cmd));
65 }
66
67
68 static void cycle(void)
69 {
70 Class cls;
71 BOOL ok;
72 objc_property_t prop;
73 char namebuf[256];
74
75 testassert(!objc_getClass("Sub"));
76 testassert([Super class]);
77
78 // Test subclass with bells and whistles
79
80 cls = objc_allocateClassPair([Super class], "Sub", 0);
81 testassert(cls);
82
83 class_addMethod(cls, @selector(instanceMethod),
84 (IMP)&instance_fn, "v@:");
85 class_addMethod(object_getClass(cls), @selector(classMethod),
86 (IMP)&class_fn, "v@:");
87 class_addMethod(object_getClass(cls), @selector(initialize),
88 (IMP)&class_fn, "v@:");
89 class_addMethod(object_getClass(cls), @selector(load),
90 (IMP)&fail_fn, "v@:");
91
92 ok = class_addProtocol(cls, @protocol(Proto));
93 testassert(ok);
94 ok = class_addProtocol(cls, @protocol(Proto));
95 testassert(!ok);
96
97 char attrname[2];
98 char attrvalue[2];
99 objc_property_attribute_t attrs[1];
100 unsigned int attrcount = sizeof(attrs) / sizeof(attrs[0]);
101
102 attrs[0].name = attrname;
103 attrs[0].value = attrvalue;
104 strcpy(attrname, "T");
105 strcpy(attrvalue, "x");
106
107 strcpy(namebuf, "subProp");
108 ok = class_addProperty(cls, namebuf, attrs, attrcount);
109 testassert(ok);
110 strcpy(namebuf, "subProp");
111 ok = class_addProperty(cls, namebuf, attrs, attrcount);
112 testassert(!ok);
113 strcpy(attrvalue, "i");
114 class_replaceProperty(cls, namebuf, attrs, attrcount);
115 strcpy(namebuf, "superProp");
116 ok = class_addProperty(cls, namebuf, attrs, attrcount);
117 testassert(!ok);
118 bzero(namebuf, sizeof(namebuf));
119 bzero(attrs, sizeof(attrs));
120 bzero(attrname, sizeof(attrname));
121 bzero(attrvalue, sizeof(attrvalue));
122
123 #ifndef __LP64__
124 # define size 4
125 # define align 2
126 #else
127 #define size 8
128 # define align 3
129 #endif
130
131 /*
132 {
133 int ivar;
134 id ivarid;
135 id* ivaridstar;
136 Block_t ivarblock;
137 }
138 */
139 ok = class_addIvar(cls, "ivar", 4, 2, "i");
140 testassert(ok);
141 ok = class_addIvar(cls, "ivarid", size, align, "@");
142 testassert(ok);
143 ok = class_addIvar(cls, "ivaridstar", size, align, "^@");
144 testassert(ok);
145 ok = class_addIvar(cls, "ivarblock", size, align, "@?");
146 testassert(ok);
147
148 ok = class_addIvar(cls, "ivar", 4, 2, "i");
149 testassert(!ok);
150 ok = class_addIvar(object_getClass(cls), "classvar", 4, 2, "i");
151 testassert(!ok);
152
153 objc_registerClassPair(cls);
154
155 // should call cls's +initialize, not super's
156 // Provoke +initialize using class_getMethodImplementation(class method)
157 // in order to test getNonMetaClass's slow case
158 super_initialize = 0;
159 state = 0;
160 class_getMethodImplementation(object_getClass(cls), @selector(class));
161 testassert(super_initialize == 0);
162 testassert(state == 1);
163
164 testassert(cls == [cls class]);
165 testassert(cls == objc_getClass("Sub"));
166
167 testassert(!class_isMetaClass(cls));
168 testassert(class_isMetaClass(object_getClass(cls)));
169
170 testassert(class_getSuperclass(cls) == [Super class]);
171 testassert(class_getSuperclass(object_getClass(cls)) == object_getClass([Super class]));
172
173 testassert(class_getInstanceSize(cls) >= sizeof(Class) + 4 + 3*size);
174 testassert(class_conformsToProtocol(cls, @protocol(Proto)));
175
176 class_addMethod(cls, @selector(instanceMethod2),
177 (IMP)&instance_fn, "v@:");
178 class_addMethod(object_getClass(cls), @selector(classMethod2),
179 (IMP)&class_fn, "v@:");
180
181 ok = class_addIvar(cls, "ivar2", 4, 4, "i");
182 testassert(!ok);
183 ok = class_addIvar(object_getClass(cls), "classvar2", 4, 4, "i");
184 testassert(!ok);
185
186 ok = class_addProtocol(cls, @protocol(Proto2));
187 testassert(ok);
188 ok = class_addProtocol(cls, @protocol(Proto2));
189 testassert(!ok);
190 ok = class_addProtocol(cls, @protocol(Proto));
191 testassert(!ok);
192
193 attrs[0].name = attrname;
194 attrs[0].value = attrvalue;
195 strcpy(attrname, "T");
196 strcpy(attrvalue, "i");
197
198 strcpy(namebuf, "subProp2");
199 ok = class_addProperty(cls, namebuf, attrs, attrcount);
200 testassert(ok);
201 strcpy(namebuf, "subProp");
202 ok = class_addProperty(cls, namebuf, attrs, attrcount);
203 testassert(!ok);
204 strcpy(namebuf, "superProp");
205 ok = class_addProperty(cls, namebuf, attrs, attrcount);
206 testassert(!ok);
207 bzero(namebuf, sizeof(namebuf));
208 bzero(attrs, sizeof(attrs));
209 bzero(attrname, sizeof(attrname));
210 bzero(attrvalue, sizeof(attrvalue));
211
212 prop = class_getProperty(cls, "subProp");
213 testassert(prop);
214 testassert(0 == strcmp(property_getName(prop), "subProp"));
215 testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
216 prop = class_getProperty(cls, "subProp2");
217 testassert(prop);
218 testassert(0 == strcmp(property_getName(prop), "subProp2"));
219 testassert(0 == strcmp(property_getAttributes(prop), "Ti"));
220
221 // note: adding more methods here causes a false leak check failure
222 state = 0;
223 [cls classMethod];
224 [cls classMethod2];
225 testassert(state == 2);
226
227 // put instance tests on a separate thread so they
228 // are reliably deallocated before class destruction
229 testonthread(^{
230 id obj = [cls new];
231 state = 0;
232 [obj instanceMethod];
233 [obj instanceMethod2];
234 testassert(state == 2);
235 RELEASE_VAR(obj);
236 });
237
238 // Test ivar layouts of sub-subclass
239 Class cls2 = objc_allocateClassPair(cls, "SubSub", 0);
240 testassert(cls2);
241
242 /*
243 {
244 id ivarid2;
245 id idarray[16];
246 void* ptrarray[16];
247 char a;
248 char b;
249 char c;
250 }
251 */
252 ok = class_addIvar(cls2, "ivarid2", size, align, "@");
253 testassert(ok);
254 ok = class_addIvar(cls2, "idarray", 16*sizeof(id), align, "[16@]");
255 testassert(ok);
256 ok = class_addIvar(cls2, "ptrarray", 16*sizeof(void*), align, "[16^]");
257 testassert(ok);
258 ok = class_addIvar(cls2, "a", 1, 0, "c");
259 testassert(ok);
260 ok = class_addIvar(cls2, "b", 1, 0, "c");
261 testassert(ok);
262 ok = class_addIvar(cls2, "c", 1, 0, "c");
263 testassert(ok);
264
265 objc_registerClassPair(cls2);
266
267 // 1-byte ivars should be well packed
268 testassert(ivar_getOffset(class_getInstanceVariable(cls2, "b")) ==
269 ivar_getOffset(class_getInstanceVariable(cls2, "a")) + 1);
270 testassert(ivar_getOffset(class_getInstanceVariable(cls2, "c")) ==
271 ivar_getOffset(class_getInstanceVariable(cls2, "b")) + 1);
272
273 objc_disposeClassPair(cls2);
274 objc_disposeClassPair(cls);
275
276 testassert(!objc_getClass("Sub"));
277
278 // fixme test layout setters
279 }
280
281 int main()
282 {
283 int count = 5000;
284
285 // fixme even with this long warmup we still
286 // suffer false 4096-byte leaks occasionally.
287 for (int i = 0; i < 500; i++) {
288 testonthread(^{ cycle(); });
289 }
290
291 leak_mark();
292 while (count--) {
293 testonthread(^{ cycle(); });
294 }
295 leak_check(4096);
296
297 succeed(__FILE__);
298 }
299