You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
6.9 KiB
Objective-C
344 lines
6.9 KiB
Objective-C
#include "Test.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef _WIN32
|
|
# include "../safewindows.h"
|
|
# define sleep(x) Sleep(1000 * x)
|
|
#else
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
static int exitStatus = 0;
|
|
|
|
static void _test(BOOL X, char *expr, int line)
|
|
{
|
|
if (!X)
|
|
{
|
|
exitStatus = 1;
|
|
fprintf(stderr, "ERROR: Test failed: '%s' on %s:%d\n", expr, __FILE__, line);
|
|
}
|
|
}
|
|
#define test(X) _test(X, #X, __LINE__)
|
|
|
|
static int stringsEqual(const char *a, const char *b)
|
|
{
|
|
return 0 == strcmp(a,b);
|
|
}
|
|
|
|
@protocol NSCoding
|
|
@end
|
|
|
|
#ifdef __has_attribute
|
|
#if __has_attribute(objc_root_class)
|
|
__attribute__((objc_root_class))
|
|
#endif
|
|
#endif
|
|
@interface NSObject <NSCoding>
|
|
{
|
|
id isa;
|
|
int refcount;
|
|
}
|
|
@end
|
|
@implementation NSObject
|
|
- (id)class
|
|
{
|
|
return object_getClass(self);
|
|
}
|
|
+ (id)class
|
|
{
|
|
return self;
|
|
}
|
|
+ (id)new
|
|
{
|
|
return class_createInstance(self, 0);
|
|
}
|
|
- (void)release
|
|
{
|
|
if (refcount == 0)
|
|
{
|
|
object_dispose(self);
|
|
}
|
|
refcount--;
|
|
}
|
|
- (id)retain
|
|
{
|
|
refcount++;
|
|
return self;
|
|
}
|
|
@end
|
|
|
|
|
|
@interface Foo : NSObject
|
|
{
|
|
id a;
|
|
}
|
|
- (void) aMethod;
|
|
+ (void) aMethod;
|
|
- (int) manyTypes;
|
|
- (void) synchronizedCode;
|
|
+ (void) synchronizedCode;
|
|
+ (id) shared;
|
|
- (BOOL) basicThrowAndCatchException;
|
|
@end
|
|
|
|
@interface Bar : Foo
|
|
{
|
|
id b;
|
|
}
|
|
- (void) anotherMethod;
|
|
+ (void) anotherMethod;
|
|
- (id) manyTypes;
|
|
- (id) aBool: (BOOL)d andAnInt: (int) w;
|
|
@end
|
|
|
|
id exceptionObj = @"Exception";
|
|
|
|
@implementation Foo
|
|
- (void) aMethod
|
|
{
|
|
}
|
|
+ (void) aMethod
|
|
{
|
|
}
|
|
- (int) manyTypes
|
|
{
|
|
return YES;
|
|
}
|
|
- (void) synchronizedCode
|
|
{
|
|
@synchronized(self) { [[self class] synchronizedCode]; }
|
|
}
|
|
+ (void) synchronizedCode
|
|
{
|
|
@synchronized(self) { }
|
|
}
|
|
+ (id) shared
|
|
{
|
|
@synchronized(self) { }
|
|
return nil;
|
|
}
|
|
- (void) throwException
|
|
{
|
|
@throw exceptionObj;
|
|
}
|
|
- (BOOL) basicThrowAndCatchException
|
|
{
|
|
@try
|
|
{
|
|
[self throwException];
|
|
}
|
|
@catch (id e)
|
|
{
|
|
test(e == exceptionObj);
|
|
return YES;
|
|
}
|
|
@catch(...)
|
|
{
|
|
return NO;
|
|
}
|
|
return NO;
|
|
}
|
|
@end
|
|
|
|
@implementation Bar
|
|
- (void) anotherMethod
|
|
{
|
|
}
|
|
+ (void) anotherMethod
|
|
{
|
|
}
|
|
- (id) manyTypes
|
|
{
|
|
return @"Hello";
|
|
}
|
|
- (id) aBool: (BOOL)d andAnInt: (int) w
|
|
{
|
|
return @"Hello";
|
|
}
|
|
@end
|
|
|
|
|
|
void testInvalidArguments()
|
|
{
|
|
test(NO == class_conformsToProtocol([NSObject class], NULL));
|
|
test(NO == class_conformsToProtocol(Nil, NULL));
|
|
test(NO == class_conformsToProtocol(Nil, @protocol(NSCoding)));
|
|
test(NULL == class_copyIvarList(Nil, NULL));
|
|
test(NULL == class_copyMethodList(Nil, NULL));
|
|
test(NULL == class_copyPropertyList(Nil, NULL));
|
|
test(NULL == class_copyProtocolList(Nil, NULL));
|
|
test(nil == class_createInstance(Nil, 0));
|
|
test(0 == class_getVersion(Nil));
|
|
test(NO == class_isMetaClass(Nil));
|
|
test(Nil == class_getSuperclass(Nil));
|
|
|
|
test(NULL == method_getName(NULL));
|
|
test(NULL == method_copyArgumentType(NULL, 0));
|
|
test(NULL == method_copyReturnType(NULL));
|
|
method_exchangeImplementations(NULL, NULL);
|
|
test((IMP)NULL == method_setImplementation(NULL, (IMP)NULL));
|
|
test((IMP)NULL == method_getImplementation(NULL));
|
|
method_getArgumentType(NULL, 0, NULL, 0);
|
|
test(0 == method_getNumberOfArguments(NULL));
|
|
test(NULL == method_getTypeEncoding(NULL));
|
|
method_getReturnType(NULL, NULL, 0);
|
|
|
|
test(NULL == ivar_getName(NULL));
|
|
test(0 == ivar_getOffset(NULL));
|
|
test(NULL == ivar_getTypeEncoding(NULL));
|
|
|
|
test(nil == objc_getProtocol(NULL));
|
|
|
|
test(stringsEqual("<null selector>", sel_getName((SEL)0)));
|
|
test((SEL)0 == sel_getUid(NULL));
|
|
test(0 != sel_getUid("")); // the empty string is permitted as a selector
|
|
test(stringsEqual("", sel_getName(sel_getUid(""))));
|
|
test(YES == sel_isEqual((SEL)0, (SEL)0));
|
|
|
|
//test(NULL == property_getName(NULL));
|
|
|
|
printf("testInvalidArguments() ran\n");
|
|
}
|
|
|
|
void testAMethod(Method m)
|
|
{
|
|
test(NULL != m);
|
|
test(stringsEqual("aMethod", sel_getName(method_getName(m))));
|
|
|
|
printf("testAMethod() ran\n");
|
|
}
|
|
|
|
void testGetMethod()
|
|
{
|
|
testAMethod(class_getClassMethod([Bar class], @selector(aMethod)));
|
|
testAMethod(class_getClassMethod([Bar class], sel_getUid("aMethod")));
|
|
|
|
printf("testGetMethod() ran\n");
|
|
}
|
|
|
|
void testProtocols()
|
|
{
|
|
test(protocol_isEqual(@protocol(NSCoding), objc_getProtocol("NSCoding")));
|
|
|
|
printf("testProtocols() ran\n");
|
|
}
|
|
|
|
void testMultiTypedSelector()
|
|
{
|
|
test(sel_isEqual(@selector(manyTypes),sel_getUid("manyTypes")));
|
|
|
|
Method intMethod = class_getInstanceMethod([Foo class], @selector(manyTypes));
|
|
Method idMethod = class_getInstanceMethod([Bar class], @selector(manyTypes));
|
|
|
|
test(sel_isEqual(method_getName(intMethod), @selector(manyTypes)));
|
|
test(sel_isEqual(method_getName(idMethod), @selector(manyTypes)));
|
|
|
|
char ret[10];
|
|
method_getReturnType(intMethod, ret, 10);
|
|
test(stringsEqual(ret, "i"));
|
|
method_getReturnType(idMethod, ret, 10);
|
|
test(stringsEqual(ret, "@"));
|
|
|
|
printf("testMultiTypedSelector() ran\n");
|
|
}
|
|
|
|
void testClassHierarchy()
|
|
{
|
|
Class nsProxy = objc_getClass("NSProxy");
|
|
Class nsObject = objc_getClass("NSObject");
|
|
Class nsProxyMeta = object_getClass(nsProxy);
|
|
Class nsObjectMeta = object_getClass(nsObject);
|
|
|
|
test(object_getClass(nsProxyMeta) == nsProxyMeta);
|
|
test(object_getClass(nsObjectMeta) == nsObjectMeta);
|
|
|
|
test(Nil == class_getSuperclass(nsProxy));
|
|
test(Nil == class_getSuperclass(nsObject));
|
|
|
|
test(nsObject == class_getSuperclass(nsObjectMeta));
|
|
test(nsProxy == class_getSuperclass(nsProxyMeta));
|
|
printf("testClassHierarchy() ran\n");
|
|
}
|
|
|
|
void testAllocateClass()
|
|
{
|
|
Class newClass = objc_allocateClassPair(objc_lookUpClass("NSObject"), "UserAllocated", 0);
|
|
test(Nil != newClass);
|
|
// class_getSuperclass() will call objc_resolve_class().
|
|
// Although we have not called objc_registerClassPair() yet, this works with
|
|
// the Apple runtime and GNUstep Base relies on this behavior in
|
|
// GSObjCMakeClass().
|
|
test(objc_lookUpClass("NSObject") == class_getSuperclass(newClass));
|
|
printf("testAllocateClass() ran\n");
|
|
}
|
|
|
|
void testSynchronized()
|
|
{
|
|
Foo *foo = [Foo new];
|
|
printf("Enter synchronized code\n");
|
|
[foo synchronizedCode];
|
|
[foo release];
|
|
[Foo shared];
|
|
printf("testSynchronized() ran\n");
|
|
}
|
|
|
|
void testExceptions()
|
|
{
|
|
Foo *foo = [Foo new];
|
|
test([foo basicThrowAndCatchException]);
|
|
[foo release];
|
|
printf("testExceptions() ran\n");
|
|
|
|
}
|
|
|
|
void testRegisterAlias()
|
|
{
|
|
class_registerAlias_np([NSObject class], "AliasObject");
|
|
test([NSObject class] == objc_getClass("AliasObject"));
|
|
printf("testRegisterAlias() ran\n");
|
|
}
|
|
|
|
@interface SlowInit1 : NSObject
|
|
+ (void)doNothing;
|
|
@end
|
|
@interface SlowInit2 : NSObject
|
|
+ (void)doNothing;
|
|
@end
|
|
|
|
@implementation SlowInit1
|
|
+ (void)initialize
|
|
{
|
|
sleep(1);
|
|
[SlowInit2 doNothing];
|
|
}
|
|
+ (void)doNothing {}
|
|
@end
|
|
static int initCount;
|
|
@implementation SlowInit2
|
|
+ (void)initialize
|
|
{
|
|
sleep(1);
|
|
__sync_fetch_and_add(&initCount, 1);
|
|
}
|
|
+ (void)doNothing {}
|
|
@end
|
|
|
|
|
|
|
|
int main (int argc, const char * argv[])
|
|
{
|
|
testInvalidArguments();
|
|
testGetMethod();
|
|
testProtocols();
|
|
testMultiTypedSelector();
|
|
testClassHierarchy();
|
|
testAllocateClass();
|
|
printf("Instance of NSObject: %p\n", class_createInstance([NSObject class], 0));
|
|
|
|
testSynchronized();
|
|
testExceptions();
|
|
testRegisterAlias();
|
|
|
|
return exitStatus;
|
|
}
|