1/* Test the Modern GNU Objective-C Runtime API.
2
3  This is test 'sel', covering all functions starting with 'sel'.  */
4
5/* { dg-do run } */
6/* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */
7
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>
14
15@interface MyRootClass
16{ Class isa; }
17+ alloc;
18- init;
19+ initialize;
20@end
21
22@implementation MyRootClass
23+ alloc { return class_createInstance (self, 0); }
24- init  { return self; }
25+ initialize { return self; }
26@end
27
28@protocol MyProtocol
29- (id) variable;
30@end
31
32@protocol MySecondProtocol
33- (id) setVariable: (id)value;
34@end
35
36@interface MySubClass : MyRootClass <MyProtocol>
37{ id variable_ivar; }
38- (void) setVariable: (id)value;
39- (id) variable;
40- (void) method;
41@end
42
43@implementation MySubClass
44- (void) setVariable: (id)value { variable_ivar = value; }
45- (id) variable { return variable_ivar; }
46- (void) method { return; }
47@end
48
49@interface ClassA : MyRootClass
50- (id) conflictingSelectorMethod;
51@end
52
53@implementation ClassA
54- (id) conflictingSelectorMethod { return nil; }
55@end
56
57@interface ClassB : MyRootClass
58- (void) conflictingSelectorMethod;
59@end
60
61@implementation ClassB
62- (void) conflictingSelectorMethod { return; }
63@end
64
65int main ()
66{
67  /* Functions are tested in alphabetical order.  */
68
69#ifdef __GNU_LIBOBJC__
70  std::cout << "Testing sel_copyTypedSelectorList ()...\n";
71  {
72    unsigned int count;
73    SEL * list = sel_copyTypedSelectorList ("method", &count);
74
75    /* There should only be two, since 'method' is referenced twice,
76       once with types and once without (in this very test).  */
77    if (count != 2)
78      abort ();
79
80    /* Check that both selectors are not-NULL, and have the correct
81       name.  We use @selector() here, which wouldn't really be
82       needed, just to register a second, untyped selector with name
83       'method'.  */
84    if (std::strcmp (sel_getName (list[0]), sel_getName (@selector (method))) != 0)
85      abort ();
86
87    if (std::strcmp (sel_getName (list[1]), sel_getName (@selector (method))) != 0)
88      abort ();
89
90    if (list[2] != NULL)
91      abort ();
92  }
93#endif
94
95  std::cout << "Testing sel_getName () ...\n";
96  {
97    if (std::strcmp (sel_getName (@selector (variable)), "variable") != 0)
98      abort ();
99
100    if (std::strcmp (sel_getName (NULL), "<null selector>") != 0)
101      abort ();
102  }
103
104#ifdef __GNU_LIBOBJC__
105  std::cout << "Testing sel_getTypeEncoding () ...\n";
106  {
107    /* Get a selector from a real class, so it has interesting
108       types.  */
109    Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
110					     @selector (variable));
111
112    if (std::strcmp (sel_getTypeEncoding (method_getName (method)),
113		method_getTypeEncoding (method)) != 0)
114      abort ();
115
116    if (sel_getTypeEncoding (NULL) != NULL)
117      abort ();
118  }
119#endif
120
121#ifdef __GNU_LIBOBJC__
122  std::cout << "Testing sel_getTypedSelector () ...\n";
123  {
124    /* First try with a selector where we know that a typed one has
125       been registered.  */
126    SEL selector = sel_getTypedSelector ("variable");
127
128    if (selector == NULL)
129      abort ();
130
131    if (sel_getTypeEncoding (selector) == NULL)
132      abort ();
133
134    /* Now try a selector which was never registered.  */
135    selector = sel_getTypedSelector ("not_registered");
136
137    if (selector != NULL)
138      abort ();
139
140    /* Now try registering a selector with no types.  The following
141       line is just a way to have an unused '@selector()' expression
142       without the compiler complaining.  */
143    if (@selector (registered_with_no_types) == NULL)
144      abort ();
145
146    /* Try getting it.  Nothing should be returned because it is
147       untyped.  */
148    selector = sel_getTypedSelector ("registered_with_no_types");
149
150    if (selector != NULL)
151      abort ();
152
153    /* Now try a selector with multiple, conflicting types.  NULL
154       should be returned.  */
155    selector = sel_getTypedSelector ("conflictingSelectorMethod");
156
157    if (selector != NULL)
158      abort ();
159  }
160#endif
161
162  std::cout << "Testing sel_getUid () ...\n";
163  {
164    if (std::strcmp (sel_getName (sel_getUid ("myMethod")), "myMethod") != 0)
165      abort ();
166
167    if (sel_getUid (NULL) != NULL)
168      abort ();
169  }
170
171  std::cout << "Testing sel_isEqual () ...\n";
172  {
173    if (! sel_isEqual (@selector (setVariable:), @selector (setVariable:)))
174      abort ();
175  }
176
177  std::cout << "Testing sel_registerName () ...\n";
178  {
179    if (std::strcmp (sel_getName (sel_registerName ("myMethod")), "myMethod") != 0)
180      abort ();
181
182    if (sel_registerName (NULL) != NULL)
183      abort ();
184  }
185
186#ifdef __GNU_LIBOBJC__
187  std::cout << "Testing set_registerTypedName () ...\n";
188  {
189    const char *types = method_getTypeEncoding (class_getInstanceMethod
190						(objc_getClass ("MySubClass"),
191						 @selector (variable)));
192    SEL selector = sel_registerTypedName ("aMethod", types);
193
194    if (std::strcmp (sel_getName (selector), "aMethod") != 0)
195      abort ();
196
197    if (std::strcmp (sel_getTypeEncoding (selector), types) != 0)
198      abort ();
199
200    if (sel_registerTypedName (NULL, NULL) != NULL)
201      abort ();
202
203    if (sel_registerTypedName (NULL, types) != NULL)
204      abort ();
205  }
206#endif
207
208  return (0);
209}
210