1// See instructions in weak.h
2
3#include "test.h"
4#include "weak.h"
5
6// Subclass of superclass that isn't there
7@interface MyMissingSuper : MissingSuper
8+(int) method;
9@end
10@implementation MyMissingSuper
11+(int) method { return 1+[super method]; }
12+(void) load { state++; }
13@end
14
15// Subclass of subclass of superclass that isn't there
16@interface MyMissingSub : MyMissingSuper
17+(int) method;
18@end
19@implementation MyMissingSub
20+(int) method { return 1+[super method]; }
21+(void) load { state++; }
22@end
23
24// Subclass of real superclass 
25@interface MyNotMissingSuper : NotMissingSuper
26+(int) method;
27@end
28@implementation MyNotMissingSuper
29+(int) method { return 1+[super method]; }
30+(void) load { state++; }
31@end
32
33// Subclass of subclass of superclass that isn't there
34@interface MyNotMissingSub : MyNotMissingSuper
35+(int) method;
36@end
37@implementation MyNotMissingSub
38+(int) method { return 1+[super method]; }
39+(void) load { state++; }
40@end
41
42// Categories on all of the above
43@interface MissingRoot (MissingRootExtras)
44+(void)load;
45+(int) cat_method;
46@end
47@implementation MissingRoot (MissingRootExtras)
48+(void)load { state++; }
49+(int) cat_method { return 40; }
50@end
51
52@interface MissingSuper (MissingSuperExtras)
53+(void)load;
54+(int) cat_method;
55@end
56@implementation MissingSuper (MissingSuperExtras)
57+(void)load { state++; }
58+(int) cat_method { return 1+[super cat_method]; }
59@end
60
61@interface MyMissingSuper (MyMissingSuperExtras)
62+(void)load;
63+(int) cat_method;
64@end
65@implementation MyMissingSuper (MyMissingSuperExtras)
66+(void)load { state++; }
67+(int) cat_method { return 1+[super cat_method]; }
68@end
69
70@interface MyMissingSub (MyMissingSubExtras)
71+(void)load;
72+(int) cat_method;
73@end
74@implementation MyMissingSub (MyMissingSubExtras)
75+(void)load { state++; }
76+(int) cat_method { return 1+[super cat_method]; }
77@end
78
79
80@interface NotMissingRoot (NotMissingRootExtras)
81+(void)load;
82+(int) cat_method;
83@end
84@implementation NotMissingRoot (NotMissingRootExtras)
85+(void)load { state++; }
86+(int) cat_method { return 30; }
87@end
88
89@interface NotMissingSuper (NotMissingSuperExtras)
90+(void)load;
91+(int) cat_method;
92@end
93@implementation NotMissingSuper (NotMissingSuperExtras)
94+(void)load { state++; }
95+(int) cat_method { return 1+[super cat_method]; }
96@end
97
98@interface MyNotMissingSuper (MyNotMissingSuperExtras)
99+(void)load;
100+(int) cat_method;
101@end
102@implementation MyNotMissingSuper (MyNotMissingSuperExtras)
103+(void)load { state++; }
104+(int) cat_method { return 1+[super cat_method]; }
105@end
106
107@interface MyNotMissingSub (MyNotMissingSubExtras)
108+(void)load;
109+(int) cat_method;
110@end
111@implementation MyNotMissingSub (MyNotMissingSubExtras)
112+(void)load { state++; }
113+(int) cat_method { return 1+[super cat_method]; }
114@end
115
116
117#if WEAK_FRAMEWORK
118#   define TESTIVAR(cond) testassert(cond)
119#else
120#   define TESTIVAR(cond) /* rdar */
121#endif
122
123static BOOL classInList(__unsafe_unretained Class classes[], const char *name)
124{
125    for (int i = 0; classes[i] != nil; i++) {
126        if (0 == strcmp(class_getName(classes[i]), name)) return YES;
127    }
128    return NO;
129}
130
131static BOOL classInNameList(const char **names, const char *name)
132{
133    const char **cp;
134    for (cp = names; *cp; cp++) {
135        if (0 == strcmp(*cp, name)) return YES;
136    }
137    return NO;
138}
139
140int main(int argc __unused, char **argv)
141{
142    BOOL weakMissing;
143    if (strstr(argv[0], "-not-missing.out")) {
144        weakMissing = NO;
145    } else if (strstr(argv[0], "-missing.out")) {
146        weakMissing = YES;
147    } else {
148        fail("executable name must be weak*-missing.out or weak*-not-missing.out");
149    }
150
151    // class and category +load methods
152    if (weakMissing) testassert(state == 8);
153    else testassert(state == 16);
154    state = 0;
155
156    // classes
157    testassert([NotMissingRoot class]);
158    testassert([NotMissingSuper class]);
159    testassert([MyNotMissingSuper class]);
160    testassert([MyNotMissingSub class]);
161    if (weakMissing) {
162        testassert([MissingRoot class] == nil);
163        testassert([MissingSuper class] == nil);
164        testassert([MyMissingSuper class] == nil);
165        testassert([MyMissingSub class] == nil);
166    } else {
167        testassert([MissingRoot class]);
168        testassert([MissingSuper class]);
169        testassert([MyMissingSuper class]);
170        testassert([MyMissingSub class]);
171    }
172    
173    // objc_getClass
174    testassert(objc_getClass("NotMissingRoot"));
175    testassert(objc_getClass("NotMissingSuper"));
176    testassert(objc_getClass("MyNotMissingSuper"));
177    testassert(objc_getClass("MyNotMissingSub"));
178    if (weakMissing) {
179        testassert(objc_getClass("MissingRoot") == nil);
180        testassert(objc_getClass("MissingSuper") == nil);
181        testassert(objc_getClass("MyMissingSuper") == nil);
182        testassert(objc_getClass("MyMissingSub") == nil);
183    } else {
184        testassert(objc_getClass("MissingRoot"));
185        testassert(objc_getClass("MissingSuper"));
186        testassert(objc_getClass("MyMissingSuper"));
187        testassert(objc_getClass("MyMissingSub"));
188    }
189
190    // class list
191    union {
192        Class *c;
193        void *v;
194    } classes;
195    classes.c = objc_copyClassList(NULL);
196    testassert(classInList(classes.c, "NotMissingRoot"));
197    testassert(classInList(classes.c, "NotMissingSuper"));
198    testassert(classInList(classes.c, "MyNotMissingSuper"));
199    testassert(classInList(classes.c, "MyNotMissingSub"));
200    if (weakMissing) {
201        testassert(! classInList(classes.c, "MissingRoot"));
202        testassert(! classInList(classes.c, "MissingSuper"));
203        testassert(! classInList(classes.c, "MyMissingSuper"));
204        testassert(! classInList(classes.c, "MyMissingSub"));
205    } else {
206        testassert(classInList(classes.c, "MissingRoot"));
207        testassert(classInList(classes.c, "MissingSuper"));
208        testassert(classInList(classes.c, "MyMissingSuper"));
209        testassert(classInList(classes.c, "MyMissingSub"));
210    }
211    free(classes.v);
212
213    // class name list
214    const char *image = class_getImageName(objc_getClass("NotMissingRoot"));
215    testassert(image);
216    const char **names = objc_copyClassNamesForImage(image, NULL);
217    testassert(names);
218    testassert(classInNameList(names, "NotMissingRoot"));
219    testassert(classInNameList(names, "NotMissingSuper"));
220    if (weakMissing) {
221        testassert(! classInNameList(names, "MissingRoot"));
222        testassert(! classInNameList(names, "MissingSuper"));
223    } else {
224        testassert(classInNameList(names, "MissingRoot"));
225        testassert(classInNameList(names, "MissingSuper"));
226    }
227    free(names);
228
229    image = class_getImageName(objc_getClass("MyNotMissingSub"));
230    testassert(image);
231    names = objc_copyClassNamesForImage(image, NULL);
232    testassert(names);
233    testassert(classInNameList(names, "MyNotMissingSuper"));
234    testassert(classInNameList(names, "MyNotMissingSub"));
235    if (weakMissing) {
236        testassert(! classInNameList(names, "MyMissingSuper"));
237        testassert(! classInNameList(names, "MyMissingSub"));
238    } else {
239        testassert(classInNameList(names, "MyMissingSuper"));
240        testassert(classInNameList(names, "MyMissingSub"));
241    }
242    free(names);
243    
244    // methods
245    testassert(20 == [NotMissingRoot method]);
246    testassert(21 == [NotMissingSuper method]);
247    testassert(22 == [MyNotMissingSuper method]);
248    testassert(23 == [MyNotMissingSub method]);
249    if (weakMissing) {
250        testassert(0 == [MissingRoot method]);
251        testassert(0 == [MissingSuper method]);
252        testassert(0 == [MyMissingSuper method]);
253        testassert(0 == [MyMissingSub method]);
254    } else {
255        testassert(10 == [MissingRoot method]);
256        testassert(11 == [MissingSuper method]);
257        testassert(12 == [MyMissingSuper method]);
258        testassert(13 == [MyMissingSub method]);
259    }
260    
261    // category methods
262    testassert(30 == [NotMissingRoot cat_method]);
263    testassert(31 == [NotMissingSuper cat_method]);
264    testassert(32 == [MyNotMissingSuper cat_method]);
265    testassert(33 == [MyNotMissingSub cat_method]);
266    if (weakMissing) {
267        testassert(0 == [MissingRoot cat_method]);
268        testassert(0 == [MissingSuper cat_method]);
269        testassert(0 == [MyMissingSuper cat_method]);
270        testassert(0 == [MyMissingSub cat_method]);
271    } else {
272        testassert(40 == [MissingRoot cat_method]);
273        testassert(41 == [MissingSuper cat_method]);
274        testassert(42 == [MyMissingSuper cat_method]);
275        testassert(43 == [MyMissingSub cat_method]);
276    }
277
278    // allocations and ivars
279    id obj;
280    NotMissingSuper *obj2;
281    MissingSuper *obj3;
282    testassert((obj = [[NotMissingRoot alloc] init])); 
283    RELEASE_VAR(obj);
284    testassert((obj2 = [[NotMissingSuper alloc] init]));
285    TESTIVAR(obj2->ivar == 200); 
286    RELEASE_VAR(obj2);
287    testassert((obj2 = [[MyNotMissingSuper alloc] init]));
288    TESTIVAR(obj2->ivar == 200); 
289    RELEASE_VAR(obj2);
290    testassert((obj2 = [[MyNotMissingSub alloc] init]));
291    TESTIVAR(obj2->ivar == 200); 
292    RELEASE_VAR(obj2);
293    if (weakMissing) {
294        testassert([[MissingRoot alloc] init] == nil);
295        testassert([[MissingSuper alloc] init] == nil);
296        testassert([[MyMissingSuper alloc] init] == nil);
297        testassert([[MyMissingSub alloc] init] == nil);
298    } else {
299        testassert((obj = [[MissingRoot alloc] init])); 
300        RELEASE_VAR(obj);
301        testassert((obj3 = [[MissingSuper alloc] init])); 
302        TESTIVAR(obj3->ivar == 100); 
303        RELEASE_VAR(obj3);
304        testassert((obj3 = [[MyMissingSuper alloc] init])); 
305        TESTIVAR(obj3->ivar == 100); 
306        RELEASE_VAR(obj3);
307        testassert((obj3 = [[MyMissingSub alloc] init])); 
308        TESTIVAR(obj3->ivar == 100); 
309        RELEASE_VAR(obj3);
310    }
311
312    *strrchr(argv[0], '.') = 0;
313    succeed(basename(argv[0]));
314    return 0;
315}
316
317