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