1 /* Test the Modern GNU Objective-C Runtime API.
3 This is test 'method', covering all functions starting with 'method'. */
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" } { "" } } */
9 /* To get the modern GNU Objective-C Runtime API, you include
11 #include <objc/runtime.h>
16 @interface MyRootClass
23 @implementation MyRootClass
24 + alloc { return class_createInstance (self, 0); }
25 - init { return self; }
26 + initialize { return self; }
33 @protocol MySecondProtocol
34 - (id) setVariable: (id)value;
37 @interface MySubClass : MyRootClass <MyProtocol>
39 - (void) setVariable: (id)value;
44 @implementation MySubClass
45 - (void) setVariable: (id)value { variable_ivar = value; }
46 - (id) variable { return variable_ivar; }
47 - (id) constant { return nil; }
51 int main(int argc, void **args)
53 /* Functions are tested in alphabetical order. */
55 printf ("Testing method_copyArgumentType () ...\n");
57 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
58 @selector (setVariable:));
59 char *type = method_copyArgumentType (method, 2);
61 if (type == NULL || type[0] != '@')
65 printf ("Testing method_copyReturnType () ...\n");
67 Method method = class_getClassMethod (objc_getClass ("MyRootClass"),
69 char *type = method_copyReturnType (method);
71 /* Check that it returns an object. */
72 if (type == NULL || type[0] != '@')
76 printf ("Testing method_exchangeImplementations () ...\n");
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];
84 /* Check that things work as expected before the swap. */
85 [object setVariable: object];
87 if ([object variable] != object || [object constant] != nil)
90 /* Swap the methods. */
91 method_exchangeImplementations (method_a, method_b);
93 /* Check that behavior has changed. */
94 if ([object variable] != nil || [object constant] != object)
97 /* Swap the methods again. */
98 method_exchangeImplementations (method_a, method_b);
100 /* Check that behavior is back to normal. */
101 if ([object variable] != object || [object constant] != nil)
105 printf ("Testing method_getArgumentType () ...\n");
107 Method method = class_getInstanceMethod (objc_getClass ("MyRootClass"),
111 method_getArgumentType (method, 1, type, 16);
113 /* Check the second argument (_cmd), which should be a SEL. */
118 printf ("Testing method_getDescription () ...\n");
120 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
121 @selector (variable));
122 struct objc_method_description *description = method_getDescription (method);
124 if (strcmp (sel_getName (description->name), "variable") != 0)
127 if (method_getDescription (NULL) != NULL)
131 printf ("Testing method_getImplementation () ...\n");
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];
139 imp = (set_variable_function)(method_getImplementation (method));
141 (*imp)(object, @selector (setVariable:), object);
143 if ([object variable] != object)
147 printf ("Testing method_getName () ...\n");
149 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
150 @selector (setVariable:));
151 if (strcmp (sel_getName (method_getName (method)), "setVariable:") != 0)
155 printf ("Testing method_getNumberOfArguments () ...\n");
157 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
158 @selector (setVariable:));
159 if (method_getNumberOfArguments (method) != 3)
162 method = class_getInstanceMethod (objc_getClass ("MySubClass"),
163 @selector (variable));
164 if (method_getNumberOfArguments (method) != 2)
168 printf ("Testing method_getTypeEncoding () ...\n");
170 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
171 @selector (setVariable:));
172 const char *types = method_getTypeEncoding (method);
174 /* Check that method type string starts with 'v' (void) */
175 if (types == NULL || types[0] != 'v')
179 printf ("Testing method_getReturnType () ...\n");
181 Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
182 @selector (setVariable:));
185 method_getReturnType (method, type, 16);
190 method_getReturnType (NULL, type, 16);
196 printf ("Testing method_setImplementation () ...\n");
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];
206 /* Check that things work as expected before the swap. */
207 [object setVariable: object];
209 if ([object variable] != object || [object constant] != nil)
212 /* Have 'variable' use the same implementation as 'constant'. */
213 if (method_setImplementation (method_a, original_imp_b) != original_imp_a)
216 /* Check that behavior has changed. */
217 if ([object variable] != nil || [object constant] != nil)
220 /* Put the original method back. */
221 if (method_setImplementation (method_a, original_imp_a) != original_imp_b)
224 /* Check that behavior is back to normal. */
225 if ([object variable] != object || [object constant] != nil)