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