willInitializeClassFunc.m 2.8 KB

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