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 WO_ENUMERATE([self testableClasses], class)
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 NSArray *methods = [self testableMethodsFrom:aClass];
364 WO_ENUMERATE(methods, method)
366 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
367 NSDate *startMethod = [NSDate date];
368 SEL preflight = @selector(preflight);
369 SEL postflight = @selector(postflight);
371 _WOLog(@"Running test method %@", method);
374 // minimize time spent with exception handlers in place
375 [self installLowLevelExceptionHandler];
377 // record program counter and some other registers right now
379 // LowLevelABI.pdf says "EDI, ESI, EBX, EBP" are the preserved registers (across function calls)
380 // ebp is the "saved frame pointer": "the base address of the caller's stack frame"
381 // eax is used to return pointer and integral results to callers: "The called function places integral or pointer results in EAX"
383 // info on inline assembly: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
384 __asm__ volatile("movl %%eax, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.eax));
385 __asm__ volatile("movl %%ebx, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebx));
386 __asm__ volatile("movl %%edi, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.edi));
387 __asm__ volatile("movl %%esi, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.esi));
388 __asm__ volatile("movl %%esp, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.esp));
389 __asm__ volatile("movl %%ebp, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebp));
391 // done this way in Linux (see acpi_save_register_state function)
392 WOProgramCounter = (unsigned long)&&jump_point;
393 #elif defined (__ppc__)
394 // equivalent to (psuedo code) "WOProgramCounter = current contents of PC register"
395 unsigned long counter;
396 __asm__ volatile("mflr %0" : "=r" (counter));
397 WOProgramCounter.lo = counter & 0xffffffff;
398 WOProgramCounter.hi = (counter & 0xffffffff00000000) >> 32;
400 #error Unsupported architecture
404 goto jump_point; // necessary to silence compiler warning about unused label
406 // if flag set, that means we crashed: throw an exception
407 if (WOTestExceptionTriggered)
409 WOTestExceptionTriggered = 0;
410 @throw [WOTestLowLevelException exceptionWithType:WOLastLowLevelException];
413 if ([self isClassMethod:method])
415 if ([NSObject WOTest_class:aClass respondsToSelector:preflight])
416 objc_msgSend(aClass, preflight);
417 objc_msgSend(aClass, [self selectorFromMethod:method]);
418 if ([NSObject WOTest_class:aClass respondsToSelector:postflight])
419 objc_msgSend(aClass, postflight);
421 else if ([self isInstanceMethod:method])
423 // class must implement alloc, init and release
424 if ([NSObject WOTest_object:aClass respondsToSelector:@selector(alloc)] &&
425 [NSObject WOTest_instancesOfClass:aClass respondToSelector:@selector(init)] &&
426 [NSObject WOTest_instancesOfClass:aClass respondToSelector:@selector(release)])
428 id instance = [[aClass alloc] init];
429 if ([NSObject WOTest_instancesOfClass:aClass respondToSelector:preflight])
430 objc_msgSend(instance, preflight);
431 objc_msgSend(instance, [self selectorFromMethod:method]);
432 if ([NSObject WOTest_instancesOfClass:aClass respondToSelector:postflight])
433 objc_msgSend(instance, postflight);
438 [self writeError:@"Class %@ must respond to the alloc, init and release selectors",
439 NSStringFromClass(aClass)];
440 [self writeLastKnownLocation];
443 else // should never get here
444 [self writeError:@"WOTest internal error"];
446 @catch (WOTestLowLevelException *lowLevelException)
448 if ([self expectLowLevelExceptions])
450 [self writeStatus:[lowLevelException reason]]; // expected low-level exceptions are not an error
451 lowLevelExceptionsExpected++;
455 [self writeError:[lowLevelException reason]]; // unexpected low-level exceptions are an error
456 [self writeLastKnownLocation];
458 lowLevelExceptionsUnexpected++;
463 [self writeError:@"uncaught exception (%@) in test method %@", [NSException WOTest_descriptionForException:e],
465 [self writeLastKnownLocation];
467 uncaughtExceptions++;
471 if (lowLevelExceptionHandlerInstalled)
472 [self removeLowLevelExceptionHandler];
473 _WOLog(@"Finished test method %@ (%.4f seconds)", method, -[startMethod timeIntervalSinceNow]);
481 [self writeError:@"uncaught exception (%@) testing class %@", [NSException WOTest_descriptionForException:e],
482 NSStringFromClass(aClass)];
483 [self writeLastKnownLocation];
485 uncaughtExceptions++;
489 _WOLog(@"Finished tests for class %@ (%.4f seconds)", NSStringFromClass(aClass), -[startClass timeIntervalSinceNow]);
494 - (NSArray *)testableClasses
496 // return an array of class names
497 NSMutableArray *testableClasses = [NSMutableArray array];
499 unsigned classCount = 0; // the total number of classes
500 unsigned conformingClassCount = 0; // classes conforming to WOTest
501 unsigned nonconformingClassCount = 0; // unconforming classes
502 unsigned excludedClassCount = 0; // excluded classes
503 unsigned exceptionCount = 0; // classes provoking exceptions
506 int newNumClasses = objc_getClassList(NULL, 0);
507 Class *classes = NULL;
509 // get a list of all classes on the system
510 while (numClasses < newNumClasses)
512 numClasses = newNumClasses;
513 size_t bufferSize = sizeof(Class) * numClasses;
514 classes = realloc(classes, bufferSize);
515 NSAssert1((classes != NULL), @"realloc() failed (size %d)", bufferSize);
516 newNumClasses = objc_getClassList(classes, numClasses);
523 // skip over some classes because they not only cause exceptions but also spew out ugly console messages
524 SInt32 systemVersion;
525 Gestalt(gestaltSystemVersion, &systemVersion);
526 systemVersion = systemVersion & 0x0000ffff; // Apple instructs to ignore the high-order word
528 NSArray *excludedClasses = (systemVersion < 0x00001040) ?
529 [NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", nil] : // 10.3
530 [NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", @"NSATSGlyphGenerator", nil]; // 10.4
532 if ([self verbosity] > 1)
533 _WOLog(@"Examining classes for WOTest protocol compliance");
535 for (int i = 0; i < newNumClasses; i++)
539 Class aClass = classes[i];
540 NSString *className = NSStringFromClass(aClass);
544 if ([excludedClasses containsObject:className])
546 excludedClassCount++;
547 if ([self verbosity] > 1)
548 _WOLog(@"Skipping class %@ (appears in exclusion list)", className);
550 else if ([NSObject WOTest_instancesOfClass:aClass conformToProtocol:@protocol(WOTest)])
552 conformingClassCount++;
553 [testableClasses addObject:className];
554 if ([self verbosity] > 0)
555 _WOLog(@"Class %@ complies with the WOTest protocol", className);
559 nonconformingClassCount++;
560 if ([self verbosity] > 1)
561 _WOLog(@"Class %@ does not comply with the WOTest protocol", className);
564 @catch (id exception)
567 // a number of classes are known to provoke exceptions:
568 if ([self verbosity] > 1)
569 _WOLog(@"Cannot test protocol compliance for class %@ (caught exception)", className);
579 _WOLog(@"Uncaught exception...");
582 _WOLog(@"Runtime Summary:\n"
583 @"Total classes: %d\n"
584 @"Classes which conform to the WOTest protocol: %d\n"
585 @"Classes which do not conform to the protocol: %d\n"
586 @"Classes excluded from scanning: %d\n"
587 @"Classes that could not be scanned due to exceptions: %d",
589 conformingClassCount,
590 nonconformingClassCount,
594 return [testableClasses sortedArrayUsingSelector:@selector(compare:)];
597 - (NSArray *)testableClassesFrom:(NSBundle *)aBundle
599 NSArray *allClasses = [self testableClasses];
600 NSMutableArray *classNames = [NSMutableArray array];
602 if (aBundle) // only search if actually passed a non-nil bundle
604 // add only classes that match the passed bundle and conform to WOTest
605 WO_ENUMERATE(allClasses, className)
607 Class aClass = NSClassFromString(className);
608 NSBundle *classBundle = [NSBundle bundleForClass:aClass];
609 if ([classBundle isEqualTo:aBundle])
610 [classNames addObject:className];
614 // return autoreleased, immutable NSArray
615 return [NSArray arrayWithArray:classNames];
618 - (NSArray *)testableMethodsFrom:(Class)aClass
620 // catch crashes caused by passing an "id" instead of a "Class"
621 NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass] || [NSObject WOTest_isMetaClass:aClass]);
623 NSMutableArray *methodNames = [NSMutableArray array];
626 NSString *prefix = @"-"; // default prefix (instance methods)
627 if (class_isMetaClass(aClass))
628 prefix = @"+"; // special prefix (class methods)
629 else // this is not a metaclass
631 // get the metaclass; could also use object_getClass
632 Class metaClass = object_getClass(aClass);
633 NSArray *classMethods = [self testableMethodsFrom:metaClass];
634 [methodNames addObjectsFromArray:classMethods];
638 Method *methods = class_copyMethodList(aClass, &count);
641 for (unsigned int i = 0, max = count; i < max; i++)
643 SEL aSelector = method_getName(methods[i]);
644 NSString *name = NSStringFromSelector(aSelector);
645 if (name && [name hasPrefix:@"test"])
646 [methodNames addObject:[NSString stringWithFormat:@"%@%@", prefix, name]];
653 NSString *error = [NSString stringWithFormat:@"exception caught trying to identify testable methods in class %@",
654 NSStringFromClass(aClass)];
655 [self writeError:error];
658 return [methodNames sortedArrayUsingSelector:@selector(compare:)];
661 - (void)printTestResultsSummary;
663 [self checkStartDate]; // just in case no tests were run, make sure that startDate is non-nil
664 double successRate = 0.0;
665 double failureRate = 0.0;
666 if (testsRun > 0) // watch out for divide-by-zero if no tests run
668 successRate = ((double)(testsPassed + testsFailedExpected) / (double)testsRun) * 100.0;
669 failureRate = ((double)(testsFailed + testsPassedUnexpected) / (double)testsRun) * 100.0;
671 _WOLog(@"Run summary:\n"
673 @"Tests passed: %d + %d expected failures (%.2f%% success rate)\n"
674 @"Tests failed: %d + %d unexpected passes (%.2f%% failure rate)\n"
675 @"Uncaught exceptions: %d\n"
676 @"Low-level exceptions (crashers): %d + %d expected\n"
677 @"Total run time: %.2f seconds\n",
679 testsPassed, testsFailedExpected, successRate,
680 testsFailed, testsPassedUnexpected, failureRate,
682 lowLevelExceptionsUnexpected, lowLevelExceptionsExpected,
683 -[[self startDate] timeIntervalSinceNow]);
686 _WOLog(@"warning: no tests were run\n");
688 // TODO: make Growl notifications optional
689 // TODO: include information about project being tested in Growl notification title
690 // TODO: add options for showing coalesced growl notifications showing individual test failures (with path and line info)
691 // TODO: make clicking on notification bring Xcode to the front, or open the file with the last failure in it etc
692 NSString *status = [NSString stringWithFormat:@"%d tests passed, %d tests failed",
693 testsPassed + testsFailedExpected, testsFailed + testsPassedUnexpected];
695 if ([self testsWereSuccessful])
696 [self growlNotifyTitle:@"WOTest run successful" message:status isWarning:NO sticky:NO];
699 _WOLog(@"error: testing did not complete without errors\n");
700 [self growlNotifyTitle:@"WOTest run failed" message:status isWarning:YES sticky:YES];
705 [self setStartDate:nil];
708 - (BOOL)testsWereSuccessful
710 return ((testsFailed + testsPassedUnexpected + uncaughtExceptions + lowLevelExceptionsUnexpected) == 0);
714 #pragma mark Low-level exception handling
716 - (void)installLowLevelExceptionHandler
718 if (!lowLevelExceptionHandlerInstalled)
720 WOOldLowLevelExceptionHandler = InstallExceptionHandler(NewExceptionHandlerUPP(WOLowLevelExceptionHandler));
721 lowLevelExceptionHandlerInstalled = YES;
725 - (void)removeLowLevelExceptionHandler
727 if (lowLevelExceptionHandlerInstalled)
729 DisposeExceptionHandlerUPP(InstallExceptionHandler(WOOldLowLevelExceptionHandler));
730 lowLevelExceptionHandlerInstalled = NO;
735 #pragma mark Growl support
737 - (void)growlNotifyTitle:(NSString *)title message:(NSString *)message isWarning:(BOOL)isWarning sticky:(BOOL)sticky
739 NSParameterAssert(title != nil);
740 NSParameterAssert(message != nil);
742 // clean up enviroment a bit (hides possible warnings caused if these set for WOTestRunner)
743 NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary:[[NSProcessInfo processInfo] environment]];
744 [environment removeObjectForKey:@"DYLD_INSERT_LIBRARIES"];
745 [environment removeObjectForKey:@"WOTestBundleInjector"];
747 NSTask *task = [[[NSTask alloc] init] autorelease];
748 [task setLaunchPath:@"/usr/bin/env"]; // use env so as to pick up PATH, if set
749 [task setEnvironment:environment];
750 NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"growlnotify",
751 @"--name", @"com.wincent.WOTest",
752 @"--appIcon", @"Xcode",
753 @"--priority", (isWarning ? @"2" : @"0"),
754 @"--message", message,
756 if (sticky) [arguments insertObject:@"--sticky" atIndex:0];
757 [task setArguments:arguments];
761 [task waitUntilExit];
765 // ignore: growlnotify may not be installed or the PATH environment variable may not be correctly set
770 #pragma mark Logging methods
772 - (NSString *)trimmedPath:(char *)path
774 NSParameterAssert(path != NULL);
775 NSString *pathString = [NSString stringWithUTF8String:path];
777 unsigned trim = [self trimInitialPathComponents];
778 if (trim == 0) return pathString;
779 if (![pathString isAbsolutePath]) return pathString; // only trim absolute paths
780 NSArray *components = [pathString pathComponents]; // note: Cocoa returns "/" here as an additional first component
781 NSAssert(components != nil, @"components != nil");
782 unsigned count = [components count];
783 if (count < trim + 2) return pathString; // only trim if there will be at least one component left over
784 return [NSString pathWithComponents:[components subarrayWithRange:NSMakeRange(trim + 1, count - trim - 1)]];
787 - (void)writePassed:(BOOL)passed
790 message:(NSString *)message, ...
794 va_start(args, message);
795 NSString *string = [NSString WOTest_stringWithFormat:message arguments:args];
797 if ([self expectFailures]) // invert sense of tests (ie. failure is good)
799 if (passed) // passed: bad
801 [self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Passed (unexpected pass): %@", string]];
802 testsPassedUnexpected++;
806 [self writeStatusInFile:path atLine:line message:[NSString stringWithFormat:@"Failed (expected failure): %@", string]];
807 testsFailedExpected++;
810 else // normal handling (ie. passing is good, failing is bad)
812 if (passed) // passed: good
814 [self writeStatusInFile:path atLine:line message:[NSString stringWithFormat:@"Passed: %@", string]];
819 [self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Failed: %@", string]];
825 - (void)cacheFile:(char *)path line:(int)line
827 [self setLastReportedFile:[self trimmedPath:path]];
828 lastReportedLine = line;
831 - (void)writeLastKnownLocation
833 NSString *path = [self lastReportedFile];
835 _WOLog(@"%@:%d: last known location was %@:%d", path, lastReportedLine, path, lastReportedLine);
838 - (void)writeErrorInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
841 va_start(args, message);
842 NSString *error = [NSString WOTest_stringWithFormat:message arguments:args];
843 _WOLog(@"%@:%d: error: %@", [self trimmedPath:path], line, error);
844 [self cacheFile:path line:line];
848 - (void)writeWarningInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
851 va_start(args, message);
852 NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
853 _WOLog(@"%@:%d: warning: %@", [self trimmedPath:path], line, warning);
854 [self cacheFile:path line:line];
858 - (void)writeUncaughtException:(NSString *)info inFile:(char *)path atLine:(int)line
860 _WOLog(@"%@:%d: error: uncaught exception during test execution: %@", [self trimmedPath:path], line, info);
861 uncaughtExceptions++;
864 - (void)writeStatusInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
867 va_start(args, message);
868 NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
869 _WOLog(@"%@:%d %@", [self trimmedPath:path], line, status); // omit colin after line number or Xcode will show this as an error
870 [self cacheFile:path line:line];
874 - (void)writeStatus:(NSString *)message, ...
877 va_start(args, message);
878 NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
879 _WOLog(@"%@", status);
883 - (void)writeWarning:(NSString *)message, ...
886 va_start(args, message);
887 NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
888 _WOLog(@"warning: %@", warning); // older versions of Xcode required initial colons "::" to show this as a warning
892 - (void)writeError:(NSString *)message, ...
895 va_start(args, message);
896 NSString *error = [NSString WOTest_stringWithFormat:message arguments:args];
897 _WOLog(@"error: %@", error); // older versions of Xcode required initial colons "::" to show this as an error
902 #pragma mark Empty (do-nothing) test methods
904 - (void)passTestInFile:(char *)path atLine:(int)line
906 [self writePassed:YES inFile:path atLine:line message:@"(always passes)"];
909 - (void)failTestInFile:(char *)path atLine:(int)line
911 [self writePassed:NO inFile:path atLine:line message:@"(always fails)"];
915 #pragma mark Boolean test methods
917 - (void)testTrue:(BOOL)expr inFile:(char *)path atLine:(int)line
919 [self writePassed:expr inFile:path atLine:line message:@"expected YES, got %@", (expr ? @"YES" : @"NO")];
922 - (void)testFalse:(BOOL)expr inFile:(char *)path atLine:(int)line
924 [self writePassed:!expr inFile:path atLine:line message:@"expected NO, got %@", (expr ? @"YES" : @"NO")];
928 #pragma mark NSValue-based tests
930 - (void)testValue:(NSValue *)actual isEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line
932 NSParameterAssert(actual);
933 NSParameterAssert(expected);
936 // NSValue category will throw an exception for invalid input(s)
938 equal = [actual WOTest_testIsEqualToValue:expected];
941 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
942 uncaughtExceptions++;
944 BOOL expectedTruncated, actualTruncated;
945 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
946 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
947 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
950 - (void)testValue:(NSValue *)actual isNotEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line
952 NSParameterAssert(actual);
953 NSParameterAssert(expected);
956 // NSValue category will throw an exception for invalid input(s)
958 equal = [actual WOTest_testIsEqualToValue:expected];
961 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
962 uncaughtExceptions++;
964 BOOL expectedTruncated, actualTruncated;
965 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
966 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
967 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
970 - (void)testValue:(NSValue *)actual greaterThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
972 NSParameterAssert(actual);
973 NSParameterAssert(expected);
974 BOOL greaterThan = NO;
976 // NSValue category will throw an exception for invalid input(s)
978 greaterThan = [actual WOTest_testIsGreaterThanValue:expected];
981 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
982 uncaughtExceptions++;
984 BOOL expectedTruncated, actualTruncated;
985 [self writePassed:greaterThan inFile:path atLine:line message:@"expected > %@, got %@", WO_DESC(expected), WO_DESC(actual)];
986 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
987 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
990 - (void)testValue:(NSValue *)actual notGreaterThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
992 NSParameterAssert(actual);
993 NSParameterAssert(expected);
994 BOOL notGreaterThan = NO;
996 // NSValue category will throw an exception for invalid input(s)
998 notGreaterThan = [actual WOTest_testIsNotGreaterThanValue:expected];
1001 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1002 uncaughtExceptions++;
1004 BOOL expectedTruncated, actualTruncated;
1005 [self writePassed:notGreaterThan inFile:path atLine:line message:@"expected <= %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1006 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1007 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1010 - (void)testValue:(NSValue *)actual lessThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1012 NSParameterAssert(actual);
1013 NSParameterAssert(expected);
1016 // NSValue category will throw an exception for invalid input(s)
1018 lessThan = [actual WOTest_testIsLessThanValue:expected];
1021 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1022 uncaughtExceptions++;
1024 BOOL expectedTruncated, actualTruncated;
1025 [self writePassed:lessThan inFile:path atLine:line message:@"expected < %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1026 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1027 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1030 - (void)testValue:(NSValue *)actual notLessThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1032 NSParameterAssert(actual);
1033 NSParameterAssert(expected);
1034 BOOL notLessThan = NO;
1036 // NSValue category will throw an exception for invalid input(s)
1038 notLessThan = [actual WOTest_testIsNotLessThanValue:expected];
1041 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1042 uncaughtExceptions++;
1044 BOOL expectedTruncated, actualTruncated;
1045 [self writePassed:notLessThan inFile:path atLine:line message:@"expected >= %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1046 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1047 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1051 #pragma mark Pointer to void test methods
1053 - (void)testNil:(void *)pointer inFile:(char *)path atLine:(int)line
1055 BOOL result = (pointer ? NO : YES);
1056 [self writePassed:result inFile:path atLine:line message:@"expected nil, got %@",
1057 (result ? @"nil" : [NSString stringWithFormat:@"%x", pointer])];
1060 - (void)testNotNil:(void *)pointer inFile:(char *)path atLine:(int)line
1062 BOOL result = (pointer ? YES : NO);
1063 [self writePassed:result inFile:path atLine:line message:@"expected (not) nil, got %@",
1064 (result ? [NSString stringWithFormat:@"%x", pointer] : @"nil")];
1067 - (void)testPointer:(void *)actual isEqualTo:(void *)expected inFile:(char *)path atLine:(int)line
1069 BOOL result = (actual == expected);
1070 [self writePassed:result inFile:path atLine:line message:@"expected %x, got %x", expected, actual];
1073 - (void)testPointer:(void *)actual isNotEqualTo:(void *)expected inFile:(char *)path atLine:(int)line
1075 BOOL result = (actual != expected);
1076 [self writePassed:result inFile:path atLine:line message:@"expected (not) %x, got %x", expected, actual];
1080 #pragma mark int test methods
1082 - (void)testIsInt:(char *)type inFile:(char *)path atLine:(int)line
1084 BOOL result = (strcmp(type, "i") == 0);
1085 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"i\", got \"%s\"", type]];
1088 - (void)testIsNotInt:(char *)type inFile:(char *)path atLine:(int)line
1090 BOOL result = (strcmp(type, "i") != 0);
1091 [self writePassed:result
1094 message:[NSString stringWithFormat:@"expected type (not) \"i\", got \"%s\"", type]];
1097 - (void)testIntPositive:(int)aInt inFile:(char *)path atLine:(int)line
1099 [self testInt:aInt greaterThan:(int)0 inFile:path atLine:line];
1102 - (void)testIntNegative:(int)aInt inFile:(char *)path atLine:(int)line
1104 [self testInt:aInt lessThan:(int)0 inFile:path atLine:line];
1107 - (void)testIntZero:(int)aInt inFile:(char *)path atLine:(int)line
1109 [self testInt:aInt isEqualTo:(int)0 inFile:path atLine:line];
1112 - (void)testIntNotZero:(int)aInt inFile:(char *)path atLine:(int)line
1114 [self testInt:aInt isNotEqualTo:(int)0 inFile:path atLine:line];
1117 - (void)testInt:(int)actual isEqualTo:(int)expected inFile:(char *)path atLine:(int)line
1119 BOOL result = (actual == expected);
1120 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat:@"expected %d, got %d", expected, actual]];
1123 - (void)testInt:(int)actual isNotEqualTo:(int)expected inFile:(char *)path atLine:(int)line
1125 BOOL result = (actual != expected);
1126 [self writePassed:result
1129 message:[NSString stringWithFormat:@"expected (not) %d, got %d", expected, actual]];
1132 - (void)testInt:(int)actual greaterThan:(int)expected inFile:(char *)path atLine:(int)line
1134 BOOL result = (actual > expected);
1135 [self writePassed:result
1138 message:[NSString stringWithFormat:@"expected > %d, got %d", expected, actual]];
1141 - (void)testInt:(int)actual notGreaterThan:(int)expected inFile:(char *)path atLine:(int)line
1143 BOOL result = (actual <= expected);
1144 [self writePassed:result
1147 message:[NSString stringWithFormat:@"expected <= %d, got %d", expected, actual]];
1150 - (void)testInt:(int)actual lessThan:(int)expected inFile:(char *)path atLine:(int)line
1152 BOOL result = (actual < expected);
1153 [self writePassed:result
1156 message:[NSString stringWithFormat:@"expected < %d, got %d", expected, actual]];
1159 - (void)testInt:(int)actual notLessThan:(int)expected inFile:(char *)path atLine:(int)line
1161 BOOL result = (actual >= expected);
1162 [self writePassed:result
1165 message:[NSString stringWithFormat:@"expected >= %d, got %d", expected, actual]];
1169 #pragma mark unsigned test methods
1171 - (void)testIsUnsigned:(char *)type inFile:(char *)path atLine:(int)line
1173 BOOL result = (strcmp(type, "I") == 0);
1174 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"I\", got \"%s\"", type]];
1177 - (void)testIsNotUnsigned:(char *)type inFile:(char *)path atLine:(int)line
1179 BOOL result = (strcmp(type, "I") != 0);
1180 [self writePassed:result
1183 message:[NSString stringWithFormat:@"expected type (not) \"I\", got \"%s\"", type]];
1186 - (void)testUnsignedZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
1188 return [self testUnsigned:aUnsigned isEqualTo:(unsigned)0 inFile:path atLine:line];
1191 - (void)testUnsignedNotZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
1193 return [self testUnsigned:aUnsigned isNotEqualTo:(unsigned)0 inFile:path atLine:line];
1196 - (void)testUnsigned:(unsigned)actual isEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
1198 BOOL result = (actual == expected);
1199 [self writePassed:result
1202 message:[NSString stringWithFormat:@"expected %u, got %u", expected, actual]];
1205 - (void)testUnsigned:(unsigned)actual isNotEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
1207 BOOL result = (actual != expected);
1208 [self writePassed:result
1211 message:[NSString stringWithFormat:@"expected (not) %u, got %u", expected, actual]];
1214 - (void)testUnsigned:(unsigned)actual greaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1216 BOOL result = (actual > expected);
1217 [self writePassed:result
1220 message:[NSString stringWithFormat:@"expected > %u, got %u", expected, actual]];
1223 - (void)testUnsigned:(unsigned)actual notGreaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1225 BOOL result = (actual <= expected);
1226 [self writePassed:result
1229 message:[NSString stringWithFormat:@"expected <= %u, got %u", expected, actual]];
1232 - (void)testUnsigned:(unsigned)actual lessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1234 BOOL result = (actual < expected);
1235 [self writePassed:result
1238 message:[NSString stringWithFormat:@"expected < %u, got %u", expected, actual]];
1241 - (void)testUnsigned:(unsigned)actual notLessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1243 BOOL result = (actual >= expected);
1244 [self writePassed:result
1247 message:[NSString stringWithFormat:@"expected >= %u, got %u", expected, actual]];
1251 #pragma mark float test methods without error margins
1253 - (void)testIsFloat:(char *)type inFile:(char *)path atLine:(int)line
1255 BOOL result = (strcmp(type, "f") == 0);
1256 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"f\", got \"%s\"", type]];
1259 - (void)testIsNotFloat:(char *)type inFile:(char *)path atLine:(int)line
1261 BOOL result = (strcmp(type, "f") != 0);
1262 [self writePassed:result
1265 message:[NSString stringWithFormat:@"expected type (not) \"f\", got \"%s\"", type]];
1268 - (void)testFloatPositive:(float)aFloat inFile:(char *)path atLine:(int)line
1270 return [self testFloat:aFloat greaterThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1273 - (void)testFloatNegative:(float)aFloat inFile:(char *)path atLine:(int)line
1275 return [self testFloat:aFloat lessThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1278 - (void)testFloatZero:(float)aFloat inFile:(char *)path atLine:(int)line
1280 return [self testFloat:aFloat isEqualTo:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1283 - (void)testFloatNotZero:(float)aFloat inFile:(char *)path atLine:(int)line
1285 return [self testFloat:aFloat isNotEqualTo:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1288 - (void)testFloat:(float)actual isEqualTo:(float)expected inFile:(char *)path atLine:(int)line
1290 return [self testFloat:actual isEqualTo:expected withinError:(float)0.0 inFile:path atLine:line];
1293 - (void)testFloat:(float)actual isNotEqualTo:(float)expected inFile:(char *)path atLine:(int)line
1295 return [self testFloat:actual isNotEqualTo:expected withinError:(float)0.0 inFile:path atLine:line];
1298 - (void)testFloat:(float)actual greaterThan:(float)expected inFile:(char *)path atLine:(int)line
1300 return [self testFloat:actual greaterThan:expected withinError:(float)0.0 inFile:path atLine:line];
1303 - (void)testFloat:(float)actual notGreaterThan:(float)expected inFile:(char *)path atLine:(int)line
1305 return [self testFloat:actual notGreaterThan:expected withinError:(float)0.0 inFile:path atLine:line];
1308 - (void)testFloat:(float)actual lessThan:(float)expected inFile:(char *)path atLine:(int)line
1310 return [self testFloat:actual lessThan:expected withinError:(float)0.0 inFile:path atLine:line];
1313 - (void)testFloat:(float)actual notLessThan:(float)expected inFile:(char *)path atLine:(int)line
1315 return [self testFloat:actual notLessThan:expected withinError:(float)0.0 inFile:path atLine:line];
1319 #pragma mark float test methods with error margins
1321 - (void)testFloatPositive:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1323 return [self testFloat:aFloat greaterThan:(float)0.0 withinError:error inFile:path atLine:line];
1326 - (void)testFloatNegative:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1328 return [self testFloat:aFloat lessThan:(float)0.0 withinError:error inFile:path atLine:line];
1331 - (void)testFloatZero:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1333 return [self testFloat:aFloat isEqualTo:(float)0.0 withinError:error inFile:path atLine:line];
1336 - (void)testFloatNotZero:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1338 return [self testFloat:aFloat isNotEqualTo:(float)0.0 withinError:error inFile:path atLine:line];
1341 - (void)testFloat:(float)actual isEqualTo:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1343 BOOL result = (fabsf(actual - expected) <= error);
1344 [self writePassed:result
1348 [NSString stringWithFormat:@"expected %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1351 - (void)testFloat:(float)actual isNotEqualTo:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1353 BOOL result = (fabsf(actual - expected) > -error);
1354 [self writePassed:result
1358 [NSString stringWithFormat:@"expected (not) %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1361 - (void)testFloat:(float)actual greaterThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1363 BOOL result = ((actual - expected) > -error);
1364 [self writePassed:result
1368 [NSString stringWithFormat:@"expected > %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1371 - (void)testFloat:(float)actual notGreaterThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1373 BOOL result = ((actual - expected) <= error);
1374 [self writePassed:result
1378 [NSString stringWithFormat:@"expected <= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1381 - (void)testFloat:(float)actual lessThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1383 BOOL result = ((actual - expected) < -error);
1384 [self writePassed:result
1388 [NSString stringWithFormat:@"expected < %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1391 - (void)testFloat:(float)actual notLessThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1393 BOOL result = ((actual - expected) >= error);
1394 [self writePassed:result
1398 [NSString stringWithFormat:@"expected >= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1402 #pragma mark double test methods without error margins
1404 - (void)testIsDouble:(char *)type inFile:(char *)path atLine:(int)line
1406 BOOL result = (strcmp(type, "d") == 0);
1407 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"d\", got \"%s\"", type]];
1410 - (void)testIsNotDouble:(char *)type inFile:(char *)path atLine:(int)line
1412 BOOL result = (strcmp(type, "d") != 0);
1413 [self writePassed:result
1416 message:[NSString stringWithFormat:@"expected type (not) \"d\", got \"%s\"", type]];
1419 - (void)testDoublePositive:(double)aDouble inFile:(char *)path atLine:(int)line
1421 return [self testDouble:aDouble greaterThan:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1424 - (void)testDoubleNegative:(double)aDouble inFile:(char *)path atLine:(int)line
1426 return [self testDouble:aDouble lessThan:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1429 - (void)testDoubleZero:(double)aDouble inFile:(char *)path atLine:(int)line
1431 return [self testDouble:aDouble isEqualTo:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1434 - (void)testDoubleNotZero:(double)aDouble inFile:(char *)path atLine:(int)line
1436 return [self testDouble:aDouble isNotEqualTo:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1439 - (void)testDouble:(double)actual isEqualTo:(double)expected inFile:(char *)path atLine:(int)line
1441 return [self testDouble:actual isEqualTo:expected withinError:(double)0.0 inFile:path atLine:line];
1444 - (void)testDouble:(double)actual isNotEqualTo:(double)expected inFile:(char *)path atLine:(int)line
1446 return [self testDouble:actual isNotEqualTo:expected withinError:(double)0.0 inFile:path atLine:line];
1449 - (void)testDouble:(double)actual greaterThan:(double)expected inFile:(char *)path atLine:(int)line
1451 return [self testDouble:actual greaterThan:expected withinError:(double)0.0 inFile:path atLine:line];
1454 - (void)testDouble:(double)actual notGreaterThan:(double)expected inFile:(char *)path atLine:(int)line
1456 return [self testDouble:actual notGreaterThan:expected withinError:(double)0.0 inFile:path atLine:line];
1459 - (void)testDouble:(double)actual lessThan:(double)expected inFile:(char *)path atLine:(int)line
1461 return [self testDouble:actual lessThan:expected withinError:(double)0.0 inFile:path atLine:line];
1464 - (void)testDouble:(double)actual notLessThan:(double)expected inFile:(char *)path atLine:(int)line
1466 return [self testDouble:actual notLessThan:expected withinError:(double)0.0 inFile:path atLine:line];
1470 #pragma mark double test methods with error margins
1472 - (void)testDoublePositive:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1474 return [self testDouble:aDouble greaterThan:(double)0.0 withinError:error inFile:path atLine:line];
1477 - (void)testDoubleNegative:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1479 return [self testDouble:aDouble lessThan:(double)0.0 withinError:error inFile:path atLine:line];
1482 - (void)testDoubleZero:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1484 return [self testDouble:aDouble isEqualTo:(double)0.0 withinError:error inFile:path atLine:line];
1487 - (void)testDoubleNotZero:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1489 return [self testDouble:aDouble isNotEqualTo:(double)0.0 withinError:error inFile:path atLine:line];
1492 - (void)testDouble:(double)actual isEqualTo:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1494 BOOL result = (fabs(actual - expected) <= error);
1495 [self writePassed:result
1499 [NSString stringWithFormat:@"expected %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1502 - (void)testDouble:(double)actual isNotEqualTo:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1504 BOOL result = (fabs(actual - expected) > -error);
1505 [self writePassed:result
1509 [NSString stringWithFormat:@"expected (not) %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1512 - (void)testDouble:(double)actual greaterThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1514 BOOL result = ((actual - expected) > -error);
1515 [self writePassed:result
1519 [NSString stringWithFormat:@"expected > %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1522 - (void)testDouble:(double)actual notGreaterThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1524 BOOL result = ((actual - expected) <= error);
1525 [self writePassed:result
1529 [NSString stringWithFormat:@"expected <= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1532 - (void)testDouble:(double)actual lessThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1534 BOOL result = ((actual - expected) < -error);
1535 [self writePassed:result
1539 [NSString stringWithFormat:@"expected < %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1542 - (void)testDouble:(double)actual notLessThan:(double)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1544 BOOL result = ((actual - expected) >= error);
1545 [self writePassed:result
1549 [NSString stringWithFormat:@"expected >= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1553 #pragma mark object test methods
1555 - (void)testObject:(id)actual isEqualTo:(id)expected inFile:(char *)path atLine:(int)line
1558 if (!actual && !expected) equal = YES; // equal (both nil)
1559 else if (actual) equal = [actual isEqual:expected];
1560 BOOL expectedTruncated, actualTruncated;
1561 [self writePassed:equal inFile:path atLine:line message:@"expected \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1562 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1563 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1566 - (void)testObject:(id)actual isNotEqualTo:(id)expected inFile:(char *)path atLine:(int)line
1569 if (!actual && !expected) equal = YES; // equal (both nil)
1570 else if (actual) equal = [actual isEqual:expected];
1571 BOOL expectedTruncated, actualTruncated;
1572 [self writePassed:(!equal)
1575 message:@"expected (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1576 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1577 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1581 #pragma mark NSString test methods
1583 - (void)testString:(NSString *)actual isEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line
1585 if (actual && ![actual isKindOfClass:[NSString class]])
1586 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1587 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1590 if (expected && ![expected isKindOfClass:[NSString class]])
1591 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1592 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1596 if (!actual && !expected) equal = YES; // equal (both nil)
1597 else if (actual) equal = [actual isEqualToString:expected];
1598 BOOL expectedTruncated, actualTruncated;
1599 [self writePassed:equal inFile:path atLine:line message:@"expected \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1600 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1601 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1604 - (void)testString:(NSString *)actual isNotEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line
1606 if (actual && ![actual isKindOfClass:[NSString class]])
1607 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1608 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1611 if (expected && ![expected isKindOfClass:[NSString class]])
1612 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1613 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1617 if (!actual && !expected) equal = YES; // equal (both nil)
1618 else if (actual) equal = [actual isEqualToString:expected];
1619 BOOL expectedTruncated, actualTruncated;
1620 [self writePassed:equal
1623 message:@"expected (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1624 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1625 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1628 - (void)testString:(NSString *)actual hasPrefix:(NSString *)expected inFile:(char *)path atLine:(int)line
1631 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1632 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1635 if (actual && ![actual isKindOfClass:[NSString class]])
1636 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1637 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1640 if (![expected isKindOfClass:[NSString class]])
1641 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1642 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1645 BOOL result = actual ? NO : [actual hasPrefix:expected];
1646 BOOL expectedTruncated, actualTruncated;
1647 [self writePassed:result
1650 message:@"expected prefix \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1651 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1652 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1655 - (void)testString:(NSString *)actual doesNotHavePrefix:(NSString *)expected inFile:(char *)path atLine:(int)line
1658 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1659 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1662 if (actual && ![actual isKindOfClass:[NSString class]])
1663 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1664 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1667 if (![expected isKindOfClass:[NSString class]])
1668 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1669 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1672 BOOL result = actual ? (![actual hasPrefix:expected]) : NO;
1673 BOOL expectedTruncated, actualTruncated;
1674 [self writePassed:result
1677 message:@"expected prefix (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1678 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1679 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1682 - (void)testString:(NSString *)actual hasSuffix:(NSString *)expected inFile:(char *)path atLine:(int)line
1685 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1686 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1689 if (actual && ![actual isKindOfClass:[NSString class]])
1690 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1691 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1694 if (![expected isKindOfClass:[NSString class]])
1695 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1696 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1699 BOOL result = actual ? NO : [actual hasSuffix:expected];
1700 BOOL expectedTruncated, actualTruncated;
1701 [self writePassed:result
1704 message:@"expected suffix \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1705 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1706 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1709 - (void)testString:(NSString *)actual doesNotHaveSuffix:(NSString *)expected inFile:(char *)path atLine:(int)line
1712 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1713 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1716 if (actual && ![actual isKindOfClass:[NSString class]])
1717 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1718 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1721 if (![expected isKindOfClass:[NSString class]])
1722 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1723 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1726 BOOL result = actual ? (![actual hasSuffix:expected]) : NO;
1727 BOOL expectedTruncated, actualTruncated;
1728 [self writePassed:result
1731 message:@"expected suffix (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1732 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1733 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1736 - (void)testString:(NSString *)actual contains:(NSString *)expected inFile:(char *)path atLine:(int)line
1739 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1740 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1743 if (actual && ![actual isKindOfClass:[NSString class]])
1744 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1745 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1748 if (![expected isKindOfClass:[NSString class]])
1749 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1750 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1753 BOOL result = actual ? NO : (!NSEqualRanges([actual rangeOfString:expected], NSMakeRange(NSNotFound, 0)));
1754 BOOL expectedTruncated, actualTruncated;
1755 [self writePassed:result
1758 message:@"expected contains \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1759 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1760 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1763 - (void)testString:(NSString *)actual doesNotContain:(NSString *)expected inFile:(char *)path atLine:(int)line
1766 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1767 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1770 if (actual && ![actual isKindOfClass:[NSString class]])
1771 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1772 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1775 if (![expected isKindOfClass:[NSString class]])
1776 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1777 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1780 BOOL result = actual ? YES : (NSEqualRanges([actual rangeOfString:expected], NSMakeRange(NSNotFound, 0)));
1781 BOOL expectedTruncated, actualTruncated;
1782 [self writePassed:result
1785 message:@"expected contains (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1786 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1787 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1791 #pragma mark NSArray test methods
1793 - (void)testArray:(NSArray *)actual isEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line
1795 if (actual && ![actual isKindOfClass:[NSArray class]])
1796 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1797 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(actual)
1800 if (expected && ![expected isKindOfClass:[NSArray class]])
1801 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1802 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(expected)
1806 if (!actual && !expected) equal = YES; // equal (both nil)
1807 else if (actual) equal = [actual isEqualToArray:expected];
1808 BOOL expectedTruncated, actualTruncated;
1809 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1810 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1811 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1814 - (void)testArray:(NSArray *)actual isNotEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line
1816 if (actual && ![actual isKindOfClass:[NSArray class]])
1817 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1818 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(actual)
1821 if (expected && ![expected isKindOfClass:[NSArray class]])
1822 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1823 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(expected)
1827 if (!actual && !expected) equal = YES; // equal (both nil)
1828 else if (actual) equal = [actual isEqualToArray:expected];
1829 BOOL expectedTruncated, actualTruncated;
1830 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1831 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1832 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1836 #pragma mark NSDictionary test methods
1838 - (void)testDictionary:(NSDictionary *)actual isEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line
1840 if (actual && ![actual isKindOfClass:[NSArray class]])
1841 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1842 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(actual)
1845 if (expected && ![expected isKindOfClass:[NSArray class]])
1846 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1847 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(expected)
1851 if (!actual && !expected) equal = YES; // equal (both nil)
1852 else if (actual) equal = [actual isEqualToDictionary:expected];
1853 BOOL expectedTruncated, actualTruncated;
1854 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1855 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1856 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1859 - (void)testDictionary:(NSDictionary *)actual isNotEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line
1861 if (actual && ![actual isKindOfClass:[NSDictionary class]])
1862 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1863 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(actual)
1866 if (expected && ![expected isKindOfClass:[NSDictionary class]])
1867 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1868 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(expected)
1872 if (!actual && !expected) equal = YES; // equal (both nil)
1873 else if (actual) equal = [actual isEqualToDictionary:expected];
1874 BOOL expectedTruncated, actualTruncated;
1875 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1876 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1877 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1881 #pragma mark Exception test methods
1883 - (void)testThrowsException:(id)exception inFile:(char *)path atLine:(int)line
1885 BOOL result = (exception ? YES : NO);
1886 [self writePassed:result
1889 message:[NSString stringWithFormat:@"expected exception, got %@", [NSException WOTest_nameForException:exception]]];
1892 - (void)testDoesNotThrowException:(id)exception inFile:(char *)path atLine:(int)line
1894 BOOL result = (exception ? NO : YES);
1895 [self writePassed:result
1899 [NSString stringWithFormat:@"expected no exception, got %@", [NSException WOTest_nameForException:exception]]];
1902 - (void)testThrowsException:(id)exception named:(NSString *)name inFile:(char *)path atLine:(int)line
1904 if (name && ![name isKindOfClass:[NSString class]])
1906 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1907 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(name)
1913 NSString *actualName = [NSException WOTest_nameForException:exception];
1915 if (exception && [actualName isEqualToString:name]) result = YES;
1917 [self writePassed:result
1920 message:[NSString stringWithFormat:@"expected %@, got %@", name, actualName]];
1923 - (void)testDoesNotThrowException:(id)exception named:(NSString *)name inFile:(char *)path atLine:(int)line
1925 if (name && ![name isKindOfClass:[NSString class]])
1927 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1928 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(name)
1934 NSString *actualName = [NSException WOTest_nameForException:exception];
1936 if (exception && [actualName isEqualToString:name]) result = NO;
1938 [self writePassed:result inFile:path atLine:line message:@"expected (not) %@, got %@", name, actualName];
1942 #pragma mark Random value generator methods
1944 // TODO: move these into a category, these are more "test helpers" rather than actual "testing methods"
1948 return (int)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1953 return (int)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1958 return (int)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1968 return (int)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1971 - (int)aBigPositiveInt
1973 return (int)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1976 - (int)aBigNegativeInt
1978 return (int)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1983 return (int)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1986 - (int)aSmallPositiveInt
1988 return (int)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1991 - (int)aSmallNegativeInt
1993 return (int)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1996 - (unsigned)anUnsigned
1998 return (unsigned)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2001 - (unsigned)aZeroUnsigned
2006 - (unsigned)aBigUnsigned
2008 return (unsigned)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2011 - (unsigned)aSmallUnsigned
2013 return (unsigned)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2018 return (float)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2021 - (float)aPositiveFloat
2023 return (float)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2026 - (float)aNegativeFloat
2028 return (float)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2038 return (float)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2041 - (float)aBigPositiveFloat
2043 return (float)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2046 - (float)aBigNegativeFloat
2048 return (float)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2051 - (float)aSmallFloat
2053 return (float)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2056 - (float)aSmallPositiveFloat
2058 return (float)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2061 - (float)aSmallNegativeFloat
2063 return (float)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2068 return (double)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2071 - (double)aPositiveDouble
2073 return (double)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2076 - (double)aNegativeDouble
2078 return (double)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2081 - (double)aZeroDouble
2086 - (double)aBigDouble
2088 return (double)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2091 - (double)aBigPositiveDouble
2093 return (double)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2096 - (double)aBigNegativeDouble
2098 return (double)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2101 - (double)aSmallDouble
2103 return (double)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2106 - (double)aSmallPositiveDouble
2108 return (double)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2111 - (double)aSmallNegativeDouble
2113 return (double)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2117 #pragma mark Accessors
2119 - (NSDate *)startDate
2121 return [[startDate retain] autorelease];
2124 - (void)setStartDate:(NSDate *)aStartDate
2126 [aStartDate retain];
2127 [startDate release];
2128 startDate = aStartDate;
2131 - (unsigned)classesWithTests
2133 return classesWithTests;
2136 - (unsigned)classesWithoutTests
2138 return classesWithoutTests;
2141 - (unsigned)methodsWithTests
2143 return methodsWithTests;
2146 - (unsigned)testsRun
2151 - (unsigned)testsPassed
2156 - (unsigned)testsFailed
2161 - (unsigned)uncaughtExceptions
2163 return uncaughtExceptions;
2166 - (unsigned)testsFailedExpected
2168 return testsFailedExpected;
2171 - (unsigned)testsPassedUnexpected
2173 return testsPassedUnexpected;
2176 - (BOOL)expectFailures
2178 return expectFailures;
2181 - (void)setExpectFailures:(BOOL)aValue
2183 expectFailures = aValue;
2186 - (unsigned)lowLevelExceptionsExpected
2188 return lowLevelExceptionsExpected;
2191 - (unsigned)lowLevelExceptionsUnexpected
2193 return lowLevelExceptionsUnexpected;
2196 - (BOOL)expectLowLevelExceptions
2198 return expectLowLevelExceptions;
2201 - (void)setExpectLowLevelExceptions:(BOOL)aValue
2203 expectLowLevelExceptions = aValue;
2206 - (BOOL)handlesLowLevelExceptions
2208 return handlesLowLevelExceptions;
2211 - (void)setHandlesLowLevelExceptions:(BOOL)aValue
2213 handlesLowLevelExceptions = aValue;
2216 - (unsigned)verbosity
2221 - (void)setVerbosity:(unsigned)aVerbosity
2223 verbosity = aVerbosity;
2226 - (unsigned)trimInitialPathComponents
2228 return trimInitialPathComponents;
2231 - (void)setTrimInitialPathComponents:(unsigned)aTrimInitialPathComponents
2233 trimInitialPathComponents = aTrimInitialPathComponents;
2236 - (NSString *)lastReportedFile
2238 return [[lastReportedFile retain] autorelease];
2241 - (void)setLastReportedFile:(NSString *)aLastReportedFile
2243 if (lastReportedFile != aLastReportedFile)
2245 [aLastReportedFile retain];
2246 [lastReportedFile release];
2247 lastReportedFile = aLastReportedFile;
2251 - (BOOL)warnsAboutSignComparisons
2253 return warnsAboutSignComparisons;
2256 - (void)setWarnsAboutSignComparisons:(BOOL)aWarnsAboutSignComparisons
2258 warnsAboutSignComparisons = aWarnsAboutSignComparisons;