]> git.saurik.com Git - apple/objc4.git/blob - test/willInitializeClassFunc.m
objc4-787.1.tar.gz
[apple/objc4.git] / test / willInitializeClassFunc.m
1 // TEST_CONFIG MEM=mrc
2
3 #import "test.h"
4 #import "testroot.i"
5
6 #import <objc/objc-internal.h>
7
8 #import <stdio.h>
9
10 char dummy;
11
12 Class *seenClasses;
13 size_t seenClassesCount;
14
15 static void clear(void) {
16 free(seenClasses);
17 seenClasses = NULL;
18 seenClassesCount = 0;
19 }
20
21 static void willInitializeClass(void *context, Class cls) {
22 testprintf("Will initialize %s\n", class_getName(cls));
23 seenClassesCount++;
24 seenClasses = (Class *)realloc(seenClasses, seenClassesCount * sizeof(*seenClasses));
25 seenClasses[seenClassesCount - 1] = cls;
26 testassert(context == &dummy);
27 }
28
29 int initializedC;
30 @interface C: TestRoot @end
31 @implementation C
32 + (void)initialize {
33 testprintf("C initialize\n");
34 initializedC = 1;
35 }
36 @end
37
38 int initializedD;
39 @interface D: TestRoot @end
40 @implementation D
41 + (void)initialize {
42 testprintf("D initialize\n");
43 initializedD = 1;
44 }
45 @end
46
47 int initializedE;
48 @interface E: TestRoot @end
49 @implementation E
50 + (void)initialize {
51 testprintf("E initialize\n");
52 initializedE = 1;
53 }
54 @end
55
56 int main()
57 {
58 _objc_addWillInitializeClassFunc(willInitializeClass, &dummy);
59
60 // Merely getting a class should not trigger the callback.
61 clear();
62 size_t oldCount = seenClassesCount;
63 Class c = objc_getClass("C");
64 testassert(seenClassesCount == oldCount);
65 testassert(initializedC == 0);
66
67 // Sending a message to C should trigger the callback and the superclass's callback.
68 [c class];
69 testassert(seenClassesCount == oldCount + 2);
70 testassert(seenClasses[seenClassesCount - 2] == [TestRoot class]);
71 testassert(seenClasses[seenClassesCount - 1] == [C class]);
72
73 // Sending a message to D should trigger the callback only for D, since the
74 // superclass is already initialized.
75 oldCount = seenClassesCount;
76 [D class];
77 testassert(seenClassesCount == oldCount + 1);
78 testassert(seenClasses[seenClassesCount - 1] == [D class]);
79
80 // Registering a second callback should inform us of all three exactly once.
81 clear();
82 _objc_addWillInitializeClassFunc(willInitializeClass, &dummy);
83 testassert(seenClassesCount == 3);
84
85 int foundRoot = 0;
86 int foundC = 0;
87 int foundD = 0;
88 for (size_t i = 0; i < seenClassesCount; i++) {
89 if (seenClasses[i] == [TestRoot class])
90 foundRoot++;
91 if (seenClasses[i] == [C class])
92 foundC++;
93 if (seenClasses[i] == [D class])
94 foundD++;
95 }
96 testassert(foundRoot == 1);
97 testassert(foundC == 1);
98 testassert(foundD == 1);
99
100 // Both callbacks should fire when sending a message to E.
101 clear();
102 [E class];
103 testassert(initializedE);
104 testassert(seenClassesCount == 2);
105 testassert(seenClasses[0] == [E class]);
106 testassert(seenClasses[1] == [E class]);
107
108 succeed(__FILE__);
109 }