]> git.saurik.com Git - apple/objc4.git/blob - test/initialize.m
objc4-680.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 int main()
224 {
225 Class cls;
226
227 // objc_getClass() must not +initialize anything
228 state = 0;
229 objc_getClass("Super0");
230 testassert(state == 0);
231
232 // initialize superclass, then subclass
233 state = 0;
234 [Sub method];
235 testassert(state == 3);
236
237 // check subclass's inheritance of superclass initialize
238 state = 0;
239 [Sub2 method];
240 testassert(state == 3);
241
242 // check subclass method called from superclass initialize
243 state = 0;
244 [Sub3 method];
245 testassert(state == 3);
246
247 // check class_getMethodImplementation (instance method)
248 state = 0;
249 cls = objc_getClass("Super4");
250 testassert(state == 0);
251 class_getMethodImplementation(cls, @selector(classMethod));
252 testassert(state == 2);
253
254 // check class_getMethodImplementation (class method)
255 // this is the "slow" case for getNonMetaClass
256 state = 0;
257 cls = objc_getClass("Super5");
258 testassert(state == 0);
259 class_getMethodImplementation(object_getClass(cls), @selector(instanceMethod));
260 testassert(state == 2);
261
262 // check +initialize cycles
263 // this is the "cls is a subclass" case for getNonMetaClass
264 state = 0;
265 [Super6 class];
266 testassert(state == 6);
267
268 // check +initialize cycles
269 // this is the "cls is a subclass" case for getNonMetaClass
270 state = 0;
271 [Sub7 class];
272 testassert(state == 6);
273
274 succeed(__FILE__);
275
276 return 0;
277 }