1#import "Testing.h" 2#import <Foundation/NSAutoreleasePool.h> 3#import <Foundation/NSException.h> 4#import <Foundation/NSDebug.h> 5#import <Foundation/NSObject.h> 6#import <Foundation/NSString.h> 7#import <Foundation/NSObjCRuntime.h> 8 9#include <string.h> 10 11#if defined(GNUSTEP) 12#import <GNUstepBase/GSObjCRuntime.h> 13#else 14#include <objc/runtime.h> 15#endif 16 17static int c1count = 0; 18static int c1initialize = 0; 19static int c1load = 0; 20 21@interface Class1 : NSObject 22{ 23 int ivar1; 24 Class1 *ivar1obj; 25} 26- (const char *) sel1; 27@end 28 29@implementation Class1 30+ (void) initialize 31{ 32 if (self == [Class1 class]) 33 c1initialize = ++c1count; 34} 35+ (void) load 36{ 37 c1load = ++c1count; 38} 39- (const char *) sel1 40{ 41 return ""; 42} 43@end 44 45@protocol SubProto 46- (const char *) sel2; 47@end 48 49@interface SubClass1 : Class1 <SubProto> 50{ 51 int ivar2; 52} 53- (const char *) sel2; 54@end 55 56@implementation SubClass1 57- (const char *) sel2 58{ 59 return ""; 60} 61@end 62 63@interface SubClass1 (Cat1) 64- (BOOL) catMethod; 65- (const char *) sel2; 66@end 67 68@implementation SubClass1 (Cat1) 69- (BOOL) catMethod 70{ 71 return YES; 72} 73- (const char *) sel2 74{ 75 return "category sel2"; 76} 77@end 78 79int 80main(int argc, char *argv[]) 81{ 82 id obj; 83 Class cls; 84 Class meta; 85 SEL sel; 86 Ivar ivar; 87 Ivar *ivars; 88 unsigned int count; 89 Method method; 90 Method *methods; 91 Protocol **protocols; 92 NSUInteger s; 93 NSUInteger a; 94 const char *t0; 95 const char *t1; 96 const char *n; 97 98 t0 = "1@1:@"; 99 t1 = NSGetSizeAndAlignment(t0, &s, &a); 100 PASS(t1 == &t0[2], "NSGetSizeAndAlignment() steps through id"); 101 t1 = NSGetSizeAndAlignment(t1, &s, &a); 102 PASS(t1 == &t0[4], "NSGetSizeAndAlignment() steps through sel"); 103 104 PASS(NO == class_isMetaClass(Nil), 105 "class_isMetaClass() returns NO for Nil"); 106 PASS(Nil == class_getSuperclass(Nil), 107 "class_getSuperclass() returns NO for Nil"); 108 109 /* NB. the OSX documentation says that the function returns an empty string 110 * when given a Nil argument, but the actual behavior on OSX 10.6 is to 111 * return the string "nil" 112 */ 113 PASS_RUNS(n = class_getName(Nil), "class_getName() for Nil does not crash") 114 PASS(n != 0 && strcmp(n, "nil") == 0, "class_getName() for Nil is nil"); 115 116 PASS(0 == class_getInstanceVariable(Nil, 0), 117 "class_getInstanceVariables() for Nil,0 is 0"); 118 PASS(0 == class_getVersion(Nil), 119 "class_getVersion() for Nil is 0"); 120 121 obj = [NSObject new]; 122 cls = [SubClass1 class]; 123 124 PASS(c1initialize != 0, "+initialize was called"); 125 PASS(c1load != 0, "+load was called"); 126 PASS(c1initialize > c1load, "+load occurs before +initialize"); 127 PASS(strcmp(class_getName(cls), "SubClass1") == 0, "class name works"); 128 PASS(YES == class_respondsToSelector(cls, @selector(sel2)), 129 "class_respondsToSelector() works for class method"); 130 PASS(YES == class_respondsToSelector(cls, @selector(sel1)), 131 "class_respondsToSelector() works for superclass method"); 132 PASS(NO == class_respondsToSelector(cls, @selector(rangeOfString:)), 133 "class_respondsToSelector() returns NO for unknown method"); 134 PASS(NO == class_respondsToSelector(cls, 0), 135 "class_respondsToSelector() returns NO for nul selector"); 136 PASS(NO == class_respondsToSelector(0, @selector(sel1)), 137 "class_respondsToSelector() returns NO for nul class"); 138 meta = object_getClass(cls); 139 PASS(class_isMetaClass(meta), "object_getClass() retrieves meta class"); 140 PASS(strcmp(class_getName(meta), "SubClass1") == 0, "metaclass name works"); 141 ivar = class_getInstanceVariable(cls, 0); 142 PASS(ivar == 0, "class_getInstanceVariable() returns 0 for null name"); 143 ivar = class_getInstanceVariable(cls, "bad name"); 144 PASS(ivar == 0, "class_getInstanceVariable() returns 0 for non-existent"); 145 ivar = class_getInstanceVariable(0, "ivar2"); 146 PASS(ivar == 0, "class_getInstanceVariable() returns 0 for Nil class"); 147 ivar = class_getInstanceVariable(cls, "ivar2"); 148 PASS(ivar != 0, "class_getInstanceVariable() works"); 149 ivar = class_getInstanceVariable(cls, "ivar1"); 150 PASS(ivar != 0, "class_getInstanceVariable() works for superclass ivar"); 151 ivar = class_getInstanceVariable(cls, "ivar1obj"); 152 PASS(ivar != 0, "class_getInstanceVariable() works for superclass obj ivar"); 153 154 methods = class_copyMethodList(cls, &count); 155 PASS(count == 3, "SubClass1 has three methods"); 156 PASS(methods[count] == 0, "method list is terminated"); 157 158 method = methods[2]; 159 sel = method_getName(method); 160 PASS(sel_isEqual(sel, sel_getUid("sel2")), 161 "last method is sel2"); 162 PASS(method_getImplementation(method) != [cls instanceMethodForSelector: sel], 163 "method 2 is the original, overridden by the category"); 164 165 method = methods[0]; 166 sel = method_getName(method); 167 PASS(sel_isEqual(sel, sel_getUid("catMethod")) 168 || sel_isEqual(sel, sel_getUid("sel2")), 169 "method 0 has expected name"); 170 171 if (sel_isEqual(sel, sel_getUid("catMethod"))) 172 { 173 method = methods[1]; 174 sel = method_getName(method); 175 PASS(sel_isEqual(sel, sel_getUid("sel2")), 176 "method 1 has expected name"); 177 PASS(method_getImplementation(method) 178 == [cls instanceMethodForSelector: sel], 179 "method 1 is the category method overriding original"); 180 } 181 else 182 { 183 PASS(method_getImplementation(method) 184 == [cls instanceMethodForSelector: sel], 185 "method 0 is the category method overriding original"); 186 method = methods[1]; 187 sel = method_getName(method); 188 PASS(sel_isEqual(sel, sel_getUid("catMethod")), 189 "method 1 has expected name"); 190 } 191 192 ivars = class_copyIvarList(cls, &count); 193 PASS(count == 1, "SubClass1 has one ivar"); 194 PASS(ivars[count] == 0, "ivar list is terminated"); 195 PASS(strcmp(ivar_getName(ivars[0]), "ivar2") == 0, 196 "ivar has correct name"); 197 PASS(strcmp(ivar_getTypeEncoding(ivars[0]), @encode(int)) == 0, 198 "ivar has correct type"); 199 200 protocols = class_copyProtocolList(cls, &count); 201 PASS(count == 1, "SubClass1 has one protocol"); 202 PASS(protocols[count] == 0, "protocol list is terminated"); 203 PASS(strcmp(protocol_getName(protocols[0]), "SubProto") == 0, 204 "protocol has correct name"); 205 206 cls = objc_allocateClassPair([NSString class], "runtime generated", 0); 207 PASS(cls != Nil, "can allocate a class pair"); 208 PASS(class_addIvar(cls, "iv1", 1, 6, "c") == YES, 209 "able to add iVar 'iv1'"); 210 PASS(class_addIvar(cls, "iv2", 1, 5, "c") == YES, 211 "able to add iVar 'iv2'"); 212 PASS(class_addIvar(cls, "iv3", 1, 4, "c") == YES, 213 "able to add iVar 'iv3'"); 214 PASS(class_addIvar(cls, "iv4", 1, 3, "c") == YES, 215 "able to add iVar 'iv4'"); 216 objc_registerClassPair (cls); 217 ivar = class_getInstanceVariable(cls, "iv1"); 218 PASS(ivar != 0, "iv1 exists"); 219 PASS(ivar_getOffset(ivar) == 64, "iv1 offset is 64"); 220 ivar = class_getInstanceVariable(cls, "iv2"); 221 PASS(ivar != 0, "iv2 exists"); 222 PASS(ivar_getOffset(ivar) == 96, "iv2 offset is 96"); 223 ivar = class_getInstanceVariable(cls, "iv3"); 224 PASS(ivar != 0, "iv3 exists"); 225 PASS(ivar_getOffset(ivar) == 112, "iv3 offset is 112"); 226 ivar = class_getInstanceVariable(cls, "iv4"); 227 PASS(ivar != 0, "iv4 exists"); 228 PASS(ivar_getOffset(ivar) == 120, "iv4 offset is 120"); 229 230 /* NSObjCRuntime function tests. 231 */ 232 sel = NSSelectorFromString(nil); 233 PASS(sel == 0, 234 "NSSelectorFromString() returns 0 for nil string"); 235 PASS(NSStringFromSelector(0) == nil, 236 "NSStringFromSelector() returns nil for null selector"); 237 sel = NSSelectorFromString(@"xxxyyy_odd_name_xxxyyy"); 238 PASS(sel != 0, 239 "NSSelectorFromString() creates for non-existent selector"); 240 PASS([NSStringFromSelector(sel) isEqual: @"xxxyyy_odd_name_xxxyyy"], 241 "NSStringFromSelector() works for existing selector"); 242 243 return 0; 244} 245 246