foreach.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // TEST_CFLAGS -framework Foundation
  2. #include "test.h"
  3. #import <Foundation/Foundation.h>
  4. /* foreach tester */
  5. int Errors = 0;
  6. bool testHandwritten(const char *style, const char *test, const char *message, id collection, NSSet *reference) {
  7. unsigned int counter = 0;
  8. bool result = true;
  9. testprintf("testing: %s %s %s\n", style, test, message);
  10. /*
  11. for (id elem in collection)
  12. if ([reference member:elem]) ++counter;
  13. */
  14. NSFastEnumerationState state;
  15. id __unsafe_unretained buffer[4];
  16. state.state = 0;
  17. NSUInteger limit = [collection countByEnumeratingWithState:&state objects:buffer count:4];
  18. if (limit != 0) {
  19. unsigned long mutationsPtr = *state.mutationsPtr;
  20. do {
  21. unsigned long innerCounter = 0;
  22. do {
  23. if (mutationsPtr != *state.mutationsPtr) objc_enumerationMutation(collection);
  24. id elem = state.itemsPtr[innerCounter++];
  25. if ([reference member:elem]) ++counter;
  26. } while (innerCounter < limit);
  27. } while ((limit = [collection countByEnumeratingWithState:&state objects:buffer count:4]));
  28. }
  29. if (counter == [reference count]) {
  30. testprintf("success: %s %s %s\n", style, test, message);
  31. }
  32. else {
  33. result = false;
  34. printf("** failed: %s %s %s (%d vs %d)\n", style, test, message, counter, (int)[reference count]);
  35. ++Errors;
  36. }
  37. return result;
  38. }
  39. bool testCompiler(const char *style, const char *test, const char *message, id collection, NSSet *reference) {
  40. unsigned int counter = 0;
  41. bool result = true;
  42. testprintf("testing: %s %s %s\n", style, test, message);
  43. for (id elem in collection)
  44. if ([reference member:elem]) ++counter;
  45. if (counter == [reference count]) {
  46. testprintf("success: %s %s %s\n", style, test, message);
  47. }
  48. else {
  49. result = false;
  50. printf("** failed: %s %s %s (%d vs %d)\n", style, test, message, counter, (int)[reference count]);
  51. ++Errors;
  52. }
  53. return result;
  54. }
  55. void testContinue(NSArray *array) {
  56. bool broken = false;
  57. testprintf("testing: continue statements\n");
  58. for (id __unused elem in array) {
  59. if ([array count])
  60. continue;
  61. broken = true;
  62. }
  63. if (broken) {
  64. printf("** continue statement did not work\n");
  65. ++Errors;
  66. }
  67. }
  68. // array is filled with NSNumbers, in order, from 0 - N
  69. bool testBreak(unsigned int where, NSArray *array) {
  70. PUSH_POOL {
  71. unsigned int counter = 0;
  72. id enumerator = [array objectEnumerator];
  73. for (id __unused elem in enumerator) {
  74. if (++counter == where)
  75. break;
  76. }
  77. if (counter != where) {
  78. ++Errors;
  79. printf("*** break at %d didn't work (actual was %d)\n", where, counter);
  80. return false;
  81. }
  82. for (id __unused elem in enumerator)
  83. ++counter;
  84. if (counter != [array count]) {
  85. ++Errors;
  86. printf("*** break at %d didn't finish (actual was %d)\n", where, counter);
  87. return false;
  88. }
  89. } POP_POOL;
  90. return true;
  91. }
  92. bool testBreaks(NSArray *array) {
  93. bool result = true;
  94. testprintf("testing breaks\n");
  95. unsigned int counter = 0;
  96. for (counter = 1; counter < [array count]; ++counter) {
  97. result = testBreak(counter, array) && result;
  98. }
  99. return result;
  100. }
  101. bool testCompleteness(const char *test, const char *message, id collection, NSSet *reference) {
  102. bool result = true;
  103. result = result && testHandwritten("handwritten", test, message, collection, reference);
  104. result = result && testCompiler("compiler", test, message, collection, reference);
  105. return result;
  106. }
  107. bool testEnumerator(const char *test, const char *message, id collection, NSSet *reference) {
  108. bool result = true;
  109. result = result && testHandwritten("handwritten", test, message, [collection objectEnumerator], reference);
  110. result = result && testCompiler("compiler", test, message, [collection objectEnumerator], reference);
  111. return result;
  112. }
  113. NSMutableSet *ReferenceSet = nil;
  114. NSMutableArray *ReferenceArray = nil;
  115. void makeReferences(int n) {
  116. if (!ReferenceSet) {
  117. int i;
  118. ReferenceSet = [[NSMutableSet alloc] init];
  119. ReferenceArray = [[NSMutableArray alloc] init];
  120. for (i = 0; i < n; ++i) {
  121. NSNumber *number = [[NSNumber alloc] initWithInt:i];
  122. [ReferenceSet addObject:number];
  123. [ReferenceArray addObject:number];
  124. RELEASE_VAR(number);
  125. }
  126. }
  127. }
  128. void testCollections(const char *test, NSArray *array, NSSet *set) {
  129. PUSH_POOL {
  130. id collection;
  131. collection = [NSMutableArray arrayWithArray:array];
  132. testCompleteness(test, "mutable array", collection, set);
  133. testEnumerator(test, "mutable array enumerator", collection, set);
  134. collection = [NSArray arrayWithArray:array];
  135. testCompleteness(test, "immutable array", collection, set);
  136. testEnumerator(test, "immutable array enumerator", collection, set);
  137. collection = set;
  138. testCompleteness(test, "immutable set", collection, set);
  139. testEnumerator(test, "immutable set enumerator", collection, set);
  140. collection = [NSMutableSet setWithArray:array];
  141. testCompleteness(test, "mutable set", collection, set);
  142. testEnumerator(test, "mutable set enumerator", collection, set);
  143. } POP_POOL;
  144. }
  145. void testInnerDecl(const char *test, const char *message, id collection) {
  146. unsigned int counter = 0;
  147. for (id __unused x in collection)
  148. ++counter;
  149. if (counter != [collection count]) {
  150. printf("** failed: %s %s\n", test, message);
  151. ++Errors;
  152. }
  153. }
  154. void testOuterDecl(const char *test, const char *message, id collection) {
  155. unsigned int counter = 0;
  156. id x;
  157. for (x in collection)
  158. ++counter;
  159. if (counter != [collection count]) {
  160. printf("** failed: %s %s\n", test, message);
  161. ++Errors;
  162. }
  163. }
  164. void testInnerExpression(const char *test, const char *message, id collection) {
  165. unsigned int counter = 0;
  166. for (id __unused x in [collection self])
  167. ++counter;
  168. if (counter != [collection count]) {
  169. printf("** failed: %s %s\n", test, message);
  170. ++Errors;
  171. }
  172. }
  173. void testOuterExpression(const char *test, const char *message, id collection) {
  174. unsigned int counter = 0;
  175. id x;
  176. for (x in [collection self])
  177. ++counter;
  178. if (counter != [collection count]) {
  179. printf("** failed: %s %s\n", test, message);
  180. ++Errors;
  181. }
  182. }
  183. void testExpressions(const char *message, id collection) {
  184. testInnerDecl("inner", message, collection);
  185. testOuterDecl("outer", message, collection);
  186. testInnerExpression("outer expression", message, collection);
  187. testOuterExpression("outer expression", message, collection);
  188. }
  189. int main() {
  190. PUSH_POOL {
  191. testCollections("nil", nil, nil);
  192. testCollections("empty", [NSArray array], [NSSet set]);
  193. makeReferences(100);
  194. testCollections("100 item", ReferenceArray, ReferenceSet);
  195. testExpressions("array", ReferenceArray);
  196. testBreaks(ReferenceArray);
  197. testContinue(ReferenceArray);
  198. if (Errors == 0) succeed(__FILE__);
  199. else fail("foreach %d errors detected\n", Errors);
  200. } POP_POOL;
  201. exit(Errors);
  202. }