1/* Test the Modern GNU Objective-C Runtime API. 2 3 This is test 'method', covering all functions starting with 'method'. */ 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- (id) constant; 42@end 43 44@implementation MySubClass 45- (void) setVariable: (id)value { variable_ivar = value; } 46- (id) variable { return variable_ivar; } 47- (id) constant { return nil; } 48@end 49 50 51int main () 52{ 53 /* Functions are tested in alphabetical order. */ 54 55 std::cout <<"Testing method_copyArgumentType () ...\n"; 56 { 57 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 58 @selector (setVariable:)); 59 char *type = method_copyArgumentType (method, 2); 60 61 if (type == NULL || type[0] != '@') 62 abort (); 63 } 64 65 std::cout << "Testing method_copyReturnType () ...\n"; 66 { 67 Method method = class_getClassMethod (objc_getClass ("MyRootClass"), 68 @selector (alloc)); 69 char *type = method_copyReturnType (method); 70 71 /* Check that it returns an object. */ 72 if (type == NULL || type[0] != '@') 73 abort (); 74 } 75 76 std::cout << "Testing method_exchangeImplementations () ...\n"; 77 { 78 Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"), 79 @selector (variable)); 80 Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"), 81 @selector (constant)); 82 MySubClass *object = [[MySubClass alloc] init]; 83 84 /* Check that things work as expected before the swap. */ 85 [object setVariable: object]; 86 87 if ([object variable] != object || [object constant] != nil) 88 abort (); 89 90 /* Swap the methods. */ 91 method_exchangeImplementations (method_a, method_b); 92 93 /* Check that behavior has changed. */ 94 if ([object variable] != nil || [object constant] != object) 95 abort (); 96 97 /* Swap the methods again. */ 98 method_exchangeImplementations (method_a, method_b); 99 100 /* Check that behavior is back to normal. */ 101 if ([object variable] != object || [object constant] != nil) 102 abort (); 103 } 104 105 std::cout << "Testing method_getArgumentType () ...\n"; 106 { 107 Method method = class_getInstanceMethod (objc_getClass ("MyRootClass"), 108 @selector (init)); 109 char type[16]; 110 111 method_getArgumentType (method, 1, type, 16); 112 113 /* Check the second argument (_cmd), which should be a SEL. */ 114 if (type[0] != ':') 115 abort (); 116 } 117 118 std::cout << "Testing method_getDescription () ...\n"; 119 { 120 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 121 @selector (variable)); 122 struct objc_method_description *description = method_getDescription (method); 123 124 if (std::strcmp (sel_getName (description->name), "variable") != 0) 125 abort (); 126 127 if (method_getDescription (NULL) != NULL) 128 abort (); 129 } 130 131 std::cout << "Testing method_getImplementation () ...\n"; 132 { 133 typedef void (*set_variable_function) (id receiver, SEL _cmd, id variable); 134 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 135 @selector (setVariable:)); 136 set_variable_function imp; 137 MySubClass *object = [[MySubClass alloc] init]; 138 139 imp = (set_variable_function)(method_getImplementation (method)); 140 141 (*imp)(object, @selector (setVariable:), object); 142 143 if ([object variable] != object) 144 abort (); 145 } 146 147 std::cout << "Testing method_getName () ...\n"; 148 { 149 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 150 @selector (setVariable:)); 151 if (std::strcmp (sel_getName (method_getName (method)), "setVariable:") != 0) 152 abort (); 153 } 154 155 std::cout << "Testing method_getNumberOfArguments () ...\n"; 156 { 157 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 158 @selector (setVariable:)); 159 if (method_getNumberOfArguments (method) != 3) 160 abort (); 161 162 method = class_getInstanceMethod (objc_getClass ("MySubClass"), 163 @selector (variable)); 164 if (method_getNumberOfArguments (method) != 2) 165 abort (); 166 } 167 168 std::cout << "Testing method_getTypeEncoding () ...\n"; 169 { 170 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 171 @selector (setVariable:)); 172 const char *types = method_getTypeEncoding (method); 173 174 /* Check that method type string starts with 'v' (void) */ 175 if (types == NULL || types[0] != 'v') 176 abort (); 177 } 178 179 std::cout << "Testing method_getReturnType () ...\n"; 180 { 181 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 182 @selector (setVariable:)); 183 char type[16]; 184 185 method_getReturnType (method, type, 16); 186 187 if (type[0] != 'v') 188 abort (); 189 190 method_getReturnType (NULL, type, 16); 191 192 if (type[0] != 0) 193 abort (); 194 } 195 196 std::cout << "Testing method_setImplementation () ...\n"; 197 { 198 Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"), 199 @selector (variable)); 200 Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"), 201 @selector (constant)); 202 IMP original_imp_a = method_getImplementation (method_a); 203 IMP original_imp_b = method_getImplementation (method_b); 204 MySubClass *object = [[MySubClass alloc] init]; 205 206 /* Check that things work as expected before the swap. */ 207 [object setVariable: object]; 208 209 if ([object variable] != object || [object constant] != nil) 210 abort (); 211 212 /* Have 'variable' use the same implementation as 'constant'. */ 213 if (method_setImplementation (method_a, original_imp_b) != original_imp_a) 214 abort (); 215 216 /* Check that behavior has changed. */ 217 if ([object variable] != nil || [object constant] != nil) 218 abort (); 219 220 /* Put the original method back. */ 221 if (method_setImplementation (method_a, original_imp_a) != original_imp_b) 222 abort (); 223 224 /* Check that behavior is back to normal. */ 225 if ([object variable] != object || [object constant] != nil) 226 abort (); 227 } 228 229 return (0); 230} 231