darling-objc4/test/isaValidation.m
2020-06-09 21:50:17 -04:00

268 lines
10 KiB
Objective-C

// TEST_CRASHES
// TEST_CONFIG MEM=mrc
/*
TEST_RUN_OUTPUT
Testing object_getMethodImplementation
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_getInstanceMethod
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_getMethodImplementation
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_respondsToSelector
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_conformsToProtocol
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_copyProtocolList
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_getProperty
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_copyPropertyList
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_addMethod
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_replaceMethod
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_addIvar
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_addProtocol
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_addProperty
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_replaceProperty
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_setIvarLayout
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'TestRoot'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'TestRoot'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'NSObject'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'NSObject'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'AllocatedTestClass2'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'AllocatedTestClass2'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'TestRoot'
objc\[\d+\]: \*\*\* Can't set ivar layout for already-registered class 'DuplicateClass'
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing class_setWeakIvarLayout
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'TestRoot'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'TestRoot'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'NSObject'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'NSObject'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'AllocatedTestClass2'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'AllocatedTestClass2'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'TestRoot'
objc\[\d+\]: \*\*\* Can't set weak ivar layout for already-registered class 'DuplicateClass'
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing objc_registerClassPair
objc\[\d+\]: objc_registerClassPair: class 'TestRoot' was not allocated with objc_allocateClassPair!
objc\[\d+\]: objc_registerClassPair: class 'NSObject' was not allocated with objc_allocateClassPair!
objc\[\d+\]: objc_registerClassPair: class 'AllocatedTestClass2' was already registered!
objc\[\d+\]: objc_registerClassPair: class 'DuplicateClass' was not allocated with objc_allocateClassPair!
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing objc_duplicateClass
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Testing objc_disposeClassPair
objc\[\d+\]: objc_disposeClassPair: class 'TestRoot' was not allocated with objc_allocateClassPair!
objc\[\d+\]: objc_disposeClassPair: class 'NSObject' was not allocated with objc_allocateClassPair!
objc\[\d+\]: objc_disposeClassPair: class 'DuplicateClass' was not allocated with objc_allocateClassPair!
Completed test on good classes.
objc\[\d+\]: Attempt to use unknown class 0x[0-9a-f]+.
objc\[\d+\]: HALTED
Completed!
END
*/
#include "test.h"
#include "testroot.i"
#include <spawn.h>
@protocol P
@end
extern char **environ;
id dummyIMP(id self, SEL _cmd) { (void)_cmd; return self; }
char *dupeName(Class cls) {
char *name;
asprintf(&name, "%sDuplicate", class_getName(cls));
return name;
}
typedef void (^TestBlock)(Class);
struct TestCase {
const char *name;
TestBlock block;
};
#define NAMED_TESTCASE(name, ...) { name, ^(Class cls) { __VA_ARGS__; } }
#define TESTCASE(...) NAMED_TESTCASE(#__VA_ARGS__, __VA_ARGS__)
#define TESTCASE_NOMETA(...) \
NAMED_TESTCASE( #__VA_ARGS__, if(class_isMetaClass(cls)) return; __VA_ARGS__; )
#define TESTCASE_OBJ(...) NAMED_TESTCASE( \
#__VA_ARGS__, \
if(class_isMetaClass(cls)) return; \
id obj = [TestRoot alloc]; \
*(Class *)obj = cls; \
__VA_ARGS__; \
)
struct TestCase TestCases[] = {
TESTCASE_OBJ(object_getMethodImplementation(obj, @selector(init))),
TESTCASE(class_getInstanceMethod(cls, @selector(init))),
TESTCASE(class_getMethodImplementation(cls, @selector(init))),
TESTCASE(class_respondsToSelector(cls, @selector(init))),
TESTCASE(class_conformsToProtocol(cls, @protocol(P))),
TESTCASE(free(class_copyProtocolList(cls, NULL))),
TESTCASE(class_getProperty(cls, "x")),
TESTCASE(free(class_copyPropertyList(cls, NULL))),
TESTCASE(class_addMethod(cls, @selector(nop), (IMP)dummyIMP, "v@:")),
TESTCASE(class_replaceMethod(cls, @selector(nop), (IMP)dummyIMP, "v@:")),
TESTCASE(class_addIvar(cls, "x", sizeof(int), sizeof(int), @encode(int))),
TESTCASE(class_addProtocol(cls, @protocol(P))),
TESTCASE(class_addProperty(cls, "x", NULL, 0)),
TESTCASE(class_replaceProperty(cls, "x", NULL, 0)),
TESTCASE(class_setIvarLayout(cls, NULL)),
TESTCASE(class_setWeakIvarLayout(cls, NULL)),
TESTCASE_NOMETA(objc_registerClassPair(cls)),
TESTCASE_NOMETA(objc_duplicateClass(cls, dupeName(cls), 0)),
TESTCASE_NOMETA(objc_disposeClassPair(cls)),
};
void parent(char *argv0)
{
int testCount = sizeof(TestCases) / sizeof(*TestCases);
for (int i = 0; i < testCount; i++) {
char *testIndex;
asprintf(&testIndex, "%d", i);
char *argvSpawn[] = {
argv0,
testIndex,
NULL
};
pid_t pid;
int result = posix_spawn(&pid, argv0, NULL, NULL, argvSpawn, environ);
if (result != 0) {
fprintf(stderr, "Could not spawn child process: (%d) %s\n",
errno, strerror(errno));
exit(1);
}
free(testIndex);
result = waitpid(pid, NULL, 0);
if (result == -1) {
fprintf(stderr, "Error waiting for termination of child process: (%d) %s\n",
errno, strerror(errno));
exit(1);
}
}
fprintf(stderr, "Completed!\n");
}
void child(char *argv1)
{
long index = strtol(argv1, NULL, 10);
struct TestCase testCase = TestCases[index];
TestBlock block = testCase.block;
const char *name = testCase.name;
if (strncmp(name, "free(", 5) == 0)
name += 5;
const char *paren = strchr(name, '(');
long len = paren != NULL ? paren - name : strlen(name);
fprintf(stderr, "Testing %.*s\n", (int)len, name);
// Make sure plain classes work.
block([TestRoot class]);
block(object_getClass([TestRoot class]));
// And framework classes.
block([NSObject class]);
block(object_getClass([NSObject class]));
// Test a constructed, unregistered class.
Class allocatedClass = objc_allocateClassPair([TestRoot class],
"AllocatedTestClass",
0);
class_getMethodImplementation(allocatedClass, @selector(self));
block(object_getClass(allocatedClass));
block(allocatedClass);
// Test a constructed, registered class. (Do this separately so
// test cases can dispose of the class if needed.)
allocatedClass = objc_allocateClassPair([TestRoot class],
"AllocatedTestClass2",
0);
objc_registerClassPair(allocatedClass);
block(object_getClass(allocatedClass));
block(allocatedClass);
// Test a duplicated class.
Class duplicatedClass = objc_duplicateClass([TestRoot class],
"DuplicateClass",
0);
block(object_getClass(duplicatedClass));
block(duplicatedClass);
fprintf(stderr, "Completed test on good classes.\n");
// Test a fake class.
Class templateClass = objc_allocateClassPair([TestRoot class],
"TemplateClass",
0);
void *fakeClass = malloc(malloc_size(templateClass));
memcpy(fakeClass, templateClass, malloc_size(templateClass));
block((Class)fakeClass);
fail("Should have died on the fake class");
}
int main(int argc, char **argv)
{
// We want to run a bunch of tests, all of which end in _objc_fatal
// (at least if they succeed). Spawn one subprocess per test and
// have the parent process manage it all. The test will begin by
// running parent(), which will repeatedly re-spawn this program to
// call child() with the index of the test to run.
if (argc == 1) {
parent(argv[0]);
} else {
child(argv[1]);
}
}