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
14int 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
223int 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}
278