1/* Test the Modern GNU Objective-C Runtime API. 2 3 This is test 'objc', covering all functions starting with 'objc'. */ 4 5/* { dg-do run } */ 6/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ 7/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ 8 9/* To get the modern GNU Objective-C Runtime API, you include 10 objc/runtime.h. */ 11#include <objc/runtime.h> 12#include <stdlib.h> 13#include <iostream> 14#include <cstring> 15 16@interface MyRootClass 17{ Class isa; } 18+ alloc; 19- init; 20+ initialize; 21@end 22 23@implementation MyRootClass 24+ alloc { return class_createInstance (self, 0); } 25- init { return self; } 26+ initialize { return self; } 27@end 28 29@protocol MyProtocol 30- (id) variable; 31@end 32 33@protocol MySecondProtocol 34- (id) setVariable: (id)value; 35@end 36 37@interface MySubClass : MyRootClass <MyProtocol> 38{ id variable_ivar; } 39- (void) setVariable: (id)value; 40- (id) variable; 41@end 42 43@implementation MySubClass 44- (void) setVariable: (id)value { variable_ivar = value; } 45- (id) variable { return variable_ivar; } 46@end 47 48/* Hack to calculate the log2 of a byte alignment. */ 49unsigned char 50log_2_of (unsigned int x) 51{ 52 unsigned char result = 0; 53 54 /* We count how many times we need to divide by 2 before we reach 1. 55 This algorithm is good enough for the small numbers (such as 8, 56 16 or 64) that we have to deal with. */ 57 while (x > 1) 58 { 59 x = x / 2; 60 result++; 61 } 62 63 return result; 64} 65 66int main () 67{ 68 /* Functions are tested in alphabetical order. */ 69 70 std::cout << "Testing objc_allocateClassPair ()...\n"; 71 { 72 Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0); 73 Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0); 74 75 /* A new root class would obviously need at least an 'isa' 76 instance variable. */ 77 class_addIvar (new_root_class, "isa", sizeof (Class), log_2_of (__alignof__ (Class)), 78 @encode (Class)); 79 80 objc_registerClassPair (new_root_class); 81 objc_registerClassPair (new_class); 82 83 if (std::strcmp (class_getName (new_class), "MyNewSubClass") != 0) 84 abort (); 85 86 if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass")) 87 abort (); 88 89 if (std::strcmp (class_getName (new_root_class), "MyNewRootClass") != 0) 90 abort (); 91 92 if (class_getSuperclass (new_root_class) != Nil) 93 abort (); 94 95 { 96 MySubClass *o = [[(Class)objc_getClass ("MyNewSubClass") alloc] init]; 97 98 if (object_getClass (o) != objc_getClass ("MyNewSubClass")) 99 abort (); 100 } 101 } 102 103 std::cout << "Testing objc_copyProtocolList ()...\n"; 104 { 105 /* Make sure both our two protocols are known to the runtime. */ 106 id my_protocol = @protocol (MyProtocol); 107 id my_second_protocol = @protocol (MySecondProtocol); 108 unsigned int count; 109 Protocol ** list = objc_copyProtocolList (&count); 110 111 if (count != 2) 112 abort (); 113 114 if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0 115 && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0) 116 || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0 117 && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0))) 118 abort (); 119 120 if (list[2] != NULL) 121 abort (); 122 } 123 124 std::cout << "Testing objc_disposeClassPair ()...\n"; 125 { 126 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:)); 127 Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass2", 0); 128 129 if (new_class == Nil) 130 abort (); 131 132 /* Add a bit of everything to the class to exercise undoing all these changes. */ 133 134 /* Instance variable. */ 135 class_addIvar (new_class, "my_variable", sizeof (float), log_2_of (__alignof__ (float)), @encode (float)); 136 137 /* Instance method. */ 138 class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method), 139 method_getTypeEncoding (method)); 140 141 /* Class method. */ 142 class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method), 143 method_getTypeEncoding (method)); 144 145 /* Protocol. */ 146 class_addProtocol (new_class, @protocol (MyProtocol)); 147 148 objc_disposeClassPair (new_class); 149 } 150 151 /* This function currently does not exist with the GNU runtime. */ 152 /* std::cout << "Testing objc_duplicateClass ()...\n"; */ 153 154 /* TODO - Test it when implemented in the GNU Runtime */ 155 /* std::cout << "Testing objc_getAssociatedObject ()...\n"; */ 156 157 std::cout << "Testing objc_getClass ()...\n"; 158 { 159 if (std::strcmp (class_getName (objc_getClass ("MySubClass")), 160 "MySubClass") != 0) 161 abort (); 162 } 163 164 std::cout << "Testing objc_getClassList ()...\n"; 165 { 166 Class *list; 167 int i, count, other_count; 168 count = objc_getClassList (NULL, 0); 169 170 /* count most likely will be 5, (MyRootClass, MySubClass, 171 Protocol, Object, NXConstantString). */ 172 if (count < 3) 173 abort (); 174 175 list = (Class *)(malloc (sizeof (Class) * count)); 176 other_count = objc_getClassList (list, count); 177 178 if (other_count != count) 179 abort (); 180 181 /* Spot-check: search for class 'MyRootClass' in the list. */ 182 for (i = 0; i < count; i++) 183 { 184 if (std::strcmp (class_getName (list[i]), "MyRootClass") == 0) 185 break; 186 } 187 if (i == count) 188 abort (); 189 190 /* Spot-check: search for class 'MySubClass' in the list. */ 191 for (i = 0; i < count; i++) 192 { 193 if (std::strcmp (class_getName (list[i]), "MySubClass") == 0) 194 break; 195 } 196 if (i == count) 197 abort (); 198 199 /* Spot-check: search for class 'Protocol' in the list. */ 200 for (i = 0; i < count; i++) 201 { 202 if (std::strcmp (class_getName (list[i]), "Protocol") == 0) 203 break; 204 } 205 if (i == count) 206 abort (); 207 } 208 209 /* This function does not exist with the GNU runtime. */ 210 /* std::cout << "Testing objc_getFutureClass ()...\n"; */ 211 212 std::cout << "Testing objc_getMetaClass ()...\n"; 213 { 214 if (! class_isMetaClass (objc_getMetaClass ("MyRootClass"))) 215 abort (); 216 } 217 218 std::cout << "Testing objc_getProtocol ()...\n"; 219 { 220 if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol))) 221 abort (); 222 } 223 224 std::cout << "Testing objc_getRequiredClass ()...\n"; 225 { 226 if (std::strcmp (class_getName (objc_getRequiredClass ("MyRootClass")), 227 "MyRootClass") != 0) 228 abort (); 229 } 230 231 std::cout << "Testing objc_lookUpClass ()...\n"; 232 { 233 if (std::strcmp (class_getName (objc_lookUpClass ("MyRootClass")), 234 "MyRootClass") != 0) 235 abort (); 236 } 237 238 /* This function does not exist with the GNU runtime. */ 239 /* std::cout << "Testing objc_setFutureClass ()...\n"; */ 240 241 std::cout << "Testing objc_registerClassPair ()...\n"; 242 { 243 Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0); 244 245 class_addProtocol (new_class, @protocol (MySecondProtocol)); 246 247 objc_registerClassPair (new_class); 248 249 if (std::strcmp (class_getName (new_class), "MySubSubClass") != 0) 250 abort (); 251 252 if (class_getSuperclass (new_class) != objc_getClass ("MySubClass")) 253 abort (); 254 255 if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol))) 256 abort (); 257 } 258 259 /* TODO - Test it when implemented in the GNU Runtime */ 260 /* std::cout << "Testing objc_removeAssociatedObjects ()...\n"; */ 261 262 /* TODO - Test it when implemented in the GNU Runtime */ 263 /* std::cout << "Testing objc_setAssociatedObject ()...\n"; */ 264 265 return (0); 266} 267