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
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 /*! Helper method for optionally trimming path names before printing them to the console. */
165 - (NSString *)trimmedPath:(char *)path;
168 #pragma mark Properties
171 //! Public properties previously declared readonly have a private readwrite implementation internally to the class.
174 // NOTE: The documentation would suggest that the repetition of the "copy" attribute here is not required, but without it the
175 // compiler issues various warnings. A Radar has been filed against this (<rdar://problem/5403996>) as it appears to be either a
176 // compiler bug or a documentation bug. The corresponding test case can be found in the other/readonly_readwrite_properties_bug
179 @property(readwrite, copy) NSDate *startDate;
180 @property(readwrite) unsigned testsRun;
181 @property(readwrite) unsigned testsPassed;
182 @property(readwrite) unsigned testsFailed;
183 @property(readwrite) unsigned uncaughtExceptions;
184 @property(readwrite) unsigned testsFailedExpected;
185 @property(readwrite) unsigned testsPassedUnexpected;
186 @property(readwrite) unsigned lowLevelExceptionsExpected;
187 @property(readwrite) unsigned lowLevelExceptionsUnexpected;
188 @property(readwrite, copy) NSString *lastReportedFile;
189 @property(readwrite) int lastReportedLine;
195 @implementation WOTest
198 #pragma mark Singleton pattern enforcement methods
200 + (WOTest *)sharedInstance;
202 // speed less of a concern here than robustness so always lock (instead of using double-checked locking plus memory barriers)
203 volatile id instance = nil;
204 @synchronized (WOTestSharedInstance)
206 if (WOTestSharedInstance)
207 instance = WOTestSharedInstance;
209 instance = [[self alloc] init];
216 @synchronized (WOTestSharedInstance)
218 if (!WOTestSharedInstance) // first time here
220 if ((self = [super init]))
221 // once-off initialization and setting of defaults:
222 self->warnsAboutSignComparisons = YES;
223 WOTestSharedInstance = self;
226 NSDeallocateObject(self); // were racing, but lost the race
228 return WOTestSharedInstance;
231 // overriding allocWithZone also effectively overrides alloc
232 + (id)allocWithZone:(NSZone *)aZone
234 volatile id instance = nil;
235 @synchronized (WOTestSharedInstance)
237 if (WOTestSharedInstance)
238 instance = WOTestSharedInstance;
240 instance = NSAllocateObject([self class], 0, aZone);
245 // overriding this also overrides copy
246 - (id)copyWithZone:(NSZone *)zone
251 // overriding this also overrides mutableCopy
252 - (id)mutableCopyWithZone:(NSZone *)zone
258 #pragma mark Utility methods
260 - (NSString *)description:(id)anObject truncatedAt:(unsigned)index didTruncate:(BOOL *)didTruncate
262 if (didTruncate) *didTruncate = NO;
263 NSString *description = nil;
265 description = @"(nil)";
270 description = [NSObject WOTest_descriptionForObject:anObject];
271 unsigned int originalLength = [description length];
272 if (index > 0) // a value of 0 would indicate that no truncation is to be performed
274 description = [description WOTest_stringByCollapsingWhitespace];
275 if ([description length] > index)
276 description = [[description substringToIndex:index] WOTest_stringByAppendingCharacter:WO_UNICODE_ELLIPSIS];
277 if (([description length] != originalLength) && (didTruncate))
283 description = @"(exception caught trying to get object description)";
289 - (void)seedRandomNumberGenerator
294 - (void)seedRandomNumberGenerator:(unsigned long)seed
299 - (BOOL)isClassMethod:(NSString *)method
301 return (method && [method hasPrefix:@"+"]);
304 - (BOOL)isInstanceMethod:(NSString *)method
306 return (method && [method hasPrefix:@"-"]);
309 - (SEL)selectorFromMethod:(NSString *)method
311 NSParameterAssert(method != nil);
312 NSParameterAssert([method length] > 1);
313 NSString *selectorName = [method substringFromIndex:1];
314 return NSSelectorFromString(selectorName);
318 #pragma mark Test-running methods
320 - (void)checkStartDate
324 if (self.startDate == nil)
325 self.startDate = [NSDate date];
332 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
333 for (NSString *class in [self testableClasses])
334 [self runTestsForClassName:class] ? : failures++;
335 [self printTestResultsSummary];
337 return (failures > 0) ? NO : YES;
340 - (BOOL)runTestsForClassName:(NSString *)className
342 NSParameterAssert(className != nil);
343 return [self runTestsForClass:NSClassFromString(className)];
346 // all other test-running methods ultimately get funnelled through this method
347 - (BOOL)runTestsForClass:(Class)aClass
349 NSParameterAssert(aClass != nil);
350 [self checkStartDate];
351 BOOL noTestFailed = YES;
352 NSDate *startClass = [NSDate date];
355 _WOLog(@"Running tests for class %@", NSStringFromClass(aClass));
356 if ([NSObject WOTest_instancesOfClass:aClass conformToProtocol:@protocol(WOTest)])
358 for (NSString *method in [self testableMethodsFrom:aClass])
360 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
361 NSDate *startMethod = [NSDate date];
362 SEL preflight = @selector(preflight);
363 SEL postflight = @selector(postflight);
365 _WOLog(@"Running test method %@", method);
368 // minimize time spent with exception handlers in place
369 [self installLowLevelExceptionHandler];
371 // record program counter and some other registers right now
373 // LowLevelABI.pdf says "EDI, ESI, EBX, EBP" are the preserved registers (across function calls)
374 // ebp is the "saved frame pointer": "the base address of the caller's stack frame"
375 // eax is used to return pointer and integral results to callers: "The called function places integral or pointer results in EAX"
377 // info on inline assembly: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
378 __asm__ volatile("movl %%eax, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.eax));
379 __asm__ volatile("movl %%ebx, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebx));
380 __asm__ volatile("movl %%edi, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.edi));
381 __asm__ volatile("movl %%esi, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.esi));
382 __asm__ volatile("movl %%esp, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.esp));
383 __asm__ volatile("movl %%ebp, %0\n" : "=m" (WOLowLevelExceptionJumpBuffer.ebp));
385 // done this way in Linux (see acpi_save_register_state function)
386 WOProgramCounter = (unsigned long)&&jump_point;
387 #elif defined (__ppc__)
388 // equivalent to (psuedo code) "WOProgramCounter = current contents of PC register"
389 unsigned long counter;
390 __asm__ volatile("mflr %0" : "=r" (counter));
391 WOProgramCounter.lo = counter & 0xffffffff;
392 WOProgramCounter.hi = (counter & 0xffffffff00000000) >> 32;
394 #error Unsupported architecture
398 goto jump_point; // necessary to silence compiler warning about unused label
400 // if flag set, that means we crashed: throw an exception
401 if (WOTestExceptionTriggered)
403 WOTestExceptionTriggered = 0;
404 @throw [WOTestLowLevelException exceptionWithType:WOLastLowLevelException];
407 if ([self isClassMethod:method])
409 if ([NSObject WOTest_class:aClass respondsToSelector:preflight])
410 objc_msgSend(aClass, preflight);
411 objc_msgSend(aClass, [self selectorFromMethod:method]);
412 if ([NSObject WOTest_class:aClass respondsToSelector:postflight])
413 objc_msgSend(aClass, postflight);
415 else if ([self isInstanceMethod:method])
417 // class must implement alloc and init
418 if ([NSObject WOTest_object:aClass respondsToSelector:@selector(alloc)] &&
419 [NSObject WOTest_instancesOfClass:aClass respondToSelector:@selector(init)])
421 id instance = [[aClass alloc] init];
422 if ([NSObject WOTest_instancesOfClass:aClass respondToSelector:preflight])
423 objc_msgSend(instance, preflight);
424 objc_msgSend(instance, [self selectorFromMethod:method]);
425 if ([NSObject WOTest_instancesOfClass:aClass respondToSelector:postflight])
426 objc_msgSend(instance, postflight);
430 [self writeError:@"Class %@ must respond to the alloc and init selectors",
431 NSStringFromClass(aClass)];
432 [self writeLastKnownLocation];
435 else // should never get here
436 [self writeError:@"WOTest internal error"];
438 @catch (WOTestLowLevelException *lowLevelException)
440 if (self.expectLowLevelExceptions)
442 [self writeStatus:[lowLevelException reason]]; // expected low-level exceptions are not an error
443 self.lowLevelExceptionsExpected++;
447 [self writeError:[lowLevelException reason]]; // unexpected low-level exceptions are an error
448 [self writeLastKnownLocation];
450 self.lowLevelExceptionsUnexpected++;
455 [self writeError:@"uncaught exception (%@) in test method %@", [NSException WOTest_descriptionForException:e],
457 [self writeLastKnownLocation];
459 self.uncaughtExceptions++;
463 if (lowLevelExceptionHandlerInstalled)
464 [self removeLowLevelExceptionHandler];
465 _WOLog(@"Finished test method %@ (%.4f seconds)", method, -[startMethod timeIntervalSinceNow]);
473 [self writeError:@"uncaught exception (%@) testing class %@", [NSException WOTest_descriptionForException:e],
474 NSStringFromClass(aClass)];
475 [self writeLastKnownLocation];
477 self.uncaughtExceptions++;
481 _WOLog(@"Finished tests for class %@ (%.4f seconds)", NSStringFromClass(aClass), -[startClass timeIntervalSinceNow]);
486 - (NSArray *)testableClasses
488 // return an array of class names
489 NSMutableArray *testableClasses = [NSMutableArray array];
491 unsigned classCount = 0; // the total number of classes
492 unsigned conformingClassCount = 0; // classes conforming to WOTest
493 unsigned nonconformingClassCount = 0; // unconforming classes
494 unsigned excludedClassCount = 0; // excluded classes
495 unsigned exceptionCount = 0; // classes provoking exceptions
498 int newNumClasses = objc_getClassList(NULL, 0);
499 Class *classes = NULL;
501 // get a list of all classes on the system
502 while (numClasses < newNumClasses)
504 numClasses = newNumClasses;
505 size_t bufferSize = sizeof(Class) * numClasses;
506 classes = realloc(classes, bufferSize);
507 NSAssert1((classes != NULL), @"realloc() failed (size %d)", bufferSize);
508 newNumClasses = objc_getClassList(classes, numClasses);
515 // skip over some classes because they not only cause exceptions but also spew out ugly console messages
516 SInt32 systemVersion;
517 Gestalt(gestaltSystemVersion, &systemVersion);
518 systemVersion = systemVersion & 0x0000ffff; // Apple instructs to ignore the high-order word
520 NSArray *excludedClasses = (systemVersion < 0x00001040) ?
521 [NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", nil] : // 10.3
522 [NSArray arrayWithObjects: @"Protocol", @"List", @"Object", @"_NSZombie", @"NSATSGlyphGenerator", nil]; // 10.4
524 if (self.verbosity > 1)
525 _WOLog(@"Examining classes for WOTest protocol compliance");
527 for (int i = 0; i < newNumClasses; i++)
531 Class aClass = classes[i];
532 NSString *className = NSStringFromClass(aClass);
536 if ([excludedClasses containsObject:className])
538 excludedClassCount++;
539 if (self.verbosity > 1)
540 _WOLog(@"Skipping class %@ (appears in exclusion list)", className);
542 else if ([NSObject WOTest_instancesOfClass:aClass conformToProtocol:@protocol(WOTest)])
544 conformingClassCount++;
545 [testableClasses addObject:className];
546 if (self.verbosity > 0)
547 _WOLog(@"Class %@ complies with the WOTest protocol", className);
551 nonconformingClassCount++;
552 if (self.verbosity > 1)
553 _WOLog(@"Class %@ does not comply with the WOTest protocol", className);
556 @catch (id exception)
559 // a number of classes are known to provoke exceptions:
560 if (self.verbosity > 1)
561 _WOLog(@"Cannot test protocol compliance for class %@ (caught exception)", className);
571 _WOLog(@"Uncaught exception...");
574 _WOLog(@"Runtime Summary:\n"
575 @"Total classes: %d\n"
576 @"Classes which conform to the WOTest protocol: %d\n"
577 @"Classes which do not conform to the protocol: %d\n"
578 @"Classes excluded from scanning: %d\n"
579 @"Classes that could not be scanned due to exceptions: %d",
581 conformingClassCount,
582 nonconformingClassCount,
586 return [testableClasses sortedArrayUsingSelector:@selector(compare:)];
589 - (NSArray *)testableClassesFrom:(NSBundle *)aBundle
591 NSMutableArray *classNames = [NSMutableArray array];
593 if (aBundle) // only search if actually passed a non-nil bundle
595 // add only classes that match the passed bundle and conform to WOTest
596 for (NSString *className in [self testableClasses])
598 Class aClass = NSClassFromString(className);
599 NSBundle *classBundle = [NSBundle bundleForClass:aClass];
600 if ([classBundle isEqualTo:aBundle])
601 [classNames addObject:className];
605 return [classNames copy]; // return immutable
608 - (NSArray *)testableMethodsFrom:(Class)aClass
610 // catch crashes caused by passing an "id" instead of a "Class"
611 NSParameterAssert([NSObject WOTest_isRegisteredClass:aClass] || [NSObject WOTest_isMetaClass:aClass]);
613 NSMutableArray *methodNames = [NSMutableArray array];
616 NSString *prefix = @"-"; // default prefix (instance methods)
617 if (class_isMetaClass(aClass))
618 prefix = @"+"; // special prefix (class methods)
619 else // this is not a metaclass
621 // get the metaclass; could also use object_getClass
622 Class metaClass = object_getClass(aClass);
623 NSArray *classMethods = [self testableMethodsFrom:metaClass];
624 [methodNames addObjectsFromArray:classMethods];
628 Method *methods = class_copyMethodList(aClass, &count);
631 for (unsigned int i = 0, max = count; i < max; i++)
633 SEL aSelector = method_getName(methods[i]);
634 NSString *name = NSStringFromSelector(aSelector);
635 if (name && [name hasPrefix:@"test"])
636 [methodNames addObject:[NSString stringWithFormat:@"%@%@", prefix, name]];
643 NSString *error = [NSString stringWithFormat:@"exception caught trying to identify testable methods in class %@",
644 NSStringFromClass(aClass)];
645 [self writeError:error];
648 return [methodNames sortedArrayUsingSelector:@selector(compare:)];
651 - (void)printTestResultsSummary;
653 [self checkStartDate]; // just in case no tests were run, make sure that startDate is non-nil
654 double successRate = 0.0;
655 double failureRate = 0.0;
656 if (self.testsRun > 0) // watch out for divide-by-zero if no tests run
658 successRate = ((double)(self.testsPassed + self.testsFailedExpected) / (double)self.testsRun) * 100.0;
659 failureRate = ((double)(self.testsFailed + self.testsPassedUnexpected) / (double)self.testsRun) * 100.0;
661 _WOLog(@"Run summary:\n"
663 @"Tests passed: %d + %d expected failures (%.2f%% success rate)\n"
664 @"Tests failed: %d + %d unexpected passes (%.2f%% failure rate)\n"
665 @"Uncaught exceptions: %d\n"
666 @"Low-level exceptions (crashers): %d + %d expected\n"
667 @"Total run time: %.2f seconds\n",
669 self.testsPassed, self.testsFailedExpected, successRate,
670 self.testsFailed, self.testsPassedUnexpected, failureRate,
671 self.uncaughtExceptions,
672 self.lowLevelExceptionsUnexpected, self.lowLevelExceptionsExpected,
673 -[self.startDate timeIntervalSinceNow]);
675 if (self.testsRun == 0)
676 _WOLog(@"warning: no tests were run\n");
678 // TODO: make Growl notifications optional
679 // TODO: include information about project being tested in Growl notification title
680 // TODO: add options for showing coalesced growl notifications showing individual test failures (with path and line info)
681 // TODO: make clicking on notification bring Xcode to the front, or open the file with the last failure in it etc
682 NSString *status = [NSString stringWithFormat:@"%d tests passed, %d tests failed",
683 self.testsPassed + self.testsFailedExpected, self.testsFailed + self.testsPassedUnexpected];
685 if ([self testsWereSuccessful])
686 [self growlNotifyTitle:@"WOTest run successful" message:status isWarning:NO sticky:NO];
689 _WOLog(@"error: testing did not complete without errors\n");
690 [self growlNotifyTitle:@"WOTest run failed" message:status isWarning:YES sticky:YES];
695 self.startDate = nil;
698 - (BOOL)testsWereSuccessful
700 return ((self.testsFailed + self.testsPassedUnexpected + self.uncaughtExceptions + self.lowLevelExceptionsUnexpected) == 0);
704 #pragma mark Low-level exception handling
706 - (void)installLowLevelExceptionHandler
708 if (!lowLevelExceptionHandlerInstalled)
710 WOOldLowLevelExceptionHandler = InstallExceptionHandler(NewExceptionHandlerUPP(WOLowLevelExceptionHandler));
711 lowLevelExceptionHandlerInstalled = YES;
715 - (void)removeLowLevelExceptionHandler
717 if (lowLevelExceptionHandlerInstalled)
719 DisposeExceptionHandlerUPP(InstallExceptionHandler(WOOldLowLevelExceptionHandler));
720 lowLevelExceptionHandlerInstalled = NO;
725 #pragma mark Growl support
727 - (void)growlNotifyTitle:(NSString *)title message:(NSString *)message isWarning:(BOOL)isWarning sticky:(BOOL)sticky
729 NSParameterAssert(title != nil);
730 NSParameterAssert(message != nil);
732 // clean up enviroment a bit (hides possible warnings caused if these set for WOTestRunner)
733 NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary:[[NSProcessInfo processInfo] environment]];
734 [environment removeObjectForKey:@"DYLD_INSERT_LIBRARIES"];
735 [environment removeObjectForKey:@"WOTestBundleInjector"];
737 NSTask *task = [[NSTask alloc] init];
738 [task setLaunchPath:@"/usr/bin/env"]; // use env so as to pick up PATH, if set
739 [task setEnvironment:environment];
740 NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"growlnotify",
741 @"--name", @"com.wincent.WOTest",
742 @"--appIcon", @"Xcode",
743 @"--priority", (isWarning ? @"2" : @"0"),
744 @"--message", message,
746 if (sticky) [arguments insertObject:@"--sticky" atIndex:0];
747 [task setArguments:arguments];
749 // if env can't find growl it will write a message like "env: growlnotify: No such file or directory" to the standard error
750 // suppress it by redirecting the standard error to /dev/null
751 [task setStandardError:[NSFileHandle fileHandleForWritingAtPath:@"/dev/null"]];
756 [task waitUntilExit];
758 // handle error conditions
759 if (![task isRunning])
761 int status = [task terminationStatus];
762 if (status == 127) // env returns this when "[t]he utility specified by utility could not be found"
763 _WOLog(@"note: growlnotify not launched (not found in the current PATH)");
764 else if (status != EXIT_SUCCESS)
765 // a failure to run growlnotify is relatively harmless, so use warning rather than error
766 _WOLog(@"warning: env terminated with exit status %d while trying to run growlnotify", status);
769 @catch (NSException *e)
771 // highly unlikely that we'd ever get here, but report it anyway
772 _WOLog(@"warning: exception caught while trying to execute growlnotify using env (%@: %@)", [e name], [e reason]);
777 #pragma mark Logging methods
779 - (NSString *)trimmedPath:(char *)path
781 NSParameterAssert(path != NULL);
782 NSString *pathString = [NSString stringWithUTF8String:path];
784 unsigned trim = self.trimInitialPathComponents;
785 if (trim == 0) return pathString;
786 if (![pathString isAbsolutePath]) return pathString; // only trim absolute paths
787 NSArray *components = [pathString pathComponents]; // note: Cocoa returns "/" here as an additional first component
788 NSAssert(components != nil, @"components != nil");
789 unsigned count = [components count];
790 if (count < trim + 2) return pathString; // only trim if there will be at least one component left over
791 return [NSString pathWithComponents:[components subarrayWithRange:NSMakeRange(trim + 1, count - trim - 1)]];
794 - (void)writePassed:(BOOL)passed inFile:(char *)path atLine:(int)line message:(NSString *)message, ...
798 va_start(args, message);
799 NSString *string = [NSString WOTest_stringWithFormat:message arguments:args];
801 if (self.expectFailures) // invert sense of tests (ie. failure is good)
803 if (passed) // passed: bad
805 [self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Passed (unexpected pass): %@", string]];
806 self.testsPassedUnexpected++;
810 [self writeStatusInFile:path atLine:line message:[NSString stringWithFormat:@"Failed (expected failure): %@", string]];
811 self.testsFailedExpected++;
814 else // normal handling (ie. passing is good, failing is bad)
816 if (passed) // passed: good
818 [self writeStatusInFile:path atLine:line message:[NSString stringWithFormat:@"Passed: %@", string]];
823 [self writeErrorInFile:path atLine:line message:[NSString stringWithFormat:@"Failed: %@", string]];
829 - (void)cacheFile:(char *)path line:(int)line
831 self.lastReportedFile = [self trimmedPath:path];
832 self.lastReportedLine = line;
835 - (void)writeLastKnownLocation
837 NSString *path = self.lastReportedFile;
839 _WOLog(@"%@:%d: last known location was %@:%d", path, self.lastReportedLine, path, self.lastReportedLine);
842 - (void)writeErrorInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
845 va_start(args, message);
846 NSString *error = [NSString WOTest_stringWithFormat:message arguments:args];
847 _WOLog(@"%@:%d: error: %@", [self trimmedPath:path], line, error);
848 [self cacheFile:path line:line];
852 - (void)writeWarningInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
855 va_start(args, message);
856 NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
857 _WOLog(@"%@:%d: warning: %@", [self trimmedPath:path], line, warning);
858 [self cacheFile:path line:line];
862 - (void)writeUncaughtException:(NSString *)info inFile:(char *)path atLine:(int)line
864 _WOLog(@"%@:%d: error: uncaught exception during test execution: %@", [self trimmedPath:path], line, info);
865 self.uncaughtExceptions++;
868 - (void)writeStatusInFile:(char *)path atLine:(int)line message:(NSString *)message, ...
871 va_start(args, message);
872 NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
873 _WOLog(@"%@:%d %@", [self trimmedPath:path], line, status); // omit colin after line number or Xcode will show this as an error
874 [self cacheFile:path line:line];
878 - (void)writeStatus:(NSString *)message, ...
881 va_start(args, message);
882 NSString *status = [NSString WOTest_stringWithFormat:message arguments:args];
883 _WOLog(@"%@", status);
887 - (void)writeWarning:(NSString *)message, ...
890 va_start(args, message);
891 NSString *warning = [NSString WOTest_stringWithFormat:message arguments:args];
892 _WOLog(@"warning: %@", warning); // older versions of Xcode required initial colons "::" to show this as a warning
896 - (void)writeError:(NSString *)message, ...
899 va_start(args, message);
900 NSString *error = [NSString WOTest_stringWithFormat:message arguments:args];
901 _WOLog(@"error: %@", error); // older versions of Xcode required initial colons "::" to show this as an error
906 #pragma mark Empty (do-nothing) test methods
908 - (void)passTestInFile:(char *)path atLine:(int)line
910 [self writePassed:YES inFile:path atLine:line message:@"(always passes)"];
913 - (void)failTestInFile:(char *)path atLine:(int)line
915 [self writePassed:NO inFile:path atLine:line message:@"(always fails)"];
919 #pragma mark Boolean test methods
921 - (void)testTrue:(BOOL)expr inFile:(char *)path atLine:(int)line
923 [self writePassed:expr inFile:path atLine:line message:@"expected YES, got %@", (expr ? @"YES" : @"NO")];
926 - (void)testFalse:(BOOL)expr inFile:(char *)path atLine:(int)line
928 [self writePassed:!expr inFile:path atLine:line message:@"expected NO, got %@", (expr ? @"YES" : @"NO")];
932 #pragma mark NSValue-based tests
934 - (void)testValue:(NSValue *)actual isEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line
936 NSParameterAssert(actual);
937 NSParameterAssert(expected);
940 // NSValue category will throw an exception for invalid input(s)
942 equal = [actual WOTest_testIsEqualToValue:expected];
945 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
946 self.uncaughtExceptions++;
948 BOOL expectedTruncated, actualTruncated;
949 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
950 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
951 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
954 - (void)testValue:(NSValue *)actual isNotEqualTo:(NSValue *)expected inFile:(char *)path atLine:(int)line
956 NSParameterAssert(actual);
957 NSParameterAssert(expected);
960 // NSValue category will throw an exception for invalid input(s)
962 equal = [actual WOTest_testIsEqualToValue:expected];
965 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
966 self.uncaughtExceptions++;
968 BOOL expectedTruncated, actualTruncated;
969 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
970 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
971 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
974 - (void)testValue:(NSValue *)actual greaterThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
976 NSParameterAssert(actual);
977 NSParameterAssert(expected);
978 BOOL greaterThan = NO;
980 // NSValue category will throw an exception for invalid input(s)
982 greaterThan = [actual WOTest_testIsGreaterThanValue:expected];
985 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
986 self.uncaughtExceptions++;
988 BOOL expectedTruncated, actualTruncated;
989 [self writePassed:greaterThan inFile:path atLine:line message:@"expected > %@, got %@", WO_DESC(expected), WO_DESC(actual)];
990 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
991 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
994 - (void)testValue:(NSValue *)actual notGreaterThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
996 NSParameterAssert(actual);
997 NSParameterAssert(expected);
998 BOOL notGreaterThan = NO;
1000 // NSValue category will throw an exception for invalid input(s)
1002 notGreaterThan = [actual WOTest_testIsNotGreaterThanValue:expected];
1005 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1006 self.uncaughtExceptions++;
1008 BOOL expectedTruncated, actualTruncated;
1009 [self writePassed:notGreaterThan inFile:path atLine:line message:@"expected <= %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1010 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1011 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1014 - (void)testValue:(NSValue *)actual lessThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1016 NSParameterAssert(actual);
1017 NSParameterAssert(expected);
1020 // NSValue category will throw an exception for invalid input(s)
1022 lessThan = [actual WOTest_testIsLessThanValue:expected];
1025 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1026 self.uncaughtExceptions++;
1028 BOOL expectedTruncated, actualTruncated;
1029 [self writePassed:lessThan inFile:path atLine:line message:@"expected < %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1030 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1031 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1034 - (void)testValue:(NSValue *)actual notLessThan:(NSValue *)expected inFile:(char *)path atLine:(int)line
1036 NSParameterAssert(actual);
1037 NSParameterAssert(expected);
1038 BOOL notLessThan = NO;
1040 // NSValue category will throw an exception for invalid input(s)
1042 notLessThan = [actual WOTest_testIsNotLessThanValue:expected];
1045 [self writeErrorInFile:path atLine:line message:@"uncaught exception (%@)", [NSException WOTest_descriptionForException:e]];
1046 self.uncaughtExceptions++;
1048 BOOL expectedTruncated, actualTruncated;
1049 [self writePassed:notLessThan inFile:path atLine:line message:@"expected >= %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1050 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1051 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1055 #pragma mark Pointer to void test methods
1057 - (void)testNil:(void *)pointer inFile:(char *)path atLine:(int)line
1059 BOOL result = (pointer ? NO : YES);
1060 [self writePassed:result inFile:path atLine:line message:@"expected nil, got %@",
1061 (result ? @"nil" : [NSString stringWithFormat:@"%x", pointer])];
1064 - (void)testNotNil:(void *)pointer inFile:(char *)path atLine:(int)line
1066 BOOL result = (pointer ? YES : NO);
1067 [self writePassed:result inFile:path atLine:line message:@"expected (not) nil, got %@",
1068 (result ? [NSString stringWithFormat:@"%x", pointer] : @"nil")];
1071 - (void)testPointer:(void *)actual isEqualTo:(void *)expected inFile:(char *)path atLine:(int)line
1073 BOOL result = (actual == expected);
1074 [self writePassed:result inFile:path atLine:line message:@"expected %x, got %x", expected, actual];
1077 - (void)testPointer:(void *)actual isNotEqualTo:(void *)expected inFile:(char *)path atLine:(int)line
1079 BOOL result = (actual != expected);
1080 [self writePassed:result inFile:path atLine:line message:@"expected (not) %x, got %x", expected, actual];
1084 #pragma mark int test methods
1086 - (void)testIsInt:(char *)type inFile:(char *)path atLine:(int)line
1088 BOOL result = (strcmp(type, "i") == 0);
1089 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"i\", got \"%s\"", type]];
1092 - (void)testIsNotInt:(char *)type inFile:(char *)path atLine:(int)line
1094 BOOL result = (strcmp(type, "i") != 0);
1095 [self writePassed:result
1098 message:[NSString stringWithFormat:@"expected type (not) \"i\", got \"%s\"", type]];
1101 - (void)testIntPositive:(int)aInt inFile:(char *)path atLine:(int)line
1103 [self testInt:aInt greaterThan:(int)0 inFile:path atLine:line];
1106 - (void)testIntNegative:(int)aInt inFile:(char *)path atLine:(int)line
1108 [self testInt:aInt lessThan:(int)0 inFile:path atLine:line];
1111 - (void)testIntZero:(int)aInt inFile:(char *)path atLine:(int)line
1113 [self testInt:aInt isEqualTo:(int)0 inFile:path atLine:line];
1116 - (void)testIntNotZero:(int)aInt inFile:(char *)path atLine:(int)line
1118 [self testInt:aInt isNotEqualTo:(int)0 inFile:path atLine:line];
1121 - (void)testInt:(int)actual isEqualTo:(int)expected inFile:(char *)path atLine:(int)line
1123 BOOL result = (actual == expected);
1124 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat:@"expected %d, got %d", expected, actual]];
1127 - (void)testInt:(int)actual isNotEqualTo:(int)expected inFile:(char *)path atLine:(int)line
1129 BOOL result = (actual != expected);
1130 [self writePassed:result
1133 message:[NSString stringWithFormat:@"expected (not) %d, got %d", expected, actual]];
1136 - (void)testInt:(int)actual greaterThan:(int)expected inFile:(char *)path atLine:(int)line
1138 BOOL result = (actual > expected);
1139 [self writePassed:result
1142 message:[NSString stringWithFormat:@"expected > %d, got %d", expected, actual]];
1145 - (void)testInt:(int)actual notGreaterThan:(int)expected inFile:(char *)path atLine:(int)line
1147 BOOL result = (actual <= expected);
1148 [self writePassed:result
1151 message:[NSString stringWithFormat:@"expected <= %d, got %d", expected, actual]];
1154 - (void)testInt:(int)actual lessThan:(int)expected inFile:(char *)path atLine:(int)line
1156 BOOL result = (actual < expected);
1157 [self writePassed:result
1160 message:[NSString stringWithFormat:@"expected < %d, got %d", expected, actual]];
1163 - (void)testInt:(int)actual notLessThan:(int)expected inFile:(char *)path atLine:(int)line
1165 BOOL result = (actual >= expected);
1166 [self writePassed:result
1169 message:[NSString stringWithFormat:@"expected >= %d, got %d", expected, actual]];
1173 #pragma mark unsigned test methods
1175 - (void)testIsUnsigned:(char *)type inFile:(char *)path atLine:(int)line
1177 BOOL result = (strcmp(type, "I") == 0);
1178 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"I\", got \"%s\"", type]];
1181 - (void)testIsNotUnsigned:(char *)type inFile:(char *)path atLine:(int)line
1183 BOOL result = (strcmp(type, "I") != 0);
1184 [self writePassed:result
1187 message:[NSString stringWithFormat:@"expected type (not) \"I\", got \"%s\"", type]];
1190 - (void)testUnsignedZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
1192 return [self testUnsigned:aUnsigned isEqualTo:(unsigned)0 inFile:path atLine:line];
1195 - (void)testUnsignedNotZero:(unsigned)aUnsigned inFile:(char *)path atLine:(int)line
1197 return [self testUnsigned:aUnsigned isNotEqualTo:(unsigned)0 inFile:path atLine:line];
1200 - (void)testUnsigned:(unsigned)actual isEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
1202 BOOL result = (actual == expected);
1203 [self writePassed:result
1206 message:[NSString stringWithFormat:@"expected %u, got %u", expected, actual]];
1209 - (void)testUnsigned:(unsigned)actual isNotEqualTo:(unsigned)expected inFile:(char *)path atLine:(int)line
1211 BOOL result = (actual != expected);
1212 [self writePassed:result
1215 message:[NSString stringWithFormat:@"expected (not) %u, got %u", expected, actual]];
1218 - (void)testUnsigned:(unsigned)actual greaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1220 BOOL result = (actual > expected);
1221 [self writePassed:result
1224 message:[NSString stringWithFormat:@"expected > %u, got %u", expected, actual]];
1227 - (void)testUnsigned:(unsigned)actual notGreaterThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1229 BOOL result = (actual <= expected);
1230 [self writePassed:result
1233 message:[NSString stringWithFormat:@"expected <= %u, got %u", expected, actual]];
1236 - (void)testUnsigned:(unsigned)actual lessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1238 BOOL result = (actual < expected);
1239 [self writePassed:result
1242 message:[NSString stringWithFormat:@"expected < %u, got %u", expected, actual]];
1245 - (void)testUnsigned:(unsigned)actual notLessThan:(unsigned)expected inFile:(char *)path atLine:(int)line
1247 BOOL result = (actual >= expected);
1248 [self writePassed:result
1251 message:[NSString stringWithFormat:@"expected >= %u, got %u", expected, actual]];
1255 #pragma mark float test methods without error margins
1257 - (void)testIsFloat:(char *)type inFile:(char *)path atLine:(int)line
1259 BOOL result = (strcmp(type, "f") == 0);
1260 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"f\", got \"%s\"", type]];
1263 - (void)testIsNotFloat:(char *)type inFile:(char *)path atLine:(int)line
1265 BOOL result = (strcmp(type, "f") != 0);
1266 [self writePassed:result
1269 message:[NSString stringWithFormat:@"expected type (not) \"f\", got \"%s\"", type]];
1272 - (void)testFloatPositive:(float)aFloat inFile:(char *)path atLine:(int)line
1274 return [self testFloat:aFloat greaterThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1277 - (void)testFloatNegative:(float)aFloat inFile:(char *)path atLine:(int)line
1279 return [self testFloat:aFloat lessThan:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1282 - (void)testFloatZero:(float)aFloat inFile:(char *)path atLine:(int)line
1284 return [self testFloat:aFloat isEqualTo:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1287 - (void)testFloatNotZero:(float)aFloat inFile:(char *)path atLine:(int)line
1289 return [self testFloat:aFloat isNotEqualTo:(float)0.0 withinError:(float)0.0 inFile:path atLine:line];
1292 - (void)testFloat:(float)actual isEqualTo:(float)expected inFile:(char *)path atLine:(int)line
1294 return [self testFloat:actual isEqualTo:expected withinError:(float)0.0 inFile:path atLine:line];
1297 - (void)testFloat:(float)actual isNotEqualTo:(float)expected inFile:(char *)path atLine:(int)line
1299 return [self testFloat:actual isNotEqualTo:expected withinError:(float)0.0 inFile:path atLine:line];
1302 - (void)testFloat:(float)actual greaterThan:(float)expected inFile:(char *)path atLine:(int)line
1304 return [self testFloat:actual greaterThan:expected withinError:(float)0.0 inFile:path atLine:line];
1307 - (void)testFloat:(float)actual notGreaterThan:(float)expected inFile:(char *)path atLine:(int)line
1309 return [self testFloat:actual notGreaterThan:expected withinError:(float)0.0 inFile:path atLine:line];
1312 - (void)testFloat:(float)actual lessThan:(float)expected inFile:(char *)path atLine:(int)line
1314 return [self testFloat:actual lessThan:expected withinError:(float)0.0 inFile:path atLine:line];
1317 - (void)testFloat:(float)actual notLessThan:(float)expected inFile:(char *)path atLine:(int)line
1319 return [self testFloat:actual notLessThan:expected withinError:(float)0.0 inFile:path atLine:line];
1323 #pragma mark float test methods with error margins
1325 - (void)testFloatPositive:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1327 return [self testFloat:aFloat greaterThan:(float)0.0 withinError:error inFile:path atLine:line];
1330 - (void)testFloatNegative:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1332 return [self testFloat:aFloat lessThan:(float)0.0 withinError:error inFile:path atLine:line];
1335 - (void)testFloatZero:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1337 return [self testFloat:aFloat isEqualTo:(float)0.0 withinError:error inFile:path atLine:line];
1340 - (void)testFloatNotZero:(float)aFloat withinError:(float)error inFile:(char *)path atLine:(int)line
1342 return [self testFloat:aFloat isNotEqualTo:(float)0.0 withinError:error inFile:path atLine:line];
1345 - (void)testFloat:(float)actual isEqualTo:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1347 BOOL result = (fabsf(actual - expected) <= error);
1348 [self writePassed:result
1352 [NSString stringWithFormat:@"expected %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1355 - (void)testFloat:(float)actual isNotEqualTo:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1357 BOOL result = (fabsf(actual - expected) > -error);
1358 [self writePassed:result
1362 [NSString stringWithFormat:@"expected (not) %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1365 - (void)testFloat:(float)actual greaterThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1367 BOOL result = ((actual - expected) > -error);
1368 [self writePassed:result
1372 [NSString stringWithFormat:@"expected > %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1375 - (void)testFloat:(float)actual notGreaterThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1377 BOOL result = ((actual - expected) <= error);
1378 [self writePassed:result
1382 [NSString stringWithFormat:@"expected <= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1385 - (void)testFloat:(float)actual lessThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1387 BOOL result = ((actual - expected) < -error);
1388 [self writePassed:result
1392 [NSString stringWithFormat:@"expected < %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1395 - (void)testFloat:(float)actual notLessThan:(float)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1397 BOOL result = ((actual - expected) >= error);
1398 [self writePassed:result
1402 [NSString stringWithFormat:@"expected >= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1406 #pragma mark double test methods without error margins
1408 - (void)testIsDouble:(char *)type inFile:(char *)path atLine:(int)line
1410 BOOL result = (strcmp(type, "d") == 0);
1411 [self writePassed:result inFile:path atLine:line message:[NSString stringWithFormat: @"expected type \"d\", got \"%s\"", type]];
1414 - (void)testIsNotDouble:(char *)type inFile:(char *)path atLine:(int)line
1416 BOOL result = (strcmp(type, "d") != 0);
1417 [self writePassed:result
1420 message:[NSString stringWithFormat:@"expected type (not) \"d\", got \"%s\"", type]];
1423 - (void)testDoublePositive:(double)aDouble inFile:(char *)path atLine:(int)line
1425 return [self testDouble:aDouble greaterThan:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1428 - (void)testDoubleNegative:(double)aDouble inFile:(char *)path atLine:(int)line
1430 return [self testDouble:aDouble lessThan:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1433 - (void)testDoubleZero:(double)aDouble inFile:(char *)path atLine:(int)line
1435 return [self testDouble:aDouble isEqualTo:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1438 - (void)testDoubleNotZero:(double)aDouble inFile:(char *)path atLine:(int)line
1440 return [self testDouble:aDouble isNotEqualTo:(double)0.0 withinError:(double)0.0 inFile:path atLine:line];
1443 - (void)testDouble:(double)actual isEqualTo:(double)expected inFile:(char *)path atLine:(int)line
1445 return [self testDouble:actual isEqualTo:expected withinError:(double)0.0 inFile:path atLine:line];
1448 - (void)testDouble:(double)actual isNotEqualTo:(double)expected inFile:(char *)path atLine:(int)line
1450 return [self testDouble:actual isNotEqualTo:expected withinError:(double)0.0 inFile:path atLine:line];
1453 - (void)testDouble:(double)actual greaterThan:(double)expected inFile:(char *)path atLine:(int)line
1455 return [self testDouble:actual greaterThan:expected withinError:(double)0.0 inFile:path atLine:line];
1458 - (void)testDouble:(double)actual notGreaterThan:(double)expected inFile:(char *)path atLine:(int)line
1460 return [self testDouble:actual notGreaterThan:expected withinError:(double)0.0 inFile:path atLine:line];
1463 - (void)testDouble:(double)actual lessThan:(double)expected inFile:(char *)path atLine:(int)line
1465 return [self testDouble:actual lessThan:expected withinError:(double)0.0 inFile:path atLine:line];
1468 - (void)testDouble:(double)actual notLessThan:(double)expected inFile:(char *)path atLine:(int)line
1470 return [self testDouble:actual notLessThan:expected withinError:(double)0.0 inFile:path atLine:line];
1474 #pragma mark double test methods with error margins
1476 - (void)testDoublePositive:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1478 return [self testDouble:aDouble greaterThan:(double)0.0 withinError:error inFile:path atLine:line];
1481 - (void)testDoubleNegative:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1483 return [self testDouble:aDouble lessThan:(double)0.0 withinError:error inFile:path atLine:line];
1486 - (void)testDoubleZero:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1488 return [self testDouble:aDouble isEqualTo:(double)0.0 withinError:error inFile:path atLine:line];
1491 - (void)testDoubleNotZero:(double)aDouble withinError:(double)error inFile:(char *)path atLine:(int)line
1493 return [self testDouble:aDouble isNotEqualTo:(double)0.0 withinError:error inFile:path atLine:line];
1496 - (void)testDouble:(double)actual isEqualTo:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1498 BOOL result = (fabs(actual - expected) <= error);
1499 [self writePassed:result
1503 [NSString stringWithFormat:@"expected %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1506 - (void)testDouble:(double)actual isNotEqualTo:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1508 BOOL result = (fabs(actual - expected) > -error);
1509 [self writePassed:result
1513 [NSString stringWithFormat:@"expected (not) %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1516 - (void)testDouble:(double)actual greaterThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1518 BOOL result = ((actual - expected) > -error);
1519 [self writePassed:result
1523 [NSString stringWithFormat:@"expected > %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1526 - (void)testDouble:(double)actual notGreaterThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1528 BOOL result = ((actual - expected) <= error);
1529 [self writePassed:result
1533 [NSString stringWithFormat:@"expected <= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1536 - (void)testDouble:(double)actual lessThan:(double)expected withinError:(double)error inFile:(char *)path atLine:(int)line
1538 BOOL result = ((actual - expected) < -error);
1539 [self writePassed:result
1543 [NSString stringWithFormat:@"expected < %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1546 - (void)testDouble:(double)actual notLessThan:(double)expected withinError:(float)error inFile:(char *)path atLine:(int)line
1548 BOOL result = ((actual - expected) >= error);
1549 [self writePassed:result
1553 [NSString stringWithFormat:@"expected >= %f (%C%f), got %f", expected, WO_UNICODE_PLUS_MINUS_SIGN, error, actual]];
1557 #pragma mark object test methods
1559 - (void)testObject:(id)actual isEqualTo:(id)expected inFile:(char *)path atLine:(int)line
1562 if (!actual && !expected) equal = YES; // equal (both nil)
1563 else if (actual) equal = [actual isEqual:expected];
1564 BOOL expectedTruncated, actualTruncated;
1565 [self writePassed:equal inFile:path atLine:line message:@"expected \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1566 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1567 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1570 - (void)testObject:(id)actual isNotEqualTo:(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)
1579 message:@"expected (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1580 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1581 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1585 #pragma mark NSString test methods
1587 - (void)testString:(NSString *)actual isEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line
1589 if (actual && ![actual isKindOfClass:[NSString class]])
1590 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1591 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1594 if (expected && ![expected isKindOfClass:[NSString class]])
1595 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1596 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1600 if (!actual && !expected) equal = YES; // equal (both nil)
1601 else if (actual) equal = [actual isEqualToString:expected];
1602 BOOL expectedTruncated, actualTruncated;
1603 [self writePassed:equal inFile:path atLine:line message:@"expected \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1604 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1605 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1608 - (void)testString:(NSString *)actual isNotEqualTo:(NSString *)expected inFile:(char *)path atLine:(int)line
1610 if (actual && ![actual isKindOfClass:[NSString class]])
1611 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1612 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1615 if (expected && ![expected isKindOfClass:[NSString class]])
1616 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1617 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1621 if (!actual && !expected) equal = YES; // equal (both nil)
1622 else if (actual) equal = [actual isEqualToString:expected];
1623 BOOL expectedTruncated, actualTruncated;
1624 [self writePassed:equal
1627 message:@"expected (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1628 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1629 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1632 - (void)testString:(NSString *)actual hasPrefix:(NSString *)expected inFile:(char *)path atLine:(int)line
1635 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1636 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1639 if (actual && ![actual isKindOfClass:[NSString class]])
1640 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1641 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1644 if (![expected isKindOfClass:[NSString class]])
1645 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1646 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1649 BOOL result = actual ? NO : [actual hasPrefix:expected];
1650 BOOL expectedTruncated, actualTruncated;
1651 [self writePassed:result
1654 message:@"expected prefix \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1655 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1656 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1659 - (void)testString:(NSString *)actual doesNotHavePrefix:(NSString *)expected inFile:(char *)path atLine:(int)line
1662 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1663 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1666 if (actual && ![actual isKindOfClass:[NSString class]])
1667 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1668 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1671 if (![expected isKindOfClass:[NSString class]])
1672 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1673 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1676 BOOL result = actual ? (![actual hasPrefix:expected]) : NO;
1677 BOOL expectedTruncated, actualTruncated;
1678 [self writePassed:result
1681 message:@"expected prefix (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1682 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1683 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1686 - (void)testString:(NSString *)actual hasSuffix:(NSString *)expected inFile:(char *)path atLine:(int)line
1689 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1690 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1693 if (actual && ![actual isKindOfClass:[NSString class]])
1694 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1695 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1698 if (![expected isKindOfClass:[NSString class]])
1699 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1700 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1703 BOOL result = actual ? NO : [actual hasSuffix:expected];
1704 BOOL expectedTruncated, actualTruncated;
1705 [self writePassed:result
1708 message:@"expected suffix \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1709 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1710 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1713 - (void)testString:(NSString *)actual doesNotHaveSuffix:(NSString *)expected inFile:(char *)path atLine:(int)line
1716 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1717 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1720 if (actual && ![actual isKindOfClass:[NSString class]])
1721 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1722 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1725 if (![expected isKindOfClass:[NSString class]])
1726 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1727 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1730 BOOL result = actual ? (![actual hasSuffix:expected]) : NO;
1731 BOOL expectedTruncated, actualTruncated;
1732 [self writePassed:result
1735 message:@"expected suffix (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1736 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1737 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1740 - (void)testString:(NSString *)actual contains:(NSString *)expected inFile:(char *)path atLine:(int)line
1743 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1744 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1747 if (actual && ![actual isKindOfClass:[NSString class]])
1748 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1749 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1752 if (![expected isKindOfClass:[NSString class]])
1753 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1754 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1757 BOOL result = actual ? NO : (!NSEqualRanges([actual rangeOfString:expected], NSMakeRange(NSNotFound, 0)));
1758 BOOL expectedTruncated, actualTruncated;
1759 [self writePassed:result
1762 message:@"expected contains \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1763 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1764 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1767 - (void)testString:(NSString *)actual doesNotContain:(NSString *)expected inFile:(char *)path atLine:(int)line
1770 [NSException WOTest_raise:WO_TEST_NIL_PARAMETER_EXCEPTION
1771 reason:WO_NIL_PARAMETER_EXCEPTION_REASON
1774 if (actual && ![actual isKindOfClass:[NSString class]])
1775 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1776 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(actual)
1779 if (![expected isKindOfClass:[NSString class]])
1780 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1781 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(expected)
1784 BOOL result = actual ? YES : (NSEqualRanges([actual rangeOfString:expected], NSMakeRange(NSNotFound, 0)));
1785 BOOL expectedTruncated, actualTruncated;
1786 [self writePassed:result
1789 message:@"expected contains (not) \"%@\", got \"%@\"", WO_DESC(expected), WO_DESC(actual)];
1790 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1791 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1795 #pragma mark NSArray test methods
1797 - (void)testArray:(NSArray *)actual isEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line
1799 if (actual && ![actual isKindOfClass:[NSArray class]])
1800 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1801 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(actual)
1804 if (expected && ![expected isKindOfClass:[NSArray class]])
1805 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1806 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(expected)
1810 if (!actual && !expected) equal = YES; // equal (both nil)
1811 else if (actual) equal = [actual isEqualToArray:expected];
1812 BOOL expectedTruncated, actualTruncated;
1813 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1814 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1815 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1818 - (void)testArray:(NSArray *)actual isNotEqualTo:(NSArray *)expected inFile:(char *)path atLine:(int)line
1820 if (actual && ![actual isKindOfClass:[NSArray class]])
1821 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1822 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(actual)
1825 if (expected && ![expected isKindOfClass:[NSArray class]])
1826 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1827 reason:WO_EXPECTED_ARRAY_EXCEPTION_REASON(expected)
1831 if (!actual && !expected) equal = YES; // equal (both nil)
1832 else if (actual) equal = [actual isEqualToArray:expected];
1833 BOOL expectedTruncated, actualTruncated;
1834 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1835 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1836 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1840 #pragma mark NSDictionary test methods
1842 - (void)testDictionary:(NSDictionary *)actual isEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line
1844 if (actual && ![actual isKindOfClass:[NSArray class]])
1845 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1846 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(actual)
1849 if (expected && ![expected isKindOfClass:[NSArray class]])
1850 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1851 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(expected)
1855 if (!actual && !expected) equal = YES; // equal (both nil)
1856 else if (actual) equal = [actual isEqualToDictionary:expected];
1857 BOOL expectedTruncated, actualTruncated;
1858 [self writePassed:equal inFile:path atLine:line message:@"expected %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1859 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1860 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1863 - (void)testDictionary:(NSDictionary *)actual isNotEqualTo:(NSDictionary *)expected inFile:(char *)path atLine:(int)line
1865 if (actual && ![actual isKindOfClass:[NSDictionary class]])
1866 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1867 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(actual)
1870 if (expected && ![expected isKindOfClass:[NSDictionary class]])
1871 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1872 reason:WO_EXPECTED_DICTIONARY_EXCEPTION_REASON(expected)
1876 if (!actual && !expected) equal = YES; // equal (both nil)
1877 else if (actual) equal = [actual isEqualToDictionary:expected];
1878 BOOL expectedTruncated, actualTruncated;
1879 [self writePassed:(!equal) inFile:path atLine:line message:@"expected (not) %@, got %@", WO_DESC(expected), WO_DESC(actual)];
1880 if (expectedTruncated) _WOLog(@"expected result (not truncated): %@", WO_LONG_DESC(expected));
1881 if (actualTruncated) _WOLog(@"actual result (not truncated): %@", WO_LONG_DESC(actual));
1885 #pragma mark Exception test methods
1887 - (void)testThrowsException:(id)exception inFile:(char *)path atLine:(int)line
1889 BOOL result = (exception ? YES : NO);
1890 [self writePassed:result
1893 message:[NSString stringWithFormat:@"expected exception, got %@", [NSException WOTest_nameForException:exception]]];
1896 - (void)testDoesNotThrowException:(id)exception inFile:(char *)path atLine:(int)line
1898 BOOL result = (exception ? NO : YES);
1899 [self writePassed:result
1903 [NSString stringWithFormat:@"expected no exception, got %@", [NSException WOTest_nameForException:exception]]];
1906 - (void)testThrowsException:(id)exception named:(NSString *)name inFile:(char *)path atLine:(int)line
1908 if (name && ![name isKindOfClass:[NSString class]])
1910 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1911 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(name)
1917 NSString *actualName = [NSException WOTest_nameForException:exception];
1919 if (exception && [actualName isEqualToString:name]) result = YES;
1921 [self writePassed:result
1924 message:[NSString stringWithFormat:@"expected %@, got %@", name, actualName]];
1927 - (void)testDoesNotThrowException:(id)exception named:(NSString *)name inFile:(char *)path atLine:(int)line
1929 if (name && ![name isKindOfClass:[NSString class]])
1931 [NSException WOTest_raise:WO_TEST_CLASS_MISMATCH_EXCEPTION
1932 reason:WO_EXPECTED_STRING_EXCEPTION_REASON(name)
1938 NSString *actualName = [NSException WOTest_nameForException:exception];
1940 if (exception && [actualName isEqualToString:name]) result = NO;
1942 [self writePassed:result inFile:path atLine:line message:@"expected (not) %@, got %@", name, actualName];
1946 #pragma mark Random value generator methods
1948 // TODO: move these into a category, these are more "test helpers" rather than actual "testing methods"
1952 return (int)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1957 return (int)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1962 return (int)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1972 return (int)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1975 - (int)aBigPositiveInt
1977 return (int)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1980 - (int)aBigNegativeInt
1982 return (int)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1987 return (int)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
1990 - (int)aSmallPositiveInt
1992 return (int)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
1995 - (int)aSmallNegativeInt
1997 return (int)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2000 - (unsigned)anUnsigned
2002 return (unsigned)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2005 - (unsigned)aZeroUnsigned
2010 - (unsigned)aBigUnsigned
2012 return (unsigned)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2015 - (unsigned)aSmallUnsigned
2017 return (unsigned)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2022 return (float)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2025 - (float)aPositiveFloat
2027 return (float)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2030 - (float)aNegativeFloat
2032 return (float)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2042 return (float)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2045 - (float)aBigPositiveFloat
2047 return (float)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2050 - (float)aBigNegativeFloat
2052 return (float)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2055 - (float)aSmallFloat
2057 return (float)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2060 - (float)aSmallPositiveFloat
2062 return (float)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2065 - (float)aSmallNegativeFloat
2067 return (float)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2072 return (double)(WO_RANDOM_SIGN * (WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2075 - (double)aPositiveDouble
2077 return (double)(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2080 - (double)aNegativeDouble
2082 return (double)-(WO_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2085 - (double)aZeroDouble
2090 - (double)aBigDouble
2092 return (double)(WO_RANDOM_SIGN * (WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2095 - (double)aBigPositiveDouble
2097 return (double)(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2100 - (double)aBigNegativeDouble
2102 return (double)-(WO_BIG_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2105 - (double)aSmallDouble
2107 return (double)(WO_RANDOM_SIGN * (WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN)));
2110 - (double)aSmallPositiveDouble
2112 return (double)(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2115 - (double)aSmallNegativeDouble
2117 return (double)-(WO_SMALL_TEST_VALUE + (WO_RANDOM_OFFSET * WO_RANDOM_SIGN));
2121 #pragma mark Properties
2123 @synthesize startDate;
2124 @synthesize testsRun;
2125 @synthesize testsPassed;
2126 @synthesize testsFailed;
2127 @synthesize uncaughtExceptions;
2128 @synthesize testsFailedExpected;
2129 @synthesize testsPassedUnexpected;
2130 @synthesize expectFailures;
2131 @synthesize lowLevelExceptionsExpected;
2132 @synthesize lowLevelExceptionsUnexpected;
2133 @synthesize expectLowLevelExceptions;
2134 @synthesize verbosity;
2135 @synthesize trimInitialPathComponents;
2136 @synthesize lastReportedFile;
2137 @synthesize lastReportedLine;
2138 @synthesize warnsAboutSignComparisons;