/*
TEST_BUILD
    $C{COMPILE} $DIR/future0.m -o future0.dylib -dynamiclib
    $C{COMPILE} $DIR/future2.m -x none future0.dylib -o future2.dylib -dynamiclib
    $C{COMPILE} $DIR/future.m -x none future0.dylib -o future.out
END
*/

#include "test.h"

#if __has_feature(objc_arc)

int main()
{
    testwarn("rdar://10041403 future class API is not ARC-compatible");
    succeed(__FILE__);
}


#else

#include <objc/runtime.h>
#include <malloc/malloc.h>
#include <string.h>
#include <dlfcn.h>
#include "future.h"

@implementation Sub2 
+(int)method { 
    return 2;
}
+(Class)classref {
    return [Sub2 class];
}
@end

@implementation SubSub2
+(int)method {
    return 1 + [super method];
}
@end

int main()
{
    Class oldTestRoot;
    Class oldSub1;
    Class newSub1;
#if !__OBJC2__
    Class oldSub2;
    Class newSub2;
    uintptr_t buf[20];
#endif

    // objc_getFutureClass with existing class
    oldTestRoot = objc_getFutureClass("TestRoot");
    testassert(oldTestRoot == [TestRoot class]);
    testassert(! _class_isFutureClass(oldTestRoot));

    // objc_getFutureClass with missing class
    oldSub1 = objc_getFutureClass("Sub1");
    testassert(oldSub1);
    testassert(malloc_size(objc_unretainedPointer(oldSub1)) > 0);
    testassert(objc_getClass("Sub1") == Nil);
    testassert(_class_isFutureClass(oldSub1));
    testassert(0 == strcmp(class_getName(oldSub1), "Sub1"));
    testassert(object_getClass(oldSub1) == Nil);  // CF expects this

    // objc_getFutureClass a second time
    testassert(oldSub1 == objc_getFutureClass("Sub1"));

#if !__OBJC2__
    // objc_setFutureClass with existing class
    oldSub2 = objc_getClass("Sub2");
    testassert(oldSub2 == [Sub2 class]);
    testassert(oldSub2 == class_getSuperclass(objc_getClass("SubSub2")));
    objc_setFutureClass((Class)buf, "Sub2");
    testassert(0 == strcmp(class_getName((Class)buf), "Sub2"));
    newSub2 = objc_getClass("Sub2");
    testassert(newSub2 == (Class)buf);
    testassert(newSub2 != oldSub2);
    // check classrefs
    testassert(newSub2 == [Sub2 class]);
    testassert(newSub2 == [newSub2 class]);
    testassert(newSub2 == [newSub2 classref]);
    testassert(newSub2 != [oldSub2 class]);
    // check superclass chains
    testassert(newSub2 == class_getSuperclass(objc_getClass("SubSub2")));
#else
    // 64-bit ABI ignores objc_setFutureClass.
#endif

    // Load class Sub1
    dlopen("future2.dylib", 0);

    // Verify use of future class
    newSub1 = objc_getClass("Sub1");
    testassert(oldSub1 == newSub1);
    testassert(newSub1 == [newSub1 classref]);
    testassert(newSub1 == class_getSuperclass(objc_getClass("SubSub1")));
    testassert(! _class_isFutureClass(newSub1));

    testassert(1 == [oldSub1 method]);
    testassert(1 == [newSub1 method]);
#if !__OBJC2__
    testassert(2 == [newSub2 method]);
    testassert(2 == [oldSub2 method]);
    testassert(3 == [SubSub2 method]);
#endif

    succeed(__FILE__);
}

#endif
