]>
Commit | Line | Data |
---|---|---|
8972963c A |
1 | // TEST_CFLAGS -Wno-deprecated-declarations |
2 | ||
7af964d1 A |
3 | #include "test.h" |
4 | #include <objc/objc-runtime.h> | |
5 | #ifndef OBJC_NO_GC | |
6 | #include <objc/objc-auto.h> | |
7 | #include <auto_zone.h> | |
8 | #endif | |
9 | ||
10 | static int state; | |
11 | ||
12 | @protocol Proto | |
13 | +class; | |
14 | @end | |
15 | ||
16 | @interface Super<Proto> { | |
17 | id isa; | |
18 | int i; | |
19 | } | |
20 | @property int i; | |
21 | @end | |
22 | ||
23 | @implementation Super | |
24 | @synthesize i; | |
25 | ||
26 | +(void)initialize { } | |
27 | +class { return self; } | |
28 | +new { return class_createInstance(self, 0); } | |
29 | -(void)dealloc { object_dispose(self); } | |
30 | ||
31 | +(void)classMethod { | |
32 | state = 1; | |
33 | } | |
34 | ||
35 | -(void)instanceMethod { | |
36 | state = 3; | |
37 | } | |
38 | ||
39 | @end | |
40 | ||
41 | ||
42 | @implementation Super (Category) | |
43 | ||
44 | +(void)classMethod { | |
45 | state = 2; | |
46 | } | |
47 | ||
48 | -(void)instanceMethod { | |
49 | state = 4; | |
50 | } | |
51 | ||
52 | @end | |
53 | ||
54 | ||
55 | int main() | |
56 | { | |
57 | Class clone; | |
58 | Class cls; | |
59 | Method *m1, *m2; | |
60 | int i; | |
61 | ||
62 | cls = [Super class]; | |
63 | clone = objc_duplicateClass(cls, "Super_copy", 0); | |
64 | #ifndef OBJC_NO_GC | |
8972963c A |
65 | if (objc_collectingEnabled()) { |
66 | testassert(auto_zone_size(objc_collectableZone(), clone)); | |
7af964d1 | 67 | // objc_duplicateClass() doesn't duplicate the metaclass |
8972963c | 68 | // no: testassert(auto_zone_size(objc_collectableZone(), clone->isa)); |
7af964d1 A |
69 | } |
70 | #endif | |
71 | ||
72 | testassert(clone != cls); | |
73 | testassert(clone->isa == cls->isa); | |
74 | testassert(class_getSuperclass(clone) == class_getSuperclass(cls)); | |
75 | testassert(class_getVersion(clone) == class_getVersion(cls)); | |
76 | testassert(class_isMetaClass(clone) == class_isMetaClass(cls)); | |
77 | testassert(class_getIvarLayout(clone) == class_getIvarLayout(cls)); | |
78 | testassert(class_getWeakIvarLayout(clone) == class_getWeakIvarLayout(cls)); | |
79 | #if !__OBJC2__ | |
80 | testassert((clone->info & (CLS_CLASS|CLS_META)) == (cls->info & (CLS_CLASS|CLS_META))); | |
81 | #endif | |
82 | ||
83 | // Check method list | |
84 | ||
85 | m1 = class_copyMethodList(cls, NULL); | |
86 | m2 = class_copyMethodList(clone, NULL); | |
87 | testassert(m1); | |
88 | testassert(m2); | |
89 | for (i = 0; m1[i] && m2[i]; i++) { | |
90 | testassert(m1[i] != m2[i]); // method list must be deep-copied | |
91 | testassert(method_getName(m1[i]) == method_getName(m2[i])); | |
92 | testassert(method_getImplementation(m1[i]) == method_getImplementation(m2[i])); | |
93 | testassert(method_getTypeEncoding(m1[i]) == method_getTypeEncoding(m2[i])); | |
94 | } | |
95 | testassert(m1[i] == NULL && m2[i] == NULL); | |
96 | free(m1); | |
97 | free(m2); | |
98 | ||
99 | // Check ivar list | |
100 | Ivar *i1 = class_copyIvarList(cls, NULL); | |
101 | Ivar *i2 = class_copyIvarList(clone, NULL); | |
102 | testassert(i1); | |
103 | testassert(i2); | |
104 | for (i = 0; i1[i] && i2[i]; i++) { | |
105 | testassert(i1[i] == i2[i]); // ivars are not deep-copied | |
106 | } | |
107 | testassert(i1[i] == NULL && i2[i] == NULL); | |
108 | free(i1); | |
109 | free(i2); | |
110 | ||
111 | // Check protocol list | |
8972963c A |
112 | Protocol * const *p1 = class_copyProtocolList(cls, NULL); |
113 | Protocol * const *p2 = class_copyProtocolList(clone, NULL); | |
7af964d1 A |
114 | testassert(p1); |
115 | testassert(p2); | |
116 | for (i = 0; p1[i] && p2[i]; i++) { | |
117 | testassert(p1[i] == p2[i]); // protocols are not deep-copied | |
118 | } | |
119 | testassert(p1[i] == NULL && p2[i] == NULL); | |
8972963c A |
120 | free((void*)p1); |
121 | free((void*)p2); | |
7af964d1 A |
122 | |
123 | // Check property list | |
124 | objc_property_t *o1 = class_copyPropertyList(cls, NULL); | |
125 | objc_property_t *o2 = class_copyPropertyList(clone, NULL); | |
126 | testassert(o1); | |
127 | testassert(o2); | |
128 | for (i = 0; o1[i] && o2[i]; i++) { | |
129 | testassert(o1[i] == o2[i]); // properties are not deep-copied | |
130 | } | |
131 | testassert(o1[i] == NULL && o2[i] == NULL); | |
132 | free(o1); | |
133 | free(o2); | |
134 | ||
135 | // Check method calls | |
136 | ||
137 | state = 0; | |
138 | [cls classMethod]; | |
139 | testassert(state == 2); | |
140 | state = 0; | |
141 | [clone classMethod]; | |
142 | testassert(state == 2); | |
143 | ||
144 | // #4511660 Make sure category implementation is still the preferred one | |
145 | id obj; | |
146 | obj = [cls new]; | |
147 | state = 0; | |
148 | [obj instanceMethod]; | |
149 | testassert(state == 4); | |
150 | [obj dealloc]; | |
151 | ||
152 | obj = [clone new]; | |
153 | state = 0; | |
154 | [obj instanceMethod]; | |
155 | testassert(state == 4); | |
156 | [obj dealloc]; | |
157 | ||
158 | succeed(__FILE__); | |
159 | } |