1/*
2TEST_BUILD
3    $C{COMPILE} $DIR/future0.m -o future0.dylib -dynamiclib
4    $C{COMPILE} $DIR/future2.m -x none future0.dylib -o future2.dylib -dynamiclib
5    $C{COMPILE} $DIR/future.m -x none future0.dylib -o future.out
6END
7*/
8
9#include "test.h"
10
11#if __has_feature(objc_arc)
12
13int main()
14{
15    testwarn("rdar://10041403 future class API is not ARC-compatible");
16    succeed(__FILE__);
17}
18
19
20#else
21
22#include <objc/runtime.h>
23#include <malloc/malloc.h>
24#include <string.h>
25#include <dlfcn.h>
26#include "future.h"
27
28@implementation Sub2
29+(int)method {
30    return 2;
31}
32+(Class)classref {
33    return [Sub2 class];
34}
35@end
36
37@implementation SubSub2
38+(int)method {
39    return 1 + [super method];
40}
41@end
42
43int main()
44{
45    Class oldTestRoot;
46    Class oldSub1;
47    Class newSub1;
48#if !__OBJC2__
49    Class oldSub2;
50    Class newSub2;
51    uintptr_t buf[20];
52#endif
53
54    // objc_getFutureClass with existing class
55    oldTestRoot = objc_getFutureClass("TestRoot");
56    testassert(oldTestRoot == [TestRoot class]);
57    testassert(! _class_isFutureClass(oldTestRoot));
58
59    // objc_getFutureClass with missing class
60    oldSub1 = objc_getFutureClass("Sub1");
61    testassert(oldSub1);
62    testassert(malloc_size(objc_unretainedPointer(oldSub1)) > 0);
63    testassert(objc_getClass("Sub1") == Nil);
64    testassert(_class_isFutureClass(oldSub1));
65    testassert(0 == strcmp(class_getName(oldSub1), "Sub1"));
66    testassert(object_getClass(oldSub1) == Nil);  // CF expects this
67
68    // objc_getFutureClass a second time
69    testassert(oldSub1 == objc_getFutureClass("Sub1"));
70
71#if !__OBJC2__
72    // objc_setFutureClass with existing class
73    oldSub2 = objc_getClass("Sub2");
74    testassert(oldSub2 == [Sub2 class]);
75    testassert(oldSub2 == class_getSuperclass(objc_getClass("SubSub2")));
76    objc_setFutureClass((Class)buf, "Sub2");
77    testassert(0 == strcmp(class_getName((Class)buf), "Sub2"));
78    newSub2 = objc_getClass("Sub2");
79    testassert(newSub2 == (Class)buf);
80    testassert(newSub2 != oldSub2);
81    // check classrefs
82    testassert(newSub2 == [Sub2 class]);
83    testassert(newSub2 == [newSub2 class]);
84    testassert(newSub2 == [newSub2 classref]);
85    testassert(newSub2 != [oldSub2 class]);
86    // check superclass chains
87    testassert(newSub2 == class_getSuperclass(objc_getClass("SubSub2")));
88#else
89    // 64-bit ABI ignores objc_setFutureClass.
90#endif
91
92    // Load class Sub1
93    dlopen("future2.dylib", 0);
94
95    // Verify use of future class
96    newSub1 = objc_getClass("Sub1");
97    testassert(oldSub1 == newSub1);
98    testassert(newSub1 == [newSub1 classref]);
99    testassert(newSub1 == class_getSuperclass(objc_getClass("SubSub1")));
100    testassert(! _class_isFutureClass(newSub1));
101
102    testassert(1 == [oldSub1 method]);
103    testassert(1 == [newSub1 method]);
104#if !__OBJC2__
105    testassert(2 == [newSub2 method]);
106    testassert(2 == [oldSub2 method]);
107    testassert(3 == [SubSub2 method]);
108#endif
109
110    succeed(__FILE__);
111}
112
113#endif
114