1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20// 21// auto_tester.m 22// Copyright (c) 2008-2011 Apple Inc. All rights reserved. 23// 24 25#import <Foundation/Foundation.h> 26#import <objc/objc-auto.h> 27#import "TestCase.h" 28#import "auto_tester.h" 29 30static BOOL logTestOutput = NO; 31 32void testLoop(NSMutableArray *testCases); 33 34void cleanup(NSMutableArray *testCases) 35{ 36 void (^completionCallback)(void) = ^{ testLoop(testCases); }; 37 dispatch_queue_t current = dispatch_get_current_queue(); 38 auto_zone_collect_and_notify(objc_collectableZone(), AUTO_ZONE_COLLECT_EXHAUSTIVE_COLLECTION|AUTO_ZONE_COLLECT_LOCAL_COLLECTION, current, completionCallback); 39} 40 41void testLoop(NSMutableArray *testCases) 42{ 43 __block BOOL allTestsComplete = YES; 44 __block int successCount = 0; 45 __block int failCount = 0; 46 __block int skipCount = 0; 47 dispatch_queue_t current = dispatch_get_current_queue(); 48 void (^completionCallback)(void) = Block_copy(^{ cleanup(testCases); }); 49 50 [testCases enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))^(id obj, NSUInteger idx, BOOL *stop){ 51 TestCase *t = (TestCase *)obj; 52 switch ([t result]) { 53 case PENDING: 54 { 55 NSString *skipMessage = [t shouldSkip]; 56 if (skipMessage) { 57 skipCount++; 58 [t setTestResult:SKIPPED message:skipMessage]; 59 } else { 60 *stop = YES; 61 allTestsComplete = NO; 62 [t setCompletionCallback:completionCallback]; 63 [t startTest]; 64 } 65 } 66 break; 67 case PASSED: 68 successCount++; 69 break; 70 case FAILED: 71 failCount++; 72 break; 73 case SKIPPED: 74 skipCount++; 75 break; 76 default: 77 NSLog(@"unexpected test status in testLoop(): %@ = %d\n", [t className], [t result]); 78 exit(-1); 79 break; 80 } 81 }]; 82 Block_release(completionCallback); 83 84 // report results 85 if (allTestsComplete) { 86 [testCases enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))^(id obj, NSUInteger idx, BOOL *stop){ 87 TestCase *t = (TestCase *)obj; 88 NSLog(@"%@: %@", [t className], [t resultString]); 89 NSString *output = [t testOutput]; 90 if (logTestOutput && output) 91 NSLog(@"Test output:\n%@", output); 92 }]; 93 NSLog(@"%d test cases: %d passed, %d failed, %d skipped", [testCases count], successCount, failCount, skipCount); 94 exit(failCount); 95 } 96} 97 98int main(int argc, char *argv[]) 99{ 100 int repeat = 1; 101 102 NSMutableArray *testCases = [NSMutableArray array]; 103 NSMutableArray *testClasses = [NSMutableArray array]; 104 NSProcessInfo *pi = [NSProcessInfo processInfo]; 105 NSMutableArray *args = [[pi arguments] mutableCopy]; 106 [args removeObjectAtIndex:0]; 107 while ([args count] > 0) { 108 int argCount = 0; 109 NSString *arg = [args objectAtIndex:0]; 110 if ([arg isEqual:@"-logTestOutput"]) { 111 argCount++; 112 logTestOutput = YES; 113 } 114 if ([arg hasPrefix:@"-repeat="]) { 115 argCount++; 116 repeat = [[arg substringFromIndex:[@"-repeat=" length]] intValue]; 117 if (repeat < 1) 118 repeat = 1; 119 } 120 Class c = NSClassFromString(arg); 121 if (c) { 122 [testClasses addObject:c]; 123 argCount++; 124 } 125 [args removeObjectsInRange:NSMakeRange(0, argCount)]; 126 } 127 128 // Simple test driver that just runs all the tests. 129 if ([testClasses count] == 0) 130 [testClasses addObjectsFromArray:[TestCase testClasses]]; 131 [testClasses enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))^(id obj, NSUInteger idx, BOOL *stop){ 132 for (int i=0; i<repeat; i++) 133 [testCases addObject:[[obj alloc] init]]; 134 }]; 135 136 dispatch_queue_t testQ = dispatch_queue_create("Test Runner", NULL); 137 dispatch_async(testQ, ^{testLoop(testCases);}); 138 139 [[NSRunLoop mainRunLoop] run]; 140 dispatch_main(); 141 return 0; 142} 143