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