5 // Created by Wincent Colaiuta on 12 October 2004.
7 // Copyright 2004-2007 Wincent Colaiuta.
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #import "WOTestClass.h"
26 #import <objc/objc-runtime.h>
27 #import <sys/types.h> /* write() */
28 #import <sys/uio.h> /* write() */
29 #import <unistd.h> /* write(), _exit() */
35 #import "exc.h" /* generated by MiG */
37 // make what(1) produce meaningful output
38 #import "WOTest_Version.h"
40 #define WO_UNICODE_PLUS_MINUS_SIGN 0x00b1
41 #define WO_UNICODE_ELLIPSIS 0x2026
43 // convenience macros, call method to truncate description to 64 characters
44 #define WO_TRUNCATE_INDEX 64
46 // return truncated description of \p object, expects a BOOL variable of the format objectTruncated to be defined within the same scope
47 #define WO_DESC(object) [self description:object truncatedAt:WO_TRUNCATE_INDEX didTruncate:&object ## Truncated]
49 // return untruncated description of object
50 #define WO_LONG_DESC(object) [self description:object truncatedAt:0 didTruncate:NULL]
52 #define WO_UNCAUGHT_EXCEPTION_ERROR @"uncaught exception"
54 // convenience macro to throw exception when NSString type checking fails
55 #define WO_EXPECTED_STRING_EXCEPTION_REASON(object) \
56 [NSString stringWithFormat:@"Expected NSString object but got object of class \"%@\"", NSStringFromClass([object class])]
58 // convenience macro to throw exception when NSArray type checking fails
59 #define WO_EXPECTED_ARRAY_EXCEPTION_REASON(object) \
60 [NSString stringWithFormat:@"Expected NSArray object but got object of class \"%@\"", NSStringFromClass([object class])]
62 // convenience macro to throw exception when NSDictionary type check fails
63 #define WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(object) \
64 [NSString stringWithFormat:@"Expected NSDictionary object but got object of class \"%@\"", NSStringFromClass([object class])]
66 #define WO_NIL_PARAMETER_EXCEPTION_REASON @"A test which does not accept nil parameters was passed a nil parameter"
68 // Return a random offset between 0 and WO_RANDOMIZATION_RANGE inclusive.
69 #define WO_RANDOM_OFFSET (random() % (WO_RANDOMIZATION_RANGE - 1))
71 // Return +1 or -1 randomly.
72 #define WO_RANDOM_SIGN ((BOOL)(random() % 2) ? 1 : -1)
75 #pragma mark Class variables
77 static WOTest *WOTestSharedInstance = nil;
78 static volatile BOOL WOTestCanJump = NO;
79 static volatile ExceptionKind WOLastLowLevelException;
80 static volatile sig_atomic_t WOTestExceptionTriggered = 0;
81 static ExceptionHandlerUPP WOOldLowLevelExceptionHandler;
83 // for the timebeing, only store/restore a limited number of registers; may remove the unused ones from the struct at a later time
84 typedef struct WOJumpBuffer {
85 unsigned long eax; // store/restore
86 unsigned long ebx; // store/restore
89 unsigned long edi; // store/restore
90 unsigned long esi; // store/restore
91 unsigned long ebp; // store/restore
92 unsigned long esp; // store/restore
101 static volatile WOJumpBuffer WOLowLevelExceptionJumpBuffer;
104 static unsigned long WOProgramCounter;
105 #elif defined (__ppc__)
106 static UnsignedWide WOProgramCounter;
108 #error Unsupported architecture
112 #pragma mark Functions
114 OSStatus WOLowLevelExceptionHandler(ExceptionInformation *theException)
116 if (!WOTestCanJump) // unexpected exception
118 fprintf(stderr, "error: WOTest internal error (unexpected exception in WOLowLevelExceptionHandler)\n");
119 fprintf(stderr, "Exception type: %lu\n", (unsigned long)(theException->theKind));
122 // forwarding to old exception handler doesn't seem to work (get into infinite loop)
123 //return InvokeExceptionHandlerUPP(theException, WOOldLowLevelExceptionHandler);
127 WOLastLowLevelException = theException->theKind;
130 // set flag to indicate that an exception was triggerd
131 WOTestExceptionTriggered = 1;
133 // will resume execution at previously marked "safe place": longjmp would be fine here
135 // set only the registers that setjmp() saves and longjmp() restores
136 theException->machineState->EIP = WOProgramCounter;
137 theException->registerImage->EBP = WOLowLevelExceptionJumpBuffer.ebp;
138 theException->registerImage->EAX = WOLowLevelExceptionJumpBuffer.eax;
139 theException->registerImage->EBX = WOLowLevelExceptionJumpBuffer.ebx;
140 theException->registerImage->EDI = WOLowLevelExceptionJumpBuffer.edi;
141 theException->registerImage->ESI = WOLowLevelExceptionJumpBuffer.esi;
142 theException->registerImage->ESP = WOLowLevelExceptionJumpBuffer.esp;
144 // clear out exception state (probably not necessary)
145 theException->info.memoryInfo = NULL;
147 #elif defined (__ppc__)
148 theException->machineState->PC = WOProgramCounter;
149 // TODO: must restore more state here
151 #error Unsupported architecture
156 @interface WOTest (WOPrivate)
158 - (void)installLowLevelExceptionHandler;
159 - (void)removeLowLevelExceptionHandler;
161 /*! Check to see that the start date has been recorded. If it has not, record it. */
162 - (void)checkStartDate;
164 - (void)setStartDate:(NSDate *)aStartDate;
166 /*! Helper method for optionally trimming path names before printing them to the console. */
167 - (NSString *)trimmedPath:(char *)path;
171 @implementation WOTest
174 #pragma mark Singleton pattern enforcement methods
176 + (WOTest *)sharedInstance;
178 // speed less of a concern here than robustness so always lock (instead of using double-checked locking plus memory barriers)
179 volatile id instance = nil;
180 @synchronized (WOTestSharedInstance)
182 if (WOTestSharedInstance)
183 instance = WOTestSharedInstance;
185 instance = [[self alloc] init];
192 @synchronized (WOTestSharedInstance)
194 if (!WOTestSharedInstance) // first time here
196 if ((self = [super init]))
198 // once-off initialization and setting of defaults:
199 self->handlesLowLevelExceptions = YES;
200 self->warnsAboutSignComparisons = YES;
202 WOTestSharedInstance = self;
205 NSDeallocateObject(self); // were racing, but lost the race
207 return WOTestSharedInstance;
210 // overriding allocWithZone also effectively overrides alloc
211 + (id)allocWithZone:(NSZone *)aZone
213 volatile id instance = nil;
214 @synchronized (WOTestSharedInstance)
216 if (WOTestSharedInstance)
217 instance = WOTestSharedInstance;
219 instance = NSAllocateObject([self class], 0, aZone);
224 - (oneway void)release
231 [self doesNotRecognizeSelector:_cmd]; // being a singleton, officially does not support dealloc
232 [super dealloc]; // this line necessary to suppress compiler warning
235 - (unsigned)retainCount
250 // overriding this also overrides copy
251 - (id)copyWithZone:(NSZone *)zone
256 // overriding this also overrides mutableCopy
257 - (id)mutableCopyWithZone:(NSZone *)zone
263 #pragma mark Utility methods
265 - (NSString *)description:(id)anObject truncatedAt:(unsigned)index didTruncate:(BOOL *)didTruncate
267 if (didTruncate) *didTruncate = NO;
268 NSString *description = nil;
270 description = @"(nil)";
275 description = [NSObject WOTest_descriptionForObject:anObject];
276 unsigned int originalLength = [description length];
277 if (index > 0) // a value of 0 would indicate that no truncation is to be performed
279 description = [description WOTest_stringByCollapsingWhitespace];
280 if ([description length] > index)
281 description = [[description substringToIndex:index] WOTest_stringByAppendingCharacter:WO_UNICODE_ELLIPSIS];
282 if (([description length] != originalLength) && (didTruncate))
288 description = @"(exception caught trying to get object description)";
294 - (void)seedRandomNumberGenerator
299 - (void)seedRandomNumberGenerator:(unsigned long)seed
304 - (BOOL)isClassMethod:(NSString *)method
306 return (method && [method hasPrefix:@"+"]);
309 - (BOOL)isInstanceMethod:(NSString *)method
311 return (method && [method hasPrefix:@"-"]);
314 - (SEL)selectorFromMethod:(NSString *)method
316 NSParameterAssert(method != nil);
317 NSParameterAssert([method length] > 1);
318 NSString *selectorName = [method substringFromIndex:1];
319 return NSSelectorFromString(selectorName);
323 #pragma mark Test-running methods
325 - (void)checkStartDate
329 if ([self startDate] == nil)
330 [self setStartDate:[NSDate date]];
337 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
338 for (NSString *class in [self testableClasses])
339 [self runTestsForClassName:class] ? : failures++;
340 [self printTestResultsSummary];
342 return (failures > 0) ? NO : YES;
345 - (BOOL)runTestsForClassName:(NSString *)className
347 NSParameterAssert(className != nil);
348 return [self runTestsForClass:NSClassFromString(className)];
351 // all other test-running methods ultimately get funnelled through this method
352 - (BOOL)runTestsForClass:(Class)aClass
354 NSParameterAssert(aClass != nil);
355 [self checkStartDate];
356 BOOL noTestFailed = YES;
357 NSDate *startClass = [NSDate date];
360 _WOLog(@"Running tests for class %@", NSStringFromClass(aClass));
361 if ([NSObject WOTest_instancesOfClass:aClass conformToProtocol:@protocol(WOTest)])
363 for (NSString *method in [self testableMethodsFrom:aClass])
365 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
366 NSDate *startMethod = [NSDate date];
367 SEL preflight = @selector(preflight);
368 SEL postflight = @selector(postflight);
370 _WOLog(@"Running test method %@", method);
373 // minimize time spent with exception handlers in place
374 [self installLowLevelExceptionHandler];
376 // record program counter and some other registers right now
378 // LowLevelABI.pdf says "EDI, ESI, EBX, EBP" are the preserved registers (across function calls)
379 // ebp is the "saved frame pointer": "the base address of the caller's stack frame"
380 // eax is used to return pointer and integral results to callers: "The called function places integral or pointer results in EAX"
382 // info on inline assembly: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
383 __asm__ volatile("movl %%eax, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.eax));
384 __asm__ volatile("movl %%ebx, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebx));
385 __asm__ volatile("movl %%edi, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.edi));
386 __asm__ volatile("movl %%esi, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.esi));
387 __asm__ volatile("movl %%esp, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.esp));
388 __asm__ volatile("movl %%ebp, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebp));
390 // done this way in Linux (see acpi_save_register_state function)
391 WOProgramCounter = (unsigned long)&&jump_point;
392 #elif defined (__ppc__)
393 // equivalent to (psuedo code) "WOProgramCounter = current contents of PC register"
394 unsigned long counter;
395 __asm__ volatile("mflr %0" : "=r" (counter));
396 WOProgramCounter.lo = counter & 0xffffffff;
397 WOProgramCounter.hi = (counter & 0xffffffff00000000) >> 32;
399 #error Unsupported architecture
403 goto jump_point; // necessary to silence compiler warning about unused label
405 // if flag set, that means we crashed: throw an exception
406 if (WOTestExceptionTriggered)
408 WOTestExceptionTriggered = 0;
409 @throw [WOTestLowLevelException exceptionWithType:WOLastLowLevelException];
412 if ([self isClassMethod:method])
414 if ([NSObject WOTest_class:aClass respondsToSelector:preflight])
415 objc_msgSend(aClass, preflight);
416 objc_msgSend(aClass, [self selectorFromMethod:method]);
417 if ([NSObject WOTest_class:aClass respondsToSelector:postflight])
418 objc_msgSend(aClass, postflight);
420 else if ([self isInstanceMethod:method])
422 // class must implement alloc, init and release
423 if ([NSObject WOTest_object:aClass respondsToSelector:@selector(alloc)] &&
424 [NSObject WOTest_instancesOfClass:aClass respondToSelector:@selector(init)] &&
425 [NSObject WOTest_instancesOfClass:aClass respondToSelector:@selector(release)])
427 id instance = [[aClass alloc] init];
428 if ([NSObject WOTest_instancesOfClass:aClass respondToSelector:preflight])
429 objc_msgSend(instance, preflight);
430 objc_msgSend(instance, [self selectorFromMethod:method]);
431 if ([NSObject WOTest_instancesOfClass:aClass respondToSelector:postflight])
432 objc_msgSend(instance, postflight);
437 [self writeError:@"Class %@ must respond to the alloc, init and release selectors",
438 NSStringFromClass(aClass)];
439 [self writeLastKnownLocation];
442 else // should never get here
443 [self writeError:@"WOTest internal error"];
445 @catch (WOTestLowLevelException *lowLevelException)
447 if ([self expectLowLevelExceptions])
449 [self writeStatus:[lowLevelException reason]]; // expected low-level exceptions are not an error
450 lowLevelExceptionsExpected++;
454 [self writeError:[lowLevelException reason]]; // unexpected low-level exceptions are an error
455 [self writeLastKnownLocation];
457 lowLevelExceptionsUnexpected++;
462 [self writeError:@"uncaught exception (%@) in test method %@", [NSException WOTest_descriptionForException:e],
464 [self writeLastKnownLocation];
466 uncaughtExceptions++;
470 if (lowLevelExceptionHandlerInstalled)
471 [self removeLowLevelExceptionHandler];
472 _WOLog(@"Finished test method %@ (%.4f seconds)", method, -[startMethod timeIntervalSinceNow]);
480 [self writeError:@"uncaught exception (%@) testing class %@", [NSException WOTest_descriptionForException:e],
481 NSStringFromClass(aClass)];
482 [self writeLastKnownLocation];
484 uncaughtExceptions++;
488 _WOLog(@"Finished tests for class %@ (%.4f seconds)", NSStringFromClass(aClass), -[startClass timeIntervalSinceNow]);
493 - (NSArray *)testableClasses
495 // return an array of class names
496 NSMutableArray *testableClasses = [NSMutableArray array];
498 unsigned classCount = 0; // the total number of classes
499 unsigned conformingClassCount = 0; // classes conforming to WOTest
500 unsigned nonconformingClassCount = 0; // unconforming classes
501 unsigned excludedClassCount = 0; // excluded classes
502 unsigned exceptionCount = 0; // classes provoking exceptions
505 int newNumClasses = objc_getClassList(NULL, 0);
506 Class *classes = NULL;
508 // get a list of all classes on the system
509 while (numClasses < newNumClasses)
511 numClasses = newNumClasses;
512 size_t bufferSize = sizeof(Class) * numClasses;
513 classes = realloc(classes, bufferSize);
514 NSAssert1((classes != NULL), @"realloc() failed (size %d)", bufferSize);
515 newNumClasses = objc_getClassList(classes, numClasses);
522 // skip over some classes because they not only cause exceptions but also spew out ugly console messages
523 SInt32 systemVersion;
524 Gestalt(gestaltSystemVersion, &systemVersion);
525 systemVersion = systemVersion & 0x0000ffff; // Apple instructs to ignore the high-order word
527 NSArray *excludedClasses = (systemVersion < 0x00001040) ?
528 [NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", nil] : // 10.3
529 [NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", @"NSATSGlyphGenerator", nil]; // 10.4
531 if ([self verbosity] > 1)
532 _WOLog(@"Examining classes for WOTest protocol compliance");
534 for (int i = 0; i < newNumClasses; i++)
538 Class aClass = classes[i];
539 NSString *className = NSStringFromClass(aClass);
543 if ([excludedClasses containsObject:className])
545 excludedClassCount++;
546 if ([self verbosity] > 1)
547 _WOLog(@"Skipping class %@ (appears in exclusion list)", className);
549 else if ([NSObject WOTest_instancesOfClass:aClass conformToProtocol:@protocol(WOTest)])
551 conformingClassCount++;
552 [testableClasses addObject:className];
553 if ([self verbosity] > 0)
554 _WOLog(@"Class %@ complies with the WOTest protocol", className);
558 nonconformingClassCount++;
559 if ([self verbosity] > 1)
560 _WOLog(@"Class %@ does not comply with the WOTest protocol", className);
563 @catch (id exception)
566 // a number of classes are known to provoke exceptions:
567 if ([self verbosity] > 1)
568 _WOLog(@"Cannot test protocol compliance for class %@ (caught exception)", className);
578 _WOLog(@"Uncaught exception...");
581 _WOLog(@"Runtime Summary:\n"
582 @"Total classes: %d\n"
583 @"Classes which conform to the WOTest protocol: %d\n"
584 @"Classes which do not conform to the protocol: %d\n"
585 @"Classes excluded from scanning: %d\n"
586 @"Classes that could not be scanned due to exceptions: %d",
588 conformingClassCount,
589 nonconformingClassCount,
593 return [testableClasses sortedArrayUsingSelector:@selector(compare:)];
596 - (NSArray *)testableClassesFrom:(NSBundle *)aBundle
598 NSMutableArray *classNames = [NSMutableArray array];
600 if (aBundle) // only search if actually passed a non-nil bundle
602 // add only classes that match the passed bundle and conform to WOTest
603 for (NSString *className in [self testableClasses])
605 Class aClass = NSClassFromString(className);
606 NSBundle *classBundle = [NSBundle bundleForClass:aClass];
607 if ([classBundle isEqualTo:aBundle])
608 [classNames addObject:className];
612 // return autoreleased, immutable NSArray
613 return [NSArray arrayWithArray:classNames];
616 - (NSArray *)testableMethodsFrom:(Class)aClass
618 // catch crashes caused by passing an "id" instead of a "Class"
619 NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass] || [NSObject WOTest_isMetaClass:aClass]);
621 NSMutableArray *methodNames = [NSMutableArray array];
624 NSString *prefix = @"-"; // default prefix (instance methods)
625 if (class_isMetaClass(aClass))
626 prefix = @"+"; // special prefix (class methods)
627 else // this is not a metaclass
629 // get the metaclass; could also use object_getClass
630 Class metaClass = object_getClass(aClass);
631 NSArray *classMethods = [self testableMethodsFrom:metaClass];
632 [methodNames addObjectsFromArray:classMethods];
636 Method *methods = class_copyMethodList(aClass, &count);
639 for (unsigned int i = 0, max = count; i < max; i++)
641 SEL aSelector = method_getName(methods[i]);
642 NSString *name = NSStringFromSelector(aSelector);
643 if (name && [name hasPrefix:@"test"])
644 [methodNames addObject:[NSString stringWithFormat:@"%@%@", prefix, name]];
651 NSString *error = [NSString stringWithFormat:@"exception caught trying to identify testable methods in class %@",
652 NSStringFromClass(aClass)];
653 [self writeError:error];
656 return [methodNames sortedArrayUsingSelector:@selector(compare:)];
659 - (void)printTestResultsSummary;
661 [self checkStartDate]; // just in case no tests were run, make sure that startDate is non-nil
662 double successRate = 0.0;
663 double failureRate = 0.0;
664 if (testsRun > 0) // watch out for divide-by-zero if no tests run
666 successRate = ((double)(testsPassed + testsFailedExpected) / (double)testsRun) * 100.0;
667 failureRate = ((double)(testsFailed + testsPassedUnexpected) / (double)testsRun) * 100.0;
669 _WOLog(@"Run summary:\n"
671 @"Tests passed: %d + %d expected failures (%.2f%% success rate)\n"
672 @"Tests failed: %d + %d unexpected passes (%.2f%% failure rate)\n"
673 @"Uncaught exceptions: %d\n"
674 @"Low-level exceptions (crashers): %d + %d expected\n"
675 @"Total run time: %.2f seconds\n",
677 testsPassed, testsFailedExpected, successRate,
678 testsFailed, testsPassedUnexpected, failureRate,
680 lowLevelExceptionsUnexpected, lowLevelExceptionsExpected,
681 -[[self startDate] timeIntervalSinceNow]);
684 _WOLog(@"warning: no tests were run\n");
686 // TODO: make Growl notifications optional
687 // TODO: include information about project being tested in Growl notification title
688 // TODO: add options for showing coalesced growl notifications showing individual test failures (with path and line info)
689 // TODO: make clicking on notification bring Xcode to the front, or open the file with the last failure in it etc
690 NSString *status = [NSString stringWithFormat:@"%d tests passed, %d tests failed",
691 testsPassed + testsFailedExpected, testsFailed + testsPassedUnexpected];
693 if ([self testsWereSuccessful])
694 [self growlNotifyTitle:@"WOTest run successful" message:status isWarning:NO sticky:NO];
697 _WOLog(@"error: testing did not complete without errors\n");
698 [self growlNotifyTitle:@"WOTest run failed" message:status isWarning:YES sticky:YES];
703 [self setStartDate:nil];
706 - (BOOL)testsWereSuccessful
708 return ((testsFailed + testsPassedUnexpected + uncaughtExceptions + lowLevelExceptionsUnexpected) == 0);
712 #pragma mark Low-level exception handling
714 - (void)installLowLevelExceptionHandler
716 if (!lowLevelExceptionHandlerInstalled)
718 WOOldLowLevelExceptionHandler = InstallExceptionHandler(NewExceptionHandlerUPP(WOLowLevelExceptionHandler));
719 lowLevelExceptionHandlerInstalled = YES;
723 - (void)removeLowLevelExceptionHandler
725 if (lowLevelExceptionHandlerInstalled)
727 DisposeExceptionHandlerUPP(InstallExceptionHandler(WOOldLowLevelExceptionHandler));
728 lowLevelExceptionHandlerInstalled = NO;
733 #pragma mark Growl support
735 - (void)growlNotifyTitle:(NSString *)title message:(NSString *)message isWarning:(BOOL)isWarning sticky:(BOOL)sticky
737 NSParameterAssert(title != nil);
738 NSParameterAssert(message != nil);
740 // clean up enviroment a bit (hides possible warnings caused if these set for WOTestRunner)
741 NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary:[[NSProcessInfo processInfo] environment]];
742 [environment removeObjectForKey:@"DYLD_INSERT_LIBRARIES"];
743 [environment removeObjectForKey:@"WOTestBundleInjector"];
745 NSTask *task = [[[NSTask alloc] init] autorelease];
746 [task setLaunchPath:@"/usr/bin/env"]; // use env so as to pick up PATH, if set
747 [task setEnvironment:environment];
748 NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"growlnotify",
749 @"--name", @"com.wincent.WOTest",
750 @"--appIcon", @"Xcode",
751 @"--priority", (isWarning ? @"2" : @"0"),
752 @"--message", message,
754 if (sticky) [arguments insertObject:@"--sticky" atIndex:0];
755 [task setArguments:arguments];
757 // if env can't find growl it will write a message like "env: growlnotify: No such file or directory" to the standard error
758 // suppress it by redirecting the standard error to /dev/null
759 [task setStandardError:[NSFileHandle fileHandleForWritingAtPath:@"/dev/null"]];
764 [task waitUntilExit];
766 // handle error conditions
767 if (![task isRunning])
769 int status = [task terminationStatus];
770 if (status == 127) // env returns this when "[t]he utility specified by utility could not be found"
771 _WOLog(@"note: growlnotify not launched (not found in the current PATH)");
772 else if (status != EXIT_SUCCESS)
773 // a failure to run growlnotify is relatively harmless, so use warning rather than error
774 _WOLog(@"warning: env terminated with exit status %d while trying to run growlnotify", status);
777 @catch (NSException *e)
779 // highly unlikely that we'd ever get here, but report it anyway
780 _WOLog(@"warning: exception caught while trying to execute growlnotify using env (%@: %@)", [e name], [e reason]);
785 #pragma mark Logging methods
787 - (NSString *)trimmedPath:(char *)path
789 NSParameterAssert(path != NULL);
790 NSString *pathString = [NSString stringWithUTF8String:path];
792 unsigned trim = [self trimInitialPathComponents];
793 if (trim == 0) return pathString;
794 if (![pathString isAbsolutePath]) return pathString; // only trim absolute paths
795 NSArray *components = [pathString pathComponents]; // note: Cocoa returns "/" here as an additional first component
796 NSAssert(components != nil, @"components != nil");
797 unsigned count = [components count];
798 if (count < trim + 2) return pathString; // only trim if there will be at least one component left over
799 return [NSString pathWithComponents:[components subarrayWithRange:NSMakeRange(trim + 1, count - trim - 1)]];
802 - (void)writePassed:(BOOL)passed
805 message:(NSString *)message, ...
809 va_start(args, message);
810 NSString *string = [NSString WOTest_stringWithFormat:message arguments:args];
812 if ([self expectFailures]) // invert sense of tests (ie. failure is good)
814 if (passed) // passed: bad
816 [self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Passed (unexpected pass): %@", string]];
817 testsPassedUnexpected++;
821 [self writeStatusInFile:path atLine:line message:[NSString stringWithFormat:@"Failed (expected failure): %@", string]];
822 testsFailedExpected++;
825 else // normal handling (ie. passing is good, failing is bad)
827 if (passed) // passed: good
829 [self writeStatusInFile:path atLine:line message:[NSString stringWithFormat:@"Passed: %@", string]];
834 [self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Failed: %@", string]];
840 - (void)cacheFile:(char *)path line:(int)line
842 [self setLastReportedFile:[self trimmedPath:path]];
843 lastReportedLine = line;
846 - (void)writeLastKnownLocation
848 NSString *path = [self lastReportedFile];
850 _WOLog(@"%@:%d: last known location was %@:%d", path, lastReportedLine, path, lastReportedLine);
853 - (void)writeErrorInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
856 va_start(args, message);
857 NSString *error = [NSString WOTest_stringWithFormat:message arguments:args];
858 _WOLog(@"%@:%d: error: %@", [self trimmedPath:path], line, error);
859 [self cacheFile:path line:line];
863 - (void)writeWarningInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
866 va_start(args, message);
867 NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
868 _WOLog(@"%@:%d: warning: %@", [self trimmedPath:path], line, warning);
869 [self cacheFile:path line:line];
873 - (void)writeUncaughtException:(NSString *)info inFile:(char *)path atLine:(int)line
875 _WOLog(@"%@:%d: error: uncaught exception during test execution: %@", [self trimmedPath:path], line, info);
876 uncaughtExceptions++;
879 - (void)writeStatusInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
882 va_start(args, message);
883 NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
884 _WOLog(@"%@:%d %@", [self trimmedPath:path], line, status); // omit colin after line number or Xcode will show this as an error
885 [self cacheFile:path line:line];
889 - (void)writeStatus:(NSString *)message, ...
892 va_start(args, message);
893 NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
894 _WOLog(@"%@", status);
898 - (void)writeWarning:(NSString *)message, ...
901 va_start(args, message);
902 NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
903 _WOLog(@"warning: %@", warning); // older versions of Xcode required initial colons "::" to show this as a warning
907 - (void)writeError:(NSString *)message, ...
910 va_start(args, message);
911 NSString *error = [NSString WOTest_stringWithFormat:message arguments:args];
912 _WOLog(@"error: %@", error); // older versions of Xcode required initial colons "::" to show this as an error
917 #pragma mark Empty (do-nothing) test methods
919 - (void)passTestInFile:(char *)path atLine:(int)line
921 [self writePassed:YES inFile:path atLine:line message:@"(always passes)"];
924 - (void)failTestInFile:(char *)path atLine:(int)line
926 [self writePassed:NO inFile:path atLine:line message:@"(always fails)"];
930 #pragma mark Boolean test methods
932 - (void)testTrue:(BOOL)expr inFile:(char *)path atLine:(int)line
934 [self writePassed:expr inFile:path atLine:line message:@"expected YES, got %@", (expr ? @"YES" : @"NO")];
937 - (void)testFalse:(BOOL)expr inFile:(char *)path atLine:(int)line
939 [self writePassed:!expr inFile:path atLine:line message:@"expected NO, got %@", (expr ? @"YES" : @"NO")];
943 #pragma mark NSValue-based tests
945 - (void)testValue:(NSValue *)actual isEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line
947 NSParameterAssert(actual);
948 NSParameterAssert(expected);
951 // NSValue category will throw an exception for invalid input(s)
953 equal = [actual WOTest_testIsEqualToValue:expected];
956 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
957 uncaughtExceptions++;
959 BOOL expectedTruncated, actualTruncated;
960 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
961 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
962 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
965 - (void)testValue:(NSValue *)actual isNotEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line
967 NSParameterAssert(actual);
968 NSParameterAssert(expected);
971 // NSValue category will throw an exception for invalid input(s)
973 equal = [actual WOTest_testIsEqualToValue:expected];
976 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
977 uncaughtExceptions++;
979 BOOL expectedTruncated, actualTruncated;
980 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
981 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
982 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
985 - (void)testValue:(NSValue *)actual greaterThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
987 NSParameterAssert(actual);
988 NSParameterAssert(expected);
989 BOOL greaterThan = NO;
991 // NSValue category will throw an exception for invalid input(s)
993 greaterThan = [actual WOTest_testIsGreaterThanValue:expected];
996 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
997 uncaughtExceptions++;
999 BOOL expectedTruncated, actualTruncated;
1000 [self writePassed:greaterThan inFile:path atLine:line message:@"expected > %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1001 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1002 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1005 - (void)testValue:(NSValue *)actual notGreaterThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1007 NSParameterAssert(actual);
1008 NSParameterAssert(expected);
1009 BOOL notGreaterThan = NO;
1011 // NSValue category will throw an exception for invalid input(s)
1013 notGreaterThan = [actual WOTest_testIsNotGreaterThanValue:expected];
1016 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1017 uncaughtExceptions++;
1019 BOOL expectedTruncated, actualTruncated;
1020 [self writePassed:notGreaterThan inFile:path atLine:line message:@"expected <= %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1021 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1022 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1025 - (void)testValue:(NSValue *)actual lessThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1027 NSParameterAssert(actual);
1028 NSParameterAssert(expected);
1031 // NSValue category will throw an exception for invalid input(s)
1033 lessThan = [actual WOTest_testIsLessThanValue:expected];
1036 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1037 uncaughtExceptions++;
1039 BOOL expectedTruncated, actualTruncated;
1040 [self writePassed:lessThan inFile:path atLine:line message:@"expected < %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1041 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1042 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1045 - (void)testValue:(NSValue *)actual notLessThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1047 NSParameterAssert(actual);
1048 NSParameterAssert(expected);
1049 BOOL notLessThan = NO;
1051 // NSValue category will throw an exception for invalid input(s)
1053 notLessThan = [actual WOTest_testIsNotLessThanValue:expected];
1056 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1057 uncaughtExceptions++;
1059 BOOL expectedTruncated, actualTruncated;
1060 [self writePassed:notLessThan inFile:path atLine:line message:@"expected >= %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1061 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1062 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1066 #pragma mark Pointer to void test methods
1068 - (void)testNil:(void *)pointer inFile:(char *)path atLine:(int)line
1070 BOOL result = (pointer ? NO : YES);
1071 [self writePassed:result inFile:path atLine:line message:@"expected nil, got %@",
1072 (result ? @"nil" : [NSString stringWithFormat:@"%x", pointer])];
1075 - (void)testNotNil:(void *)pointer inFile:(char *)path atLine:(int)line
1077 BOOL result = (pointer ? YES : NO);
1078 [self writePassed:result inFile:path atLine:line message:@"expected (not) nil, got %@",
1079 (result ? [NSString stringWithFormat:@"%x", pointer] : @"nil")];
1082 - (void)testPointer:(void *)actual isEqualTo:(void *)expected inFile:(char *)path atLine:(int)line
1084 BOOL result = (actual == expected);
1085 [self writePassed:result inFile:path atLine:line message:@"expected %x, got %x", expected, actual];
1088 - (void)testPointer:(void *)actual isNotEqualTo:(void *)expected inFile:(char *)path atLine:(int)line
1090 BOOL result = (actual != expected);
1091 [self writePassed:result inFile:path atLine:line message:@"expected (not) %x, got %x", expected, actual];
1095 #pragma mark int test methods
1097 - (void)testIsInt:(char *)type inFile:(char *)path atLine:(int)line
1099 BOOL result = (strcmp(type, "i") == 0);
1100 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"i\", got \"%s\"", type]];
1103 - (void)testIsNotInt:(char *)type inFile:(char *)path atLine:(int)line
1105 BOOL result = (strcmp(type, "i") != 0);
1106 [self writePassed:result
1109 message:[NSString stringWithFormat:@"expected type (not) \"i\", got \"%s\"", type]];
1112 - (void)testIntPositive:(int)aInt inFile:(char *)path atLine:(int)line
1114 [self testInt:aInt greaterThan:(int)0 inFile:path atLine:line];
1117 - (void)testIntNegative:(int)aInt inFile:(char *)path atLine:(int)line
1119 [self testInt:aInt lessThan:(int)0 inFile:path atLine:line];
1122 - (void)testIntZero:(int)aInt inFile:(char *)path atLine:(int)line
1124 [self testInt:aInt isEqualTo:(int)0 inFile:path atLine:line];
1127 - (void)testIntNotZero:(int)aInt inFile:(char *)path atLine:(int)line
1129 [self testInt:aInt isNotEqualTo:(int)0 inFile:path atLine:line];
1132 - (void)testInt:(int)actual isEqualTo:(int)expected inFile:(char *)path atLine:(int)line
1134 BOOL result = (actual == expected);
1135 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat:@"expected %d, got %d", expected, actual]];
1138 - (void)testInt:(int)actual isNotEqualTo:(int)expected inFile:(char *)path atLine:(int)line
1140 BOOL result = (actual != expected);
1141 [self writePassed:result
1144 message:[NSString stringWithFormat:@"expected (not) %d, got %d", expected, actual]];
1147 - (void)testInt:(int)actual greaterThan:(int)expected inFile:(char *)path atLine:(int)line
1149 BOOL result = (actual > expected);
1150 [self writePassed:result
1153 message:[NSString stringWithFormat:@"expected > %d, got %d", expected, actual]];
1156 - (void)testInt:(int)actual notGreaterThan:(int)expected inFile:(char *)path atLine:(int)line
1158 BOOL result = (actual <= expected);
1159 [self writePassed:result
1162 message:[NSString stringWithFormat:@"expected <= %d, got %d", expected, actual]];
1165 - (void)testInt:(int)actual lessThan:(int)expected inFile:(char *)path atLine:(int)line
1167 BOOL result = (actual < expected);
1168 [self writePassed:result
1171 message:[NSString stringWithFormat:@"expected < %d, got %d", expected, actual]];
1174 - (void)testInt:(int)actual notLessThan:(int)expected inFile:(char *)path atLine:(int)line
1176 BOOL result = (actual >= expected);
1177 [self writePassed:result
1180 message:[NSString stringWithFormat:@"expected >= %d, got %d", expected, actual]];
1184 #pragma mark unsigned test methods
1186 - (void)testIsUnsigned:(char *)type inFile:(char *)path atLine:(int)line
1188 BOOL result = (strcmp(type, "I") == 0);
1189 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"I\", got \"%s\"", type]];
1192 - (void)testIsNotUnsigned:(char *)type inFile:(char *)path atLine:(int)line
1194 BOOL result = (strcmp(type, "I") != 0);
1195 [self writePassed:result
1198 message:[NSString stringWithFormat:@"expected type (not) \"I\", got \"%s\"", type]];
1201 - (void)testUnsignedZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
1203 return [self testUnsigned:aUnsigned isEqualTo:(unsigned)0 inFile:path atLine:line];
1206 - (void)testUnsignedNotZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
1208 return [self testUnsigned:aUnsigned isNotEqualTo:(unsigned)0 inFile:path atLine:line];
1211 - (void)testUnsigned:(unsigned)actual isEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
1213 BOOL result = (actual == expected);
1214 [self writePassed:result
1217 message:[NSString stringWithFormat:@"expected %u, got %u", expected, actual]];
1220 - (void)testUnsigned:(unsigned)actual isNotEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
1222 BOOL result = (actual != expected);
1223 [self writePassed:result
1226 message:[NSString stringWithFormat:@"expected (not) %u, got %u", expected, actual]];
1229 - (void)testUnsigned:(unsigned)actual greaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1231 BOOL result = (actual > expected);
1232 [self writePassed:result
1235 message:[NSString stringWithFormat:@"expected > %u, got %u", expected, actual]];
1238 - (void)testUnsigned:(unsigned)actual notGreaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1240 BOOL result = (actual <= expected);
1241 [self writePassed:result
1244 message:[NSString stringWithFormat:@"expected <= %u, got %u", expected, actual]];
1247 - (void)testUnsigned:(unsigned)actual lessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1249 BOOL result = (actual < expected);
1250 [self writePassed:result
1253 message:[NSString stringWithFormat:@"expected < %u, got %u", expected, actual]];
1256 - (void)testUnsigned:(unsigned)actual notLessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1258 BOOL result = (actual >= expected);
1259 [self writePassed:result
1262 message:[NSString stringWithFormat:@"expected >= %u, got %u", expected, actual]];
1266 #pragma mark float test methods without error margins
1268 - (void)testIsFloat:(char *)type inFile:(char *)path atLine:(int)line
1270 BOOL result = (strcmp(type, "f") == 0);
1271 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"f\", got \"%s\"", type]];
1274 - (void)testIsNotFloat:(char *)type inFile:(char *)path atLine:(int)line
1276 BOOL result = (strcmp(type, "f") != 0);
1277 [self writePassed:result
1280 message:[NSString stringWithFormat:@"expected type (not) \"f\", got \"%s\"", type]];
1283 - (void)testFloatPositive:(float)aFloat inFile:(char *)path atLine:(int)line
1285 return [self testFloat:aFloat greaterThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1288 - (void)testFloatNegative:(float)aFloat inFile:(char *)path atLine:(int)line
1290 return [self testFloat:aFloat lessThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1293 - (void)testFloatZero:(float)aFloat inFile:(char *)path atLine:(int)line
1295 return [self testFloat:aFloat isEqualTo:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1298 - (void)testFloatNotZero:(float)aFloat inFile:(char *)path atLine:(int)line
1300 return [self testFloat:aFloat isNotEqualTo:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1303 - (void)testFloat:(float)actual isEqualTo:(float)expected inFile:(char *)path atLine:(int)line
1305 return [self testFloat:actual isEqualTo:expected withinError:(float)0.0 inFile:path atLine:line];
1308 - (void)testFloat:(float)actual isNotEqualTo:(float)expected inFile:(char *)path atLine:(int)line
1310 return [self testFloat:actual isNotEqualTo:expected withinError:(float)0.0 inFile:path atLine:line];
1313 - (void)testFloat:(float)actual greaterThan:(float)expected inFile:(char *)path atLine:(int)line
1315 return [self testFloat:actual greaterThan:expected withinError:(float)0.0 inFile:path atLine:line];
1318 - (void)testFloat:(float)actual notGreaterThan:(float)expected inFile:(char *)path atLine:(int)line
1320 return [self testFloat:actual notGreaterThan:expected withinError:(float)0.0 inFile:path atLine:line];
1323 - (void)testFloat:(float)actual lessThan:(float)expected inFile:(char *)path atLine:(int)line
1325 return [self testFloat:actual lessThan:expected withinError:(float)0.0 inFile:path atLine:line];
1328 - (void)testFloat:(float)actual notLessThan:(float)expected inFile:(char *)path atLine:(int)line
1330 return [self testFloat:actual notLessThan:expected withinError:(float)0.0 inFile:path atLine:line];
1334 #pragma mark float test methods with error margins
1336 - (void)testFloatPositive:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1338 return [self testFloat:aFloat greaterThan:(float)0.0 withinError:error inFile:path atLine:line];
1341 - (void)testFloatNegative:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1343 return [self testFloat:aFloat lessThan:(float)0.0 withinError:error inFile:path atLine:line];
1346 - (void)testFloatZero:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1348 return [self testFloat:aFloat isEqualTo:(float)0.0 withinError:error inFile:path atLine:line];
1351 - (void)testFloatNotZero:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1353 return [self testFloat:aFloat isNotEqualTo:(float)0.0 withinError:error inFile:path atLine:line];
1356 - (void)testFloat:(float)actual isEqualTo:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1358 BOOL result = (fabsf(actual - expected) <= error);
1359 [self writePassed:result
1363 [NSString stringWithFormat:@"expected %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1366 - (void)testFloat:(float)actual isNotEqualTo:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1368 BOOL result = (fabsf(actual - expected) > -error);
1369 [self writePassed:result
1373 [NSString stringWithFormat:@"expected (not) %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1376 - (void)testFloat:(float)actual greaterThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1378 BOOL result = ((actual - expected) > -error);
1379 [self writePassed:result
1383 [NSString stringWithFormat:@"expected > %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1386 - (void)testFloat:(float)actual notGreaterThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1388 BOOL result = ((actual - expected) <= error);
1389 [self writePassed:result
1393 [NSString stringWithFormat:@"expected <= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1396 - (void)testFloat:(float)actual lessThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1398 BOOL result = ((actual - expected) < -error);
1399 [self writePassed:result
1403 [NSString stringWithFormat:@"expected < %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1406 - (void)testFloat:(float)actual notLessThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1408 BOOL result = ((actual - expected) >= error);
1409 [self writePassed:result
1413 [NSString stringWithFormat:@"expected >= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1417 #pragma mark double test methods without error margins
1419 - (void)testIsDouble:(char *)type inFile:(char *)path atLine:(int)line
1421 BOOL result = (strcmp(type, "d") == 0);
1422 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"d\", got \"%s\"", type]];
1425 - (void)testIsNotDouble:(char *)type inFile:(char *)path atLine:(int)line
1427 BOOL result = (strcmp(type, "d") != 0);
1428 [self writePassed:result
1431 message:[NSString stringWithFormat:@"expected type (not) \"d\", got \"%s\"", type]];
1434 - (void)testDoublePositive:(double)aDouble inFile:(char *)path atLine:(int)line
1436 return [self testDouble:aDouble greaterThan:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1439 - (void)testDoubleNegative:(double)aDouble inFile:(char *)path atLine:(int)line
1441 return [self testDouble:aDouble lessThan:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1444 - (void)testDoubleZero:(double)aDouble inFile:(char *)path atLine:(int)line
1446 return [self testDouble:aDouble isEqualTo:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1449 - (void)testDoubleNotZero:(double)aDouble inFile:(char *)path atLine:(int)line
1451 return [self testDouble:aDouble isNotEqualTo:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1454 - (void)testDouble:(double)actual isEqualTo:(double)expected inFile:(char *)path atLine:(int)line
1456 return [self testDouble:actual isEqualTo:expected withinError:(double)0.0 inFile:path atLine:line];
1459 - (void)testDouble:(double)actual isNotEqualTo:(double)expected inFile:(char *)path atLine:(int)line
1461 return [self testDouble:actual isNotEqualTo:expected withinError:(double)0.0 inFile:path atLine:line];
1464 - (void)testDouble:(double)actual greaterThan:(double)expected inFile:(char *)path atLine:(int)line
1466 return [self testDouble:actual greaterThan:expected withinError:(double)0.0 inFile:path atLine:line];
1469 - (void)testDouble:(double)actual notGreaterThan:(double)expected inFile:(char *)path atLine:(int)line
1471 return [self testDouble:actual notGreaterThan:expected withinError:(double)0.0 inFile:path atLine:line];
1474 - (void)testDouble:(double)actual lessThan:(double)expected inFile:(char *)path atLine:(int)line
1476 return [self testDouble:actual lessThan:expected withinError:(double)0.0 inFile:path atLine:line];
1479 - (void)testDouble:(double)actual notLessThan:(double)expected inFile:(char *)path atLine:(int)line
1481 return [self testDouble:actual notLessThan:expected withinError:(double)0.0 inFile:path atLine:line];
1485 #pragma mark double test methods with error margins
1487 - (void)testDoublePositive:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1489 return [self testDouble:aDouble greaterThan:(double)0.0 withinError:error inFile:path atLine:line];
1492 - (void)testDoubleNegative:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1494 return [self testDouble:aDouble lessThan:(double)0.0 withinError:error inFile:path atLine:line];
1497 - (void)testDoubleZero:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1499 return [self testDouble:aDouble isEqualTo:(double)0.0 withinError:error inFile:path atLine:line];
1502 - (void)testDoubleNotZero:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1504 return [self testDouble:aDouble isNotEqualTo:(double)0.0 withinError:error inFile:path atLine:line];
1507 - (void)testDouble:(double)actual isEqualTo:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1509 BOOL result = (fabs(actual - expected) <= error);
1510 [self writePassed:result
1514 [NSString stringWithFormat:@"expected %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1517 - (void)testDouble:(double)actual isNotEqualTo:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1519 BOOL result = (fabs(actual - expected) > -error);
1520 [self writePassed:result
1524 [NSString stringWithFormat:@"expected (not) %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1527 - (void)testDouble:(double)actual greaterThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1529 BOOL result = ((actual - expected) > -error);
1530 [self writePassed:result
1534 [NSString stringWithFormat:@"expected > %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1537 - (void)testDouble:(double)actual notGreaterThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1539 BOOL result = ((actual - expected) <= error);
1540 [self writePassed:result
1544 [NSString stringWithFormat:@"expected <= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1547 - (void)testDouble:(double)actual lessThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1549 BOOL result = ((actual - expected) < -error);
1550 [self writePassed:result
1554 [NSString stringWithFormat:@"expected < %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1557 - (void)testDouble:(double)actual notLessThan:(double)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1559 BOOL result = ((actual - expected) >= error);
1560 [self writePassed:result
1564 [NSString stringWithFormat:@"expected >= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1568 #pragma mark object test methods
1570 - (void)testObject:(id)actual isEqualTo:(id)expected inFile:(char *)path atLine:(int)line
1573 if (!actual && !expected) equal = YES; // equal (both nil)
1574 else if (actual) equal = [actual isEqual:expected];
1575 BOOL expectedTruncated, actualTruncated;
1576 [self writePassed:equal inFile:path atLine:line message:@"expected \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1577 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1578 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1581 - (void)testObject:(id)actual isNotEqualTo:(id)expected inFile:(char *)path atLine:(int)line
1584 if (!actual && !expected) equal = YES; // equal (both nil)
1585 else if (actual) equal = [actual isEqual:expected];
1586 BOOL expectedTruncated, actualTruncated;
1587 [self writePassed:(!equal)
1590 message:@"expected (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1591 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1592 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1596 #pragma mark NSString test methods
1598 - (void)testString:(NSString *)actual isEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line
1600 if (actual && ![actual isKindOfClass:[NSString class]])
1601 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1602 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1605 if (expected && ![expected isKindOfClass:[NSString class]])
1606 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1607 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1611 if (!actual && !expected) equal = YES; // equal (both nil)
1612 else if (actual) equal = [actual isEqualToString:expected];
1613 BOOL expectedTruncated, actualTruncated;
1614 [self writePassed:equal inFile:path atLine:line message:@"expected \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1615 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1616 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1619 - (void)testString:(NSString *)actual isNotEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line
1621 if (actual && ![actual isKindOfClass:[NSString class]])
1622 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1623 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1626 if (expected && ![expected isKindOfClass:[NSString class]])
1627 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1628 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1632 if (!actual && !expected) equal = YES; // equal (both nil)
1633 else if (actual) equal = [actual isEqualToString:expected];
1634 BOOL expectedTruncated, actualTruncated;
1635 [self writePassed:equal
1638 message:@"expected (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1639 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1640 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1643 - (void)testString:(NSString *)actual hasPrefix:(NSString *)expected inFile:(char *)path atLine:(int)line
1646 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1647 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1650 if (actual && ![actual isKindOfClass:[NSString class]])
1651 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1652 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1655 if (![expected isKindOfClass:[NSString class]])
1656 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1657 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1660 BOOL result = actual ? NO : [actual hasPrefix:expected];
1661 BOOL expectedTruncated, actualTruncated;
1662 [self writePassed:result
1665 message:@"expected prefix \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1666 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1667 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1670 - (void)testString:(NSString *)actual doesNotHavePrefix:(NSString *)expected inFile:(char *)path atLine:(int)line
1673 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1674 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1677 if (actual && ![actual isKindOfClass:[NSString class]])
1678 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1679 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1682 if (![expected isKindOfClass:[NSString class]])
1683 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1684 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1687 BOOL result = actual ? (![actual hasPrefix:expected]) : NO;
1688 BOOL expectedTruncated, actualTruncated;
1689 [self writePassed:result
1692 message:@"expected prefix (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1693 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1694 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1697 - (void)testString:(NSString *)actual hasSuffix:(NSString *)expected inFile:(char *)path atLine:(int)line
1700 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1701 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1704 if (actual && ![actual isKindOfClass:[NSString class]])
1705 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1706 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1709 if (![expected isKindOfClass:[NSString class]])
1710 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1711 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1714 BOOL result = actual ? NO : [actual hasSuffix:expected];
1715 BOOL expectedTruncated, actualTruncated;
1716 [self writePassed:result
1719 message:@"expected suffix \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1720 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1721 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1724 - (void)testString:(NSString *)actual doesNotHaveSuffix:(NSString *)expected inFile:(char *)path atLine:(int)line
1727 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1728 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1731 if (actual && ![actual isKindOfClass:[NSString class]])
1732 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1733 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1736 if (![expected isKindOfClass:[NSString class]])
1737 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1738 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1741 BOOL result = actual ? (![actual hasSuffix:expected]) : NO;
1742 BOOL expectedTruncated, actualTruncated;
1743 [self writePassed:result
1746 message:@"expected suffix (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1747 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1748 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1751 - (void)testString:(NSString *)actual contains:(NSString *)expected inFile:(char *)path atLine:(int)line
1754 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1755 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1758 if (actual && ![actual isKindOfClass:[NSString class]])
1759 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1760 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1763 if (![expected isKindOfClass:[NSString class]])
1764 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1765 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1768 BOOL result = actual ? NO : (!NSEqualRanges([actual rangeOfString:expected], NSMakeRange(NSNotFound, 0)));
1769 BOOL expectedTruncated, actualTruncated;
1770 [self writePassed:result
1773 message:@"expected contains \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1774 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1775 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1778 - (void)testString:(NSString *)actual doesNotContain:(NSString *)expected inFile:(char *)path atLine:(int)line
1781 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1782 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1785 if (actual && ![actual isKindOfClass:[NSString class]])
1786 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1787 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1790 if (![expected isKindOfClass:[NSString class]])
1791 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1792 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1795 BOOL result = actual ? YES : (NSEqualRanges([actual rangeOfString:expected], NSMakeRange(NSNotFound, 0)));
1796 BOOL expectedTruncated, actualTruncated;
1797 [self writePassed:result
1800 message:@"expected contains (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1801 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1802 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1806 #pragma mark NSArray test methods
1808 - (void)testArray:(NSArray *)actual isEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line
1810 if (actual && ![actual isKindOfClass:[NSArray class]])
1811 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1812 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(actual)
1815 if (expected && ![expected isKindOfClass:[NSArray class]])
1816 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1817 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(expected)
1821 if (!actual && !expected) equal = YES; // equal (both nil)
1822 else if (actual) equal = [actual isEqualToArray:expected];
1823 BOOL expectedTruncated, actualTruncated;
1824 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1825 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1826 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1829 - (void)testArray:(NSArray *)actual isNotEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line
1831 if (actual && ![actual isKindOfClass:[NSArray class]])
1832 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1833 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(actual)
1836 if (expected && ![expected isKindOfClass:[NSArray class]])
1837 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1838 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(expected)
1842 if (!actual && !expected) equal = YES; // equal (both nil)
1843 else if (actual) equal = [actual isEqualToArray:expected];
1844 BOOL expectedTruncated, actualTruncated;
1845 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1846 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1847 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1851 #pragma mark NSDictionary test methods
1853 - (void)testDictionary:(NSDictionary *)actual isEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line
1855 if (actual && ![actual isKindOfClass:[NSArray class]])
1856 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1857 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(actual)
1860 if (expected && ![expected isKindOfClass:[NSArray class]])
1861 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1862 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(expected)
1866 if (!actual && !expected) equal = YES; // equal (both nil)
1867 else if (actual) equal = [actual isEqualToDictionary:expected];
1868 BOOL expectedTruncated, actualTruncated;
1869 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1870 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1871 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1874 - (void)testDictionary:(NSDictionary *)actual isNotEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line
1876 if (actual && ![actual isKindOfClass:[NSDictionary class]])
1877 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1878 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(actual)
1881 if (expected && ![expected isKindOfClass:[NSDictionary class]])
1882 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1883 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(expected)
1887 if (!actual && !expected) equal = YES; // equal (both nil)
1888 else if (actual) equal = [actual isEqualToDictionary:expected];
1889 BOOL expectedTruncated, actualTruncated;
1890 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1891 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1892 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1896 #pragma mark Exception test methods
1898 - (void)testThrowsException:(id)exception inFile:(char *)path atLine:(int)line
1900 BOOL result = (exception ? YES : NO);
1901 [self writePassed:result
1904 message:[NSString stringWithFormat:@"expected exception, got %@", [NSException WOTest_nameForException:exception]]];
1907 - (void)testDoesNotThrowException:(id)exception inFile:(char *)path atLine:(int)line
1909 BOOL result = (exception ? NO : YES);
1910 [self writePassed:result
1914 [NSString stringWithFormat:@"expected no exception, got %@", [NSException WOTest_nameForException:exception]]];
1917 - (void)testThrowsException:(id)exception named:(NSString *)name inFile:(char *)path atLine:(int)line
1919 if (name && ![name isKindOfClass:[NSString class]])
1921 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1922 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(name)
1928 NSString *actualName = [NSException WOTest_nameForException:exception];
1930 if (exception && [actualName isEqualToString:name]) result = YES;
1932 [self writePassed:result
1935 message:[NSString stringWithFormat:@"expected %@, got %@", name, actualName]];
1938 - (void)testDoesNotThrowException:(id)exception named:(NSString *)name inFile:(char *)path atLine:(int)line
1940 if (name && ![name isKindOfClass:[NSString class]])
1942 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1943 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(name)
1949 NSString *actualName = [NSException WOTest_nameForException:exception];
1951 if (exception && [actualName isEqualToString:name]) result = NO;
1953 [self writePassed:result inFile:path atLine:line message:@"expected (not) %@, got %@", name, actualName];
1957 #pragma mark Random value generator methods
1959 // TODO: move these into a category, these are more "test helpers" rather than actual "testing methods"
1963 return (int)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1968 return (int)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1973 return (int)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1983 return (int)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1986 - (int)aBigPositiveInt
1988 return (int)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1991 - (int)aBigNegativeInt
1993 return (int)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1998 return (int)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2001 - (int)aSmallPositiveInt
2003 return (int)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2006 - (int)aSmallNegativeInt
2008 return (int)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2011 - (unsigned)anUnsigned
2013 return (unsigned)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2016 - (unsigned)aZeroUnsigned
2021 - (unsigned)aBigUnsigned
2023 return (unsigned)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2026 - (unsigned)aSmallUnsigned
2028 return (unsigned)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2033 return (float)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2036 - (float)aPositiveFloat
2038 return (float)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2041 - (float)aNegativeFloat
2043 return (float)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2053 return (float)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2056 - (float)aBigPositiveFloat
2058 return (float)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2061 - (float)aBigNegativeFloat
2063 return (float)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2066 - (float)aSmallFloat
2068 return (float)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2071 - (float)aSmallPositiveFloat
2073 return (float)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2076 - (float)aSmallNegativeFloat
2078 return (float)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2083 return (double)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2086 - (double)aPositiveDouble
2088 return (double)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2091 - (double)aNegativeDouble
2093 return (double)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2096 - (double)aZeroDouble
2101 - (double)aBigDouble
2103 return (double)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2106 - (double)aBigPositiveDouble
2108 return (double)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2111 - (double)aBigNegativeDouble
2113 return (double)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2116 - (double)aSmallDouble
2118 return (double)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2121 - (double)aSmallPositiveDouble
2123 return (double)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2126 - (double)aSmallNegativeDouble
2128 return (double)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2132 #pragma mark Accessors
2134 - (NSDate *)startDate
2136 return [[startDate retain] autorelease];
2139 - (void)setStartDate:(NSDate *)aStartDate
2141 [aStartDate retain];
2142 [startDate release];
2143 startDate = aStartDate;
2146 - (unsigned)classesWithTests
2148 return classesWithTests;
2151 - (unsigned)classesWithoutTests
2153 return classesWithoutTests;
2156 - (unsigned)methodsWithTests
2158 return methodsWithTests;
2161 - (unsigned)testsRun
2166 - (unsigned)testsPassed
2171 - (unsigned)testsFailed
2176 - (unsigned)uncaughtExceptions
2178 return uncaughtExceptions;
2181 - (unsigned)testsFailedExpected
2183 return testsFailedExpected;
2186 - (unsigned)testsPassedUnexpected
2188 return testsPassedUnexpected;
2191 - (BOOL)expectFailures
2193 return expectFailures;
2196 - (void)setExpectFailures:(BOOL)aValue
2198 expectFailures = aValue;
2201 - (unsigned)lowLevelExceptionsExpected
2203 return lowLevelExceptionsExpected;
2206 - (unsigned)lowLevelExceptionsUnexpected
2208 return lowLevelExceptionsUnexpected;
2211 - (BOOL)expectLowLevelExceptions
2213 return expectLowLevelExceptions;
2216 - (void)setExpectLowLevelExceptions:(BOOL)aValue
2218 expectLowLevelExceptions = aValue;
2221 - (BOOL)handlesLowLevelExceptions
2223 return handlesLowLevelExceptions;
2226 - (void)setHandlesLowLevelExceptions:(BOOL)aValue
2228 handlesLowLevelExceptions = aValue;
2231 - (unsigned)verbosity
2236 - (void)setVerbosity:(unsigned)aVerbosity
2238 verbosity = aVerbosity;
2241 - (unsigned)trimInitialPathComponents
2243 return trimInitialPathComponents;
2246 - (void)setTrimInitialPathComponents:(unsigned)aTrimInitialPathComponents
2248 trimInitialPathComponents = aTrimInitialPathComponents;
2251 - (NSString *)lastReportedFile
2253 return [[lastReportedFile retain] autorelease];
2256 - (void)setLastReportedFile:(NSString *)aLastReportedFile
2258 if (lastReportedFile != aLastReportedFile)
2260 [aLastReportedFile retain];
2261 [lastReportedFile release];
2262 lastReportedFile = aLastReportedFile;
2266 - (BOOL)warnsAboutSignComparisons
2268 return warnsAboutSignComparisons;
2271 - (void)setWarnsAboutSignComparisons:(BOOL)aWarnsAboutSignComparisons
2273 warnsAboutSignComparisons = aWarnsAboutSignComparisons;