2014-07-11 Edward Smith-Rowland <3dw4rd@verizon.net>
[official-gcc.git] / gcc / testsuite / obj-c++.dg / gnu-api-2-objc.mm
blobe5b1a69ed042e36ae69d210a0b142d6f4b1e5af2
1 /* Test the Modern GNU Objective-C Runtime API.
3   This is test 'objc', covering all functions starting with 'objc'.  */
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" } { "" } } */
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>
16 @interface MyRootClass
17 { Class isa; }
18 + alloc;
19 - init;
20 + initialize;
21 @end
23 @implementation MyRootClass
24 + alloc { return class_createInstance (self, 0); }
25 - init  { return self; }
26 + initialize { return self; }
27 @end
29 @protocol MyProtocol
30 - (id) variable;
31 @end
33 @protocol MySecondProtocol
34 - (id) setVariable: (id)value;
35 @end
37 @interface MySubClass : MyRootClass <MyProtocol>
38 { id variable_ivar; }
39 - (void) setVariable: (id)value;
40 - (id) variable;
41 @end
43 @implementation MySubClass
44 - (void) setVariable: (id)value { variable_ivar = value; }
45 - (id) variable { return variable_ivar; }
46 @end
48 /* Hack to calculate the log2 of a byte alignment.  */
49 unsigned char
50 log_2_of (unsigned int x)
52   unsigned char result = 0;
54   /* We count how many times we need to divide by 2 before we reach 1.
55      This algorithm is good enough for the small numbers (such as 8,
56      16 or 64) that we have to deal with.  */
57   while (x > 1)
58     {
59       x = x / 2;
60       result++;
61     }
63   return result;
66 int main ()
68   /* Functions are tested in alphabetical order.  */
70   std::cout << "Testing objc_allocateClassPair ()...\n";
71   {
72     Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0);
73     Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
75     /* A new root class would obviously need at least an 'isa'
76        instance variable.  */
77     class_addIvar (new_root_class, "isa", sizeof (Class), log_2_of (__alignof__ (Class)),
78                    @encode (Class));
80     objc_registerClassPair (new_root_class);
81     objc_registerClassPair (new_class);
83     if (std::strcmp (class_getName (new_class), "MyNewSubClass") != 0)
84       abort ();
86     if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
87       abort ();
89     if (std::strcmp (class_getName (new_root_class), "MyNewRootClass") != 0)
90       abort ();
92     if (class_getSuperclass (new_root_class) != Nil)
93       abort ();
95     {
96       MySubClass *o = [[(Class)objc_getClass ("MyNewSubClass") alloc] init];
97       
98       if (object_getClass (o) != objc_getClass ("MyNewSubClass"))
99         abort ();
100     }
101   }
103   std::cout << "Testing objc_copyProtocolList ()...\n";
104   {
105     /* Make sure both our two protocols are known to the runtime.  */
106     id my_protocol = @protocol (MyProtocol);
107     id my_second_protocol = @protocol (MySecondProtocol);
108     unsigned int count;
109     Protocol ** list = objc_copyProtocolList (&count);
111     if (count != 2)
112       abort ();
114     if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
115             && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
116            || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
117                && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
118       abort ();
119     
120     if (list[2] != NULL)
121       abort ();
122   }
124   std::cout << "Testing objc_disposeClassPair ()...\n";
125   {
126     Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
127     Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass2", 0);
129     if (new_class == Nil)
130       abort ();
132     /* Add a bit of everything to the class to exercise undoing all these changes.  */
134     /* Instance variable.  */
135     class_addIvar (new_class, "my_variable", sizeof (float), log_2_of (__alignof__ (float)), @encode (float));
137     /* Instance method.  */
138     class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method),
139                      method_getTypeEncoding (method));
141     /* Class method.  */
142     class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method),
143                      method_getTypeEncoding (method));
145     /* Protocol.  */
146     class_addProtocol (new_class, @protocol (MyProtocol));
148     objc_disposeClassPair (new_class);
149   }
151   /* This function currently does not exist with the GNU runtime.  */
152   /* std::cout << "Testing objc_duplicateClass ()...\n"; */
154   /* TODO - Test it when implemented in the GNU Runtime */
155   /*  std::cout << "Testing objc_getAssociatedObject ()...\n";  */
157   std::cout << "Testing objc_getClass ()...\n";
158   {
159     if (std::strcmp (class_getName (objc_getClass ("MySubClass")),
160                         "MySubClass") != 0)
161       abort ();
162   }
164   std::cout << "Testing objc_getClassList ()...\n";
165   {
166     Class *list;
167     int i, count, other_count;
168     count = objc_getClassList (NULL, 0);
170     /* count most likely will be 5, (MyRootClass, MySubClass,
171        Protocol, Object, NXConstantString).  */
172     if (count < 3)
173       abort ();
174     
175     list = (Class *)(malloc (sizeof (Class) * count));
176     other_count = objc_getClassList (list, count);
178     if (other_count != count)
179       abort ();
181     /* Spot-check: search for class 'MyRootClass' in the list.  */
182     for (i = 0; i < count; i++)
183       {
184         if (std::strcmp (class_getName (list[i]), "MyRootClass") == 0)
185           break;
186       }
187     if (i == count)
188       abort ();
190     /* Spot-check: search for class 'MySubClass' in the list.  */
191     for (i = 0; i < count; i++)
192       {
193         if (std::strcmp (class_getName (list[i]), "MySubClass") == 0)
194           break;
195       }
196     if (i == count)
197       abort ();
199     /* Spot-check: search for class 'Protocol' in the list.  */
200     for (i = 0; i < count; i++)
201       {
202         if (std::strcmp (class_getName (list[i]), "Protocol") == 0)
203           break;
204       }
205     if (i == count)
206       abort ();
207   }
209   /* This function does not exist with the GNU runtime.  */
210   /* std::cout << "Testing objc_getFutureClass ()...\n"; */
212   std::cout << "Testing objc_getMetaClass ()...\n";
213   {
214     if (! class_isMetaClass (objc_getMetaClass ("MyRootClass")))
215       abort ();
216   }
218   std::cout << "Testing objc_getProtocol ()...\n";
219   {
220     if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol)))
221       abort ();
222   }
224   std::cout << "Testing objc_getRequiredClass ()...\n";
225   {
226     if (std::strcmp (class_getName (objc_getRequiredClass ("MyRootClass")),
227                         "MyRootClass") != 0)
228       abort ();
229   }
231   std::cout << "Testing objc_lookUpClass ()...\n";
232   {
233     if (std::strcmp (class_getName (objc_lookUpClass ("MyRootClass")),
234                         "MyRootClass") != 0)
235       abort ();
236   }
238   /* This function does not exist with the GNU runtime.  */
239   /* std::cout << "Testing objc_setFutureClass ()...\n"; */
241   std::cout << "Testing objc_registerClassPair ()...\n";
242   {
243     Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
245     class_addProtocol (new_class, @protocol (MySecondProtocol));
246     
247     objc_registerClassPair (new_class);
248     
249     if (std::strcmp (class_getName (new_class), "MySubSubClass") != 0)
250       abort ();
252     if (class_getSuperclass (new_class) != objc_getClass ("MySubClass"))
253       abort ();
255     if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol)))
256       abort ();
257   }
259   /* TODO - Test it when implemented in the GNU Runtime */
260   /*  std::cout << "Testing objc_removeAssociatedObjects ()...\n";  */
262   /* TODO - Test it when implemented in the GNU Runtime */
263   /*  std::cout << "Testing objc_setAssociatedObject ()...\n";  */
265   return (0);