In libobjc/: 2010-12-24 Nicola Pero <nicola.pero@meta-innovation.com>
[official-gcc.git] / gcc / testsuite / obj-c++.dg / gnu-api-2-class.mm
blob18c3393fa1e905de4dae416135639712db301d7a
1 /* Test the Modern GNU Objective-C Runtime API.
3   This is test 'class', covering all functions starting with 'class'.  */
5 /* { dg-do run } */
6 /* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
8 /* To get the modern GNU Objective-C Runtime API, you include
9    objc/runtime.h.  */
10 #include <objc/runtime.h>
11 #include <stdlib.h>
12 #include <iostream>
13 #include <cstring>
15 @interface MyRootClass
16 { Class isa; }
17 + alloc;
18 - init;
19 @end
21 @implementation MyRootClass
22 + alloc { return class_createInstance (self, 0); }
23 - init  { return self; }
24 @end
26 @protocol MyProtocol
27 - (id) variable;
28 @end
30 @protocol MySecondProtocol
31 - (id) setVariable: (id)value;
32 @end
34 @interface MySubClass : MyRootClass <MyProtocol>
35 { id variable_ivar; }
36 - (void) setVariable: (id)value;
37 - (id) variable;
38 @end
40 @implementation MySubClass
41 - (void) setVariable: (id)value { variable_ivar = value; }
42 - (id) variable { return variable_ivar; }
43 @end
45 @interface MyOtherSubClass : MySubClass
46 @end
48 @implementation MyOtherSubClass
49 @end
51 @interface DifferentClass : MyRootClass
52 - (id) myClass;
53 - (id) self;
54 @end
56 @implementation DifferentClass
57 - (id) myClass { return object_getClass (self); }
58 - (id) self { return self; }
59 @end
61 @interface MySubClass (MySelf)
62 - (id) mySelf;
63 @end
65 /* Hack to calculate the log2 of a byte alignment.  */
66 unsigned char
67 log_2_of (unsigned int x)
69   unsigned char result = 0;
71   /* We count how many times we need to divide by 2 before we reach 1.
72      This algorithm is good enough for the small numbers (such as 8,
73      16 or 64) that we have to deal with.  */
74   while (x > 1)
75     {
76       x = x / 2;
77       result++;
78     }
80   return result;
83 int main ()
85   /* Functions are tested in alphabetical order.  */
87   std::cout << "Testing class_addIvar ()...\n";
88   {
89     Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
91     if (new_class == Nil)
92       abort ();
93     
94     if (! class_addIvar (new_class, "variable2_ivar", sizeof (id),
95                          log_2_of (__alignof__ (id)), @encode (id)))
96       abort ();
98     if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char),
99                          log_2_of (__alignof__ (unsigned char)), @encode (unsigned char)))
100       abort ();
102     if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long),
103                          log_2_of (__alignof__ (unsigned long)), @encode (unsigned long)))
104       abort ();
106     objc_registerClassPair (new_class);    
108     {
109       MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init];
110       Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar");
111       Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar");
112       Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar");
114       if (variable2 == NULL  || variable3 == NULL  ||  variable4 == NULL)
115         abort ();
116       
117       if (std::strcmp (ivar_getName (variable2), "variable2_ivar") != 0)
118         abort ();
120       if (std::strcmp (ivar_getName (variable3), "variable3_ivar") != 0)
121         abort ();
123       if (std::strcmp (ivar_getName (variable4), "variable4_ivar") != 0)
124         abort ();
126       {
127         unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3));
128         unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4));
130         object_setIvar (o, variable2, new_class);
131         *var3 = 230;
132         *var4 = 89000L;
134         if (object_getIvar (o, variable2) != new_class)
135           abort ();
137         if (*var3 != 230)
138           abort ();
140         if (*var4 != 89000L)
141           abort ();
142       }
143     }
144   }
146   std::cout << "Testing class_addMethod ()...\n";
147   {
148     Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
149     Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
150     Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable));
152     if (new_class == Nil)
153       abort ();
154     
155     if (! class_addIvar (new_class, "variable_ivar", sizeof (id),
156                          log_2_of (__alignof__ (id)), @encode (id)))
157       abort ();
159     if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1),
160                            method_getTypeEncoding (method1)))
161       abort ();
163     if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
164                            method_getTypeEncoding (method2)))
165       abort ();
167     /* Test that if the method already exists in the class,
168        class_addMethod() returns NO.  */
169     if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
170                          method_getTypeEncoding (method2)))
171       abort ();
173     objc_registerClassPair (new_class);    
175     /* Now, MySubClass2 is basically the same as MySubClass!  We'll
176        use the variable and setVariable: methods on it.  */
177     {
178       MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init];
180       [o setVariable: o];
182       if ([o variable] != o)
183         abort ();
184     }
186     /* Now, try that if you take an existing class and try to add an
187        already existing method, class_addMethod returns NO.  This is
188        subtly different from before, when 'new_class' was still in
189        construction.  Now it's a real class and the libobjc internals
190        differ between the two cases.  */
191     if (class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
192                          method_getTypeEncoding (method2)))
193       abort ();
194   }
196   std::cout << "Testing class_addProtocol ()...\n";
197   {
198     if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
199       abort ();
200     
201     if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
202       abort ();
204     if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
205       abort ();
206   }
208   std::cout << "Testing class_conformsToProtocol ()...\n";
209   {
210     if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol)))
211       abort ();
213     if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
214       abort ();
216     /* Test that class_conformsToProtocol checks the class, but not
217        superclasses.  */
218     if (class_conformsToProtocol (objc_getClass ("MyOtherSubClass"), @protocol (MyProtocol)))
219       abort ();
220   }
222   std::cout << "Testing class_copyIvarList ()...\n";
223   {
224     unsigned int count;
225     Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count);
227     if (count != 1)
228       abort ();
230     if (std::strcmp (ivar_getName (list[0]), "variable_ivar") != 0)
231       abort ();
232     
233     if (list[1] != NULL)
234       abort ();
235   }
237   std::cout << "Testing class_copyMethodList ()...\n";
238   {
239     unsigned int count;
240     Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count);
242     if (count != 2)
243       abort ();
244     
245     if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0
246             && std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
247            || (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
248                && std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
249       abort ();
250     
251     if (list[2] != NULL)
252       abort ();
253   }
255   /* TODO: Test new ABI (when available).  */
256   std::cout << "Testing class_copyPropertyList ()...\n";
257   {
258     unsigned int count;
259     Property * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count);
261     if (count != 0  ||  list != NULL)
262       abort ();
263   }
265   std::cout << "Testing class_copyProtocolList ()...\n";
266   {
267     unsigned int count;
268     Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count);
270     /* Remember that we added MySecondProtocol in the test above.  */
271     if (count != 2)
272       abort ();
274     if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
275             && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
276            || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
277                && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
278       abort ();
279     
280     if (list[2] != NULL)
281       abort ();
282   }
284   std::cout << "Testing class_createInstance ()...\n";
285   {
286     MySubClass *object = [[MySubClass alloc] init];
288     [object setVariable: object];
289     if ([object variable] != object)
290       abort ();
291   }
293   std::cout << "Testing class_getClassMethod ()...\n";
294   {
295     Method method = class_getClassMethod (objc_getClass ("MySubClass"),
296                                           @selector(alloc));
298     if (method == NULL)
299       abort ();
301     if (std::strcmp (sel_getName (method_getName (method)), "alloc") != 0)
302       abort ();
304     if (class_getClassMethod (objc_getClass ("MySubClass"), 
305                               @selector(variable)))
306       abort ();
307   }
309   std::cout << "Testing class_getClassVariable ()...\n";
310   {
311     if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar"))
312       abort ();
313   }
315   std::cout << "Testing class_getInstanceMethod ()...\n";
316   {
317     Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), 
318                                              @selector(variable));
320     if (method == NULL)
321       abort ();
323     if (std::strcmp (sel_getName (method_getName (method)), "variable") != 0)
324       abort ();
326     if (class_getInstanceMethod (objc_getClass ("MySubClass"), 
327                                  @selector(alloc)))
328       abort ();
329   }
331   std::cout << "Testing class_getInstanceSize ()...\n";
332   {
333     if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object))
334       abort ();
335   }
337   std::cout << "Testing class_getInstanceVariable ()...\n";
338   {
339     Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
341     if (variable == NULL)
342       abort ();
344     if (std::strcmp (ivar_getName (variable), "variable_ivar") != 0)
345       abort ();
347     if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no"))
348       abort ();
349   }
351   std::cout << "Testing class_getIvarLayout ()...\n";
352   {
353     if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL)
354       abort ();
355   }
357   std::cout << "Testing class_getMethodImplementation ()...\n";
358   {
359     MySubClass *object = [[MySubClass alloc] init];
360     IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"), 
361                                              @selector(variable));
363     if (imp == NULL)
364       abort ();
366     [object setVariable: object];
368     if ((*imp)(object, @selector(variable)) != object)
369       abort ();
370   }
372   /* This function does not exist with the GNU runtime.  */
373   /* std::cout << "Testing class_getMethodImplementation_stret ()...\n"; */
375   std::cout << "Testing class_getName ()...\n";
376   {
377     if (std::strcmp (class_getName (objc_getClass ("MyRootClass")),
378                 "MyRootClass") != 0)
379       abort ();
380   }
382   /* TODO: Test new ABI (when available).  */
383   std::cout << "Testing class_getProperty ()...\n";
384   {
385     if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL)
386       abort ();
387   }
389   std::cout << "Testing class_getSuperclass ()...\n";
390   {
391     MySubClass *object = [[MySubClass alloc] init];
392     if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
393       abort ();
394   }
396   std::cout << "Testing class_getVersion ()...\n";
397   {
398     if (class_getVersion (objc_getClass ("MySubClass")) != 0)
399       abort ();
400   }
402    std::cout << "Testing class_getWeakIvarLayout ()...\n";
403   {
404     if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL)
405       abort ();
406   }
408   std::cout << "Testing class_isMetaClass ()...\n";
409   {
410     MySubClass *object = [[MySubClass alloc] init];
411     if (class_isMetaClass (object_getClass (object)) 
412         || ! class_isMetaClass (object_getClass (object_getClass (object))))
413       abort ();
414   }
416   std::cout << "Testing class_replaceMethod ()...\n";
417   {
418     Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"),
419                                                  @selector (myClass));
420     Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"),
421                                                  @selector (variable));
422     const char *new_types = method_getTypeEncoding (new_method);
423     IMP new_imp = method_getImplementation (new_method);
424     const char *old_types = method_getTypeEncoding (old_method);
425     IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
426                                        method_getImplementation (new_method),
427                                        method_getTypeEncoding (new_method));
428     MySubClass *o = [[MySubClass alloc] init];
430     [o setVariable: o];
432     /* Try the new method implementation.  */
433     if ([o variable] != objc_getClass ("MySubClass"))
434       abort ();
436     /* Put the original method back.  */
437     class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
438                          old_imp, old_types);
440     /* Test it's back to what it was.  */
441     if ([o variable] != o)
442       abort ();    
444     {
445       DifferentClass *o = [[DifferentClass alloc] init];
447       /* Finally, try adding a new method.  */
448       class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf),
449                            new_imp, new_types);
450       
451       if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass"))
452         abort ();
453     }
454   }
456   std::cout << "Testing class_respondsToSelector ()...\n";
457   {
458     if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:)))
459       abort ();
461     if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:)))
462       abort ();
463   }
465   /* This is not really implemented with the GNU runtime.  */
466   /* std::cout << "Testing class_setIvarLayout ()...\n"; */
468   std::cout << "Testing class_setVersion ()...\n";
469   {
470     class_setVersion (objc_getClass ("MySubClass"), 45);
471     
472     if (class_getVersion (objc_getClass ("MySubClass")) != 45)
473       abort ();
475     class_setVersion (objc_getClass ("MySubClass"), 46);
477     if (class_getVersion (objc_getClass ("MySubClass")) != 46)
478       abort ();
479   }
481   /* This is not really implemented with the GNU runtime.  */
482   /* std::cout << "Testing class_setWeakIvarLayout ()...\n"; */
484   return (0);