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