]> git.saurik.com Git - apple/objc4.git/blob - test/initialize.m
objc4-781.tar.gz
[apple/objc4.git] / test / initialize.m
1 // TEST_CONFIG
2
3 // initialize.m
4 // Test basic +initialize behavior
5 // * +initialize before class method
6 // * superclass +initialize before subclass +initialize
7 // * subclass inheritance of superclass implementation
8 // * messaging during +initialize
9 // * +initialize provoked by class_getMethodImplementation
10 // * +initialize not provoked by objc_getClass
11 #include "test.h"
12 #include "testroot.i"
13
14 int state = 0;
15
16 @interface Super0 : TestRoot @end
17 @implementation Super0
18 +(void)initialize {
19 fail("objc_getClass() must not trigger +initialize");
20 }
21 @end
22
23 @interface Super : TestRoot @end
24 @implementation Super
25 +(void)initialize {
26 testprintf("in [Super initialize]\n");
27 testassert(state == 0);
28 state = 1;
29 }
30 +(void)method {
31 fail("[Super method] shouldn't be called");
32 }
33 @end
34
35 @interface Sub : Super @end
36 @implementation Sub
37 +(void)initialize {
38 testprintf("in [Sub initialize]\n");
39 testassert(state == 1);
40 state = 2;
41 }
42 +(void)method {
43 testprintf("in [Sub method]\n");
44 testassert(state == 2);
45 state = 3;
46 }
47 @end
48
49
50 @interface Super2 : TestRoot @end
51 @interface Sub2 : Super2 @end
52
53 @implementation Super2
54 +(void)initialize {
55 if (self == objc_getClass("Sub2")) {
56 testprintf("in [Super2 initialize] of Sub2\n");
57 testassert(state == 1);
58 state = 2;
59 } else if (self == objc_getClass("Super2")) {
60 testprintf("in [Super2 initialize] of Super2\n");
61 testassert(state == 0);
62 state = 1;
63 } else {
64 fail("in [Super2 initialize] of unknown class");
65 }
66 }
67 +(void)method {
68 testprintf("in [Super2 method]\n");
69 testassert(state == 2);
70 state = 3;
71 }
72 @end
73
74 @implementation Sub2
75 // nothing here
76 @end
77
78
79 @interface Super3 : TestRoot @end
80 @interface Sub3 : Super3 @end
81
82 @implementation Super3
83 +(void)initialize {
84 if (self == [Sub3 class]) { // this message triggers [Sub3 initialize]
85 testprintf("in [Super3 initialize] of Sub3\n");
86 testassert(state == 0);
87 state = 1;
88 } else if (self == [Super3 class]) {
89 testprintf("in [Super3 initialize] of Super3\n");
90 testassert(state == 1);
91 state = 2;
92 } else {
93 fail("in [Super3 initialize] of unknown class");
94 }
95 }
96 +(void)method {
97 testprintf("in [Super3 method]\n");
98 testassert(state == 2);
99 state = 3;
100 }
101 @end
102
103 @implementation Sub3
104 // nothing here
105 @end
106
107
108 @interface Super4 : TestRoot @end
109 @implementation Super4
110 -(void)instanceMethod {
111 testassert(state == 1);
112 state = 2;
113 }
114 +(void)initialize {
115 testprintf("in [Super4 initialize]\n");
116 testassert(state == 0);
117 state = 1;
118 id x = [[self alloc] init];
119 [x instanceMethod];
120 RELEASE_VALUE(x);
121 }
122 @end
123
124
125 @interface Super5 : TestRoot @end
126 @implementation Super5
127 -(void)instanceMethod {
128 }
129 +(void)classMethod {
130 testassert(state == 1);
131 state = 2;
132 }
133 +(void)initialize {
134 testprintf("in [Super5 initialize]\n");
135 testassert(state == 0);
136 state = 1;
137 class_getMethodImplementation(self, @selector(instanceMethod));
138 // this is the "memoized" case for getNonMetaClass
139 class_getMethodImplementation(object_getClass(self), @selector(classMethod));
140 [self classMethod];
141 }
142 @end
143
144
145 @interface Super6 : TestRoot @end
146 @interface Sub6 : Super6 @end
147 @implementation Super6
148 +(void)initialize {
149 static bool once;
150 bool wasOnce;
151 testprintf("in [Super6 initialize] (#%d)\n", 1+(int)once);
152 if (!once) {
153 once = true;
154 wasOnce = true;
155 testassert(state == 0);
156 state = 1;
157 } else {
158 wasOnce = false;
159 testassert(state == 2);
160 state = 3;
161 }
162 [Sub6 class];
163 if (wasOnce) {
164 testassert(state == 5);
165 state = 6;
166 } else {
167 testassert(state == 3);
168 state = 4;
169 }
170 }
171 @end
172 @implementation Sub6
173 +(void)initialize {
174 testprintf("in [Sub6 initialize]\n");
175 testassert(state == 1);
176 state = 2;
177 [super initialize];
178 testassert(state == 4);
179 state = 5;
180 }
181 @end
182
183
184 @interface Super7 : TestRoot @end
185 @interface Sub7 : Super7 @end
186 @implementation Super7
187 +(void)initialize {
188 static bool once;
189 bool wasOnce;
190 testprintf("in [Super7 initialize] (#%d)\n", 1+(int)once);
191 if (!once) {
192 once = true;
193 wasOnce = true;
194 testassert(state == 0);
195 state = 1;
196 } else {
197 wasOnce = false;
198 testassert(state == 2);
199 state = 3;
200 }
201 [Sub7 class];
202 if (wasOnce) {
203 testassert(state == 5);
204 state = 6;
205 } else {
206 testassert(state == 3);
207 state = 4;
208 }
209 }
210 @end
211 @implementation Sub7
212 +(void)initialize {
213 testprintf("in [Sub7 initialize]\n");
214 testassert(state == 1);
215 state = 2;
216 [super initialize];
217 testassert(state == 4);
218 state = 5;
219 }
220 @end
221
222
223
224 @interface SuperThrower : TestRoot @end
225 @implementation SuperThrower
226 +(void)initialize {
227 testprintf("in [SuperThrower initialize]\n");
228 testassert(state == 0);
229 state = 10;
230 @throw AUTORELEASE([TestRoot new]);
231 fail("@throw didn't throw");
232 }
233 @end
234
235 @interface SubThrower : SuperThrower @end
236 @implementation SubThrower
237 +(void)initialize {
238 testprintf("in [SubThrower initialize]\n");
239 testassert(state == 0);
240 state = 20;
241 }
242 @end
243
244 int main()
245 {
246 Class cls;
247
248 // objc_getClass() must not +initialize anything
249 state = 0;
250 objc_getClass("Super0");
251 testassert(state == 0);
252
253 // initialize superclass, then subclass
254 state = 0;
255 [Sub method];
256 testassert(state == 3);
257
258 // check subclass's inheritance of superclass initialize
259 state = 0;
260 [Sub2 method];
261 testassert(state == 3);
262
263 // check subclass method called from superclass initialize
264 state = 0;
265 [Sub3 method];
266 testassert(state == 3);
267
268 // check class_getMethodImplementation (instance method)
269 state = 0;
270 cls = objc_getClass("Super4");
271 testassert(state == 0);
272 class_getMethodImplementation(cls, @selector(classMethod));
273 testassert(state == 2);
274
275 // check class_getMethodImplementation (class method)
276 // this is the "slow" case for getNonMetaClass
277 state = 0;
278 cls = objc_getClass("Super5");
279 testassert(state == 0);
280 class_getMethodImplementation(object_getClass(cls), @selector(instanceMethod));
281 testassert(state == 2);
282
283 // check +initialize cycles
284 // this is the "cls is a subclass" case for getNonMetaClass
285 state = 0;
286 [Super6 class];
287 testassert(state == 6);
288
289 // check +initialize cycles
290 // this is the "cls is a subclass" case for getNonMetaClass
291 state = 0;
292 [Sub7 class];
293 testassert(state == 6);
294
295 // exception from +initialize must be handled cleanly
296 PUSH_POOL {
297 alarm(3);
298 testonthread( ^{
299 @try {
300 state = 0;
301 [SuperThrower class];
302 fail("where's the beef^Wexception?");
303 } @catch (...) {
304 testassert(state == 10);
305 state = 11;
306 }
307 testassert(state == 11);
308 });
309 @try {
310 state = 0;
311 [SuperThrower class];
312 testassert(state == 0);
313 [SubThrower class];
314 testassert(state == 20);
315 } @catch (...) {
316 fail("+initialize called again after exception");
317 }
318 } POP_POOL;
319
320 succeed(__FILE__);
321
322 return 0;
323 }