OSDN Git Service

2011-01-08 Dominique d'Humieres <dominiq@lps.ens.fr>
[pf3gnuchains/gcc-fork.git] / gcc / testsuite / objc.dg / gnu-api-2-class.m
1 /* Test the Modern GNU Objective-C Runtime API.
2
3   This is test 'class', covering all functions starting with 'class'.  */
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 <stdio.h>
14 #include <string.h>
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 @interface MyOtherSubClass : MySubClass
49 @end
50
51 @implementation MyOtherSubClass
52 @end
53
54 @interface DifferentClass : MyRootClass
55 - (id) myClass;
56 - (id) self;
57 @end
58
59 @implementation DifferentClass
60 - (id) myClass { return object_getClass (self); }
61 - (id) self { return self; }
62 @end
63
64 @interface MySubClass (MySelf)
65 - (id) mySelf;
66 @end
67
68 /* Hack to calculate the log2 of a byte alignment.  */
69 unsigned char
70 log_2_of (unsigned int x)
71 {
72   unsigned char result = 0;
73
74   /* We count how many times we need to divide by 2 before we reach 1.
75      This algorithm is good enough for the small numbers (such as 8,
76      16 or 64) that we have to deal with.  */
77   while (x > 1)
78     {
79       x = x / 2;
80       result++;
81     }
82
83   return result;
84 }
85
86 int main(int argc, void **args)
87 {
88   /* Functions are tested in alphabetical order.  */
89
90   printf ("Testing class_addIvar ()...\n");
91   {
92     Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
93
94     if (new_class == Nil)
95       abort ();
96     
97     if (! class_addIvar (new_class, "variable2_ivar", sizeof (id),
98                          log_2_of (__alignof__ (id)), @encode (id)))
99       abort ();
100
101     if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char),
102                          log_2_of (__alignof__ (unsigned char)), @encode (unsigned char)))
103       abort ();
104
105     if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long),
106                          log_2_of (__alignof__ (unsigned long)), @encode (unsigned long)))
107       abort ();
108
109     objc_registerClassPair (new_class);    
110
111     {
112       MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init];
113       Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar");
114       Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar");
115       Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar");
116
117       if (variable2 == NULL  || variable3 == NULL  ||  variable4 == NULL)
118         abort ();
119       
120       if (strcmp (ivar_getName (variable2), "variable2_ivar") != 0)
121         abort ();
122
123       if (strcmp (ivar_getName (variable3), "variable3_ivar") != 0)
124         abort ();
125
126       if (strcmp (ivar_getName (variable4), "variable4_ivar") != 0)
127         abort ();
128
129       {
130         unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3));
131         unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4));
132
133         object_setIvar (o, variable2, new_class);
134         *var3 = 230;
135         *var4 = 89000L;
136
137         if (object_getIvar (o, variable2) != new_class)
138           abort ();
139
140         if (*var3 != 230)
141           abort ();
142
143         if (*var4 != 89000L)
144           abort ();
145       }
146     }
147   }
148
149   printf ("Testing class_addMethod ()...\n");
150   {
151     Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
152     Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
153     Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable));
154
155     if (new_class == Nil)
156       abort ();
157     
158     if (! class_addIvar (new_class, "variable_ivar", sizeof (id),
159                          log_2_of (__alignof__ (id)), @encode (id)))
160       abort ();
161
162     if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1),
163                            method_getTypeEncoding (method1)))
164       abort ();
165
166     if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
167                            method_getTypeEncoding (method2)))
168       abort ();
169
170     /* Test that if the method already exists in the class,
171        class_addMethod() returns NO.  */
172     if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
173                          method_getTypeEncoding (method2)))
174       abort ();
175
176     objc_registerClassPair (new_class);    
177
178     /* Now, MySubClass2 is basically the same as MySubClass!  We'll
179        use the variable and setVariable: methods on it.  */
180     {
181       MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init];
182
183       [o setVariable: o];
184
185       if ([o variable] != o)
186         abort ();
187     }
188
189     /* Now, try that if you take an existing class and try to add an
190        already existing method, class_addMethod returns NO.  This is
191        subtly different from before, when 'new_class' was still in
192        construction.  Now it's a real class and the libobjc internals
193        differ between the two cases.  */
194     if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
195                          method_getTypeEncoding (method2)))
196       abort ();
197   }
198
199   printf ("Testing class_addProtocol ()...\n");
200   {
201     if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
202       abort ();
203     
204     if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
205       abort ();
206
207     if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
208       abort ();
209   }
210
211   printf ("Testing class_conformsToProtocol ()...\n");
212   {
213     if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol)))
214       abort ();
215
216     if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
217       abort ();
218
219     /* Test that class_conformsToProtocol checks the class, but not
220        superclasses.  */
221     if (class_conformsToProtocol (objc_getClass ("MyOtherSubClass"), @protocol (MyProtocol)))
222       abort ();
223   }
224
225   printf ("Testing class_copyIvarList ()...\n");
226   {
227     unsigned int count;
228     Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count);
229
230     if (count != 1)
231       abort ();
232
233     if (strcmp (ivar_getName (list[0]), "variable_ivar") != 0)
234       abort ();
235     
236     if (list[1] != NULL)
237       abort ();
238   }
239
240   printf ("Testing class_copyMethodList ()...\n");
241   {
242     unsigned int count;
243     Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count);
244
245     if (count != 2)
246       abort ();
247     
248     if (! ((strcmp (sel_getName (method_getName (list[0])), "variable") == 0
249             && strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
250            || (strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
251                && strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
252       abort ();
253     
254     if (list[2] != NULL)
255       abort ();
256   }
257
258   /* TODO: Test new ABI (when available).  */
259   printf ("Testing class_copyPropertyList ()...\n");
260   {
261     unsigned int count;
262     objc_property_t * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count);
263
264     if (count != 0  ||  list != NULL)
265       abort ();
266   }
267
268   printf ("Testing class_copyProtocolList ()...\n");
269   {
270     unsigned int count;
271     Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count);
272
273     /* Remember that we added MySecondProtocol in the test above.  */
274     if (count != 2)
275       abort ();
276
277     if (! ((strcmp (protocol_getName (list[0]), "MyProtocol") == 0
278             && strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
279            || (strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
280                && strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
281       abort ();
282     
283     if (list[2] != NULL)
284       abort ();
285   }
286
287   printf ("Testing class_createInstance ()...\n");
288   {
289     MySubClass *object = [[MySubClass alloc] init];
290
291     [object setVariable: object];
292     if ([object variable] != object)
293       abort ();
294   }
295
296   printf ("Testing class_getClassMethod ()...\n");
297   {
298     Method method = class_getClassMethod (objc_getClass ("MySubClass"),
299                                           @selector(alloc));
300
301     if (method == NULL)
302       abort ();
303
304     if (strcmp (sel_getName (method_getName (method)), "alloc") != 0)
305       abort ();
306
307     if (class_getClassMethod (objc_getClass ("MySubClass"), 
308                               @selector(variable)))
309       abort ();
310   }
311
312   printf ("Testing class_getClassVariable ()...\n");
313   {
314     if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar"))
315       abort ();
316   }
317
318   printf ("Testing class_getInstanceMethod ()...\n");
319   {
320     Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 
321                                              @selector(variable));
322
323     if (method == NULL)
324       abort ();
325
326     if (strcmp (sel_getName (method_getName (method)), "variable") != 0)
327       abort ();
328
329     if (class_getInstanceMethod (objc_getClass ("MySubClass"), 
330                                  @selector(alloc)))
331       abort ();
332   }
333
334   printf ("Testing class_getInstanceSize ()...\n");
335   {
336     if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object))
337       abort ();
338   }
339
340   printf ("Testing class_getInstanceVariable ()...\n");
341   {
342     Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
343
344     if (variable == NULL)
345       abort ();
346
347     if (strcmp (ivar_getName (variable), "variable_ivar") != 0)
348       abort ();
349
350     if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no"))
351       abort ();
352   }
353
354   printf ("Testing class_getIvarLayout ()...\n");
355   {
356     if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL)
357       abort ();
358   }
359
360   printf ("Testing class_getMethodImplementation ()...\n");
361   {
362     MySubClass *object = [[MySubClass alloc] init];
363     IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"), 
364                                              @selector(variable));
365
366     if (imp == NULL)
367       abort ();
368
369     [object setVariable: object];
370
371     if ((*imp)(object, @selector(variable)) != object)
372       abort ();
373   }
374
375   /* This function does not exist with the GNU runtime.  */
376   /* printf ("Testing class_getMethodImplementation_stret ()...\n"); */
377
378   printf ("Testing class_getName ()...\n");
379   {
380     if (strcmp (class_getName (objc_getClass ("MyRootClass")),
381                 "MyRootClass") != 0)
382       abort ();
383   }
384
385   /* TODO: Test new ABI (when available).  */
386   printf ("Testing class_getProperty ()...\n");
387   {
388     if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL)
389       abort ();
390   }
391
392   printf ("Testing class_getSuperclass ()...\n");
393   {
394     MySubClass *object = [[MySubClass alloc] init];
395     if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
396       abort ();
397   }
398
399   printf ("Testing class_getVersion ()...\n");
400   {
401     if (class_getVersion (objc_getClass ("MySubClass")) != 0)
402       abort ();
403   }
404
405    printf ("Testing class_getWeakIvarLayout ()...\n");
406   {
407     if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL)
408       abort ();
409   }
410
411   printf ("Testing class_isMetaClass ()...\n");
412   {
413     MySubClass *object = [[MySubClass alloc] init];
414     if (class_isMetaClass (object_getClass (object)) 
415         || ! class_isMetaClass (object_getClass (object_getClass (object))))
416       abort ();
417   }
418
419   printf ("Testing class_replaceMethod ()...\n");
420   {
421     Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"),
422                                                  @selector (myClass));
423     Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"),
424                                                  @selector (variable));
425     const char *new_types = method_getTypeEncoding (new_method);
426     IMP new_imp = method_getImplementation (new_method);
427     const char *old_types = method_getTypeEncoding (old_method);
428     IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
429                                        method_getImplementation (new_method),
430                                        method_getTypeEncoding (new_method));
431     MySubClass *o = [[MySubClass alloc] init];
432
433     [o setVariable: o];
434
435     /* Try the new method implementation.  */
436     if ([o variable] != objc_getClass ("MySubClass"))
437       abort ();
438
439     /* Put the original method back.  */
440     class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
441                          old_imp, old_types);
442
443     /* Test it's back to what it was.  */
444     if ([o variable] != o)
445       abort ();    
446
447     {
448       DifferentClass *o = [[DifferentClass alloc] init];
449
450       /* Finally, try adding a new method.  */
451       class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf),
452                            new_imp, new_types);
453       
454       if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass"))
455         abort ();
456     }
457   }
458
459   printf ("Testing class_respondsToSelector ()...\n");
460   {
461     if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:)))
462       abort ();
463
464     if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:)))
465       abort ();
466   }
467
468   /* This is not really implemented with the GNU runtime.  */
469   /* printf ("Testing class_setIvarLayout ()...\n"); */
470
471   printf ("Testing class_setVersion ()...\n");
472   {
473     class_setVersion (objc_getClass ("MySubClass"), 45);
474     
475     if (class_getVersion (objc_getClass ("MySubClass")) != 45)
476       abort ();
477
478     class_setVersion (objc_getClass ("MySubClass"), 46);
479
480     if (class_getVersion (objc_getClass ("MySubClass")) != 46)
481       abort ();
482   }
483
484   /* This is not really implemented with the GNU runtime.  */
485   /* printf ("Testing class_setWeakIvarLayout ()...\n"); */
486
487   return 0;
488 }