| /* Test the Modern GNU Objective-C Runtime API. |
| |
| This is test 'objc', covering all functions starting with 'objc'. */ |
| |
| /* { dg-do run } */ |
| /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ |
| /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ |
| |
| /* To get the modern GNU Objective-C Runtime API, you include |
| objc/runtime.h. */ |
| #include <objc/runtime.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| @interface MyRootClass |
| { Class isa; } |
| + alloc; |
| - init; |
| + initialize; |
| @end |
| |
| @implementation MyRootClass |
| + alloc { return class_createInstance (self, 0); } |
| - init { return self; } |
| + initialize { return self; } |
| @end |
| |
| @protocol MyProtocol |
| - (id) variable; |
| @end |
| |
| @protocol MySecondProtocol |
| - (id) setVariable: (id)value; |
| @end |
| |
| @interface MySubClass : MyRootClass <MyProtocol> |
| { id variable_ivar; } |
| - (void) setVariable: (id)value; |
| - (id) variable; |
| @end |
| |
| @implementation MySubClass |
| - (void) setVariable: (id)value { variable_ivar = value; } |
| - (id) variable { return variable_ivar; } |
| @end |
| |
| /* Hack to calculate the log2 of a byte alignment. */ |
| unsigned char |
| log_2_of (unsigned int x) |
| { |
| unsigned char result = 0; |
| |
| /* We count how many times we need to divide by 2 before we reach 1. |
| This algorithm is good enough for the small numbers (such as 8, |
| 16 or 64) that we have to deal with. */ |
| while (x > 1) |
| { |
| x = x / 2; |
| result++; |
| } |
| |
| return result; |
| } |
| |
| int main(int argc, void **args) |
| { |
| /* Functions are tested in alphabetical order. */ |
| |
| printf ("Testing objc_allocateClassPair ()...\n"); |
| { |
| Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0); |
| Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0); |
| |
| /* A new root class would obviously need at least an 'isa' |
| instance variable. */ |
| class_addIvar (new_root_class, "isa", sizeof (Class), log_2_of (__alignof__ (Class)), |
| @encode (Class)); |
| |
| objc_registerClassPair (new_root_class); |
| objc_registerClassPair (new_class); |
| |
| if (strcmp (class_getName (new_class), "MyNewSubClass") != 0) |
| abort (); |
| |
| if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass")) |
| abort (); |
| |
| if (strcmp (class_getName (new_root_class), "MyNewRootClass") != 0) |
| abort (); |
| |
| if (class_getSuperclass (new_root_class) != Nil) |
| abort (); |
| |
| { |
| MySubClass *o = [[(Class)objc_getClass ("MyNewSubClass") alloc] init]; |
| |
| if (object_getClass (o) != objc_getClass ("MyNewSubClass")) |
| abort (); |
| } |
| } |
| |
| printf ("Testing objc_copyProtocolList ()...\n"); |
| { |
| /* Make sure both our two protocols are known to the runtime. */ |
| id my_protocol = @protocol (MyProtocol); |
| id my_second_protocol = @protocol (MySecondProtocol); |
| unsigned int count; |
| Protocol ** list = objc_copyProtocolList (&count); |
| |
| if (count != 2) |
| abort (); |
| |
| if (! ((strcmp (protocol_getName (list[0]), "MyProtocol") == 0 |
| && strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0) |
| || (strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0 |
| && strcmp (protocol_getName (list[1]), "MyProtocol") == 0))) |
| abort (); |
| |
| if (list[2] != NULL) |
| abort (); |
| } |
| |
| printf ("Testing objc_disposeClassPair ()...\n"); |
| { |
| Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:)); |
| Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass2", 0); |
| |
| if (new_class == Nil) |
| abort (); |
| |
| /* Add a bit of everything to the class to exercise undoing all these changes. */ |
| |
| /* Instance variable. */ |
| class_addIvar (new_class, "my_variable", sizeof (float), log_2_of (__alignof__ (float)), @encode (float)); |
| |
| /* Instance method. */ |
| class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method), |
| method_getTypeEncoding (method)); |
| |
| /* Class method. */ |
| class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method), |
| method_getTypeEncoding (method)); |
| |
| /* Protocol. */ |
| class_addProtocol (new_class, @protocol (MyProtocol)); |
| |
| objc_disposeClassPair (new_class); |
| } |
| |
| /* This function currently does not exist with the GNU runtime. */ |
| /* printf ("Testing objc_duplicateClass ()...\n"); */ |
| |
| /* TODO - Test it when implemented in the GNU Runtime */ |
| /* printf ("Testing objc_getAssociatedObject ()...\n"); */ |
| |
| printf ("Testing objc_getClass ()...\n"); |
| { |
| if (strcmp (class_getName (objc_getClass ("MySubClass")), |
| "MySubClass") != 0) |
| abort (); |
| } |
| |
| printf ("Testing objc_getClassList ()...\n"); |
| { |
| Class *list; |
| int i, count, other_count; |
| count = objc_getClassList (NULL, 0); |
| |
| /* count most likely will be 5, (MyRootClass, MySubClass, |
| Protocol, Object, NXConstantString). */ |
| if (count < 3) |
| abort (); |
| |
| list = malloc (sizeof (Class) * count); |
| other_count = objc_getClassList (list, count); |
| |
| if (other_count != count) |
| abort (); |
| |
| /* Spot-check: search for class 'MyRootClass' in the list. */ |
| for (i = 0; i < count; i++) |
| { |
| if (strcmp (class_getName (list[i]), "MyRootClass") == 0) |
| break; |
| } |
| if (i == count) |
| abort (); |
| |
| /* Spot-check: search for class 'MySubClass' in the list. */ |
| for (i = 0; i < count; i++) |
| { |
| if (strcmp (class_getName (list[i]), "MySubClass") == 0) |
| break; |
| } |
| if (i == count) |
| abort (); |
| |
| /* Spot-check: search for class 'Protocol' in the list. */ |
| for (i = 0; i < count; i++) |
| { |
| if (strcmp (class_getName (list[i]), "Protocol") == 0) |
| break; |
| } |
| if (i == count) |
| abort (); |
| } |
| |
| /* This function does not exist with the GNU runtime. */ |
| /* printf ("Testing objc_getFutureClass ()...\n"); */ |
| |
| printf ("Testing objc_getMetaClass ()...\n"); |
| { |
| if (! class_isMetaClass (objc_getMetaClass ("MyRootClass"))) |
| abort (); |
| } |
| |
| printf ("Testing objc_getProtocol ()...\n"); |
| { |
| if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol))) |
| abort (); |
| } |
| |
| printf ("Testing objc_getRequiredClass ()...\n"); |
| { |
| if (strcmp (class_getName (objc_getRequiredClass ("MyRootClass")), |
| "MyRootClass") != 0) |
| abort (); |
| } |
| |
| printf ("Testing objc_lookUpClass ()...\n"); |
| { |
| if (strcmp (class_getName (objc_lookUpClass ("MyRootClass")), |
| "MyRootClass") != 0) |
| abort (); |
| } |
| |
| /* This function does not exist with the GNU runtime. */ |
| /* printf ("Testing objc_setFutureClass ()...\n"); */ |
| |
| printf ("Testing objc_registerClassPair ()...\n"); |
| { |
| Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0); |
| |
| class_addProtocol (new_class, @protocol (MySecondProtocol)); |
| |
| objc_registerClassPair (new_class); |
| |
| if (strcmp (class_getName (new_class), "MySubSubClass") != 0) |
| abort (); |
| |
| if (class_getSuperclass (new_class) != objc_getClass ("MySubClass")) |
| abort (); |
| |
| if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol))) |
| abort (); |
| } |
| |
| /* TODO - Test it when implemented in the GNU Runtime */ |
| /* printf ("Testing objc_removeAssociatedObjects ()...\n"); */ |
| |
| /* TODO - Test it when implemented in the GNU Runtime */ |
| /* printf ("Testing objc_setAssociatedObject ()...\n"); */ |
| |
| return 0; |
| } |