Permalink
Browse files

Switched to GHUnit to be able to simply debug unit tests.

  • Loading branch information...
1 parent dd828d7 commit 32ab2128b2eb15f027cce8e9cd2205974a5d8b8e @tomaz committed Aug 30, 2010
Showing with 3,918 additions and 200 deletions.
  1. +1 −1 AppledocTests-Info.plist
  2. +2 −2 AppledocTests_prefix.pch
  3. +1 −0 Libraries/GHUnit.framework/GHUnit
  4. +1 −0 Libraries/GHUnit.framework/Headers
  5. +1 −0 Libraries/GHUnit.framework/Resources
  6. BIN Libraries/GHUnit.framework/Versions/A/GHUnit
  7. +43 −0 Libraries/GHUnit.framework/Versions/A/Headers/BWSplitView.h
  8. +139 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHAsyncTestCase.h
  9. +46 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHMockNSHTTPURLResponse.h
  10. +162 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHMockNSURLConnection.h
  11. +132 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHNSInvocation+Utils.h
  12. +133 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHNSInvocationProxy.h
  13. +59 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHNSLocale+Mock.h
  14. +100 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHNSObject+Invocation.h
  15. +40 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTest+JUnitXML.h
  16. +181 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTest.h
  17. +23 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestApp.h
  18. +141 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestCase.h
  19. +38 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestGroup+JUnitXML.h
  20. +151 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestGroup.h
  21. +1,010 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestMacros.h
  22. +42 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestOperation.h
  23. +26 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestOutlineViewModel.h
  24. +159 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestRunner.h
  25. +114 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestSuite.h
  26. +103 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestViewController.h
  27. +163 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestViewModel.h
  28. +41 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTestWindowController.h
  29. +144 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHTesting.h
  30. +36 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHUNSObject+Swizzle.h
  31. +51 −0 Libraries/GHUnit.framework/Versions/A/Headers/GHUnit.h
  32. +105 −0 Libraries/GHUnit.framework/Versions/A/Headers/GTMStackTrace.h
  33. +88 −0 Libraries/GHUnit.framework/Versions/A/Headers/NSException+GHTestFailureExceptions.h
  34. +67 −0 Libraries/GHUnit.framework/Versions/A/Headers/NSValue+GHValueFormatter.h
  35. BIN Libraries/GHUnit.framework/Versions/A/Resources/English.lproj/InfoPlist.strings
  36. BIN Libraries/GHUnit.framework/Versions/A/Resources/GHTestApp.nib
  37. BIN Libraries/GHUnit.framework/Versions/A/Resources/GHTestView.nib
  38. BIN Libraries/GHUnit.framework/Versions/A/Resources/GHTestWindow.nib
  39. +4 −0 Libraries/GHUnit.framework/Versions/A/Resources/GHUnit-Debug.xcconfig
  40. +15 −0 Libraries/GHUnit.framework/Versions/A/Resources/GHUnit.xcconfig
  41. BIN Libraries/GHUnit.framework/Versions/A/Resources/GradientSplitViewDimpleBitmap.tif
  42. BIN Libraries/GHUnit.framework/Versions/A/Resources/GradientSplitViewDimpleVector.pdf
  43. +22 −0 Libraries/GHUnit.framework/Versions/A/Resources/Info.plist
  44. +1 −0 Libraries/GHUnit.framework/Versions/Current
  45. +1 −1 Testing/GBAdoptedProtocolsProviderTesting.m
  46. +3 −3 Testing/GBCategoryDataTesting.m
  47. +2 −2 Testing/GBClassDataTesting.m
  48. +3 −3 Testing/GBIvarDataTesting.m
  49. +1 −1 Testing/GBIvarsProviderTesting.m
  50. +5 −5 Testing/GBMethodDataTesting.m
  51. +1 −1 Testing/GBMethodsProviderTesting.m
  52. +2 −2 Testing/GBModelBaseTesting.m
  53. +2 −2 Testing/GBObjectsAssertor.h
  54. +9 −9 Testing/GBObjectsAssertor.m
  55. +1 −1 Testing/GBProcessor-AdoptedProtocolsTesting.m
  56. +31 −28 Testing/GBProcessor-CommentsTesting.m
  57. +2 −2 Testing/GBProtocolDataTesting.m
  58. +1 −1 Testing/GBStoreTesting.m
  59. +1 −0 Testing/GBTestObjectsRegistry.h
  60. +5 −1 Testing/GBTestObjectsRegistry.m
  61. +1 −1 Testing/GBTokenizerTesting.m
  62. +88 −0 Testing/GHUnitTestMain.m
  63. +174 −134 appledoc.xcodeproj/project.pbxproj
View
2 AppledocTests-Info.plist
@@ -11,7 +11,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
- <string>BNDL</string>
+ <string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
View
4 AppledocTests_prefix.pch
@@ -7,17 +7,17 @@
//
#ifdef __OBJC__
- #import <Foundation/Foundation.h>
+ #import <Cocoa/Cocoa.h>
#import "NSObject+GBObject.h"
#import "NSString+GBString.h"
#import "NSException+GBException.h"
#import "NSFileManager+GBFileManager.h"
#import "GBLog.h"
#define HC_SHORTHAND
+ #import <GHUnit/GHUnit.h>
#import <OCHamcrest/OCHamcrest.h>
#import <OCMock/OCMock.h>
- #import <SenTestingKit/SenTestingKit.h>
#import "GBRealLifeDataProvider.h"
#import "GBTestObjectsRegistry.h"
#import "GBObjectsAssertor.h"
View
1 Libraries/GHUnit.framework/GHUnit
View
1 Libraries/GHUnit.framework/Headers
View
1 Libraries/GHUnit.framework/Resources
View
BIN Libraries/GHUnit.framework/Versions/A/GHUnit
Binary file not shown.
View
43 Libraries/GHUnit.framework/Versions/A/Headers/BWSplitView.h
@@ -0,0 +1,43 @@
+//
+// BWSplitView.h
+// BWToolkit
+//
+// Created by Brandon Walkin (www.brandonwalkin.com) and Fraser Kuyvenhoven.
+// All code is provided under the New BSD license.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface BWSplitView : NSSplitView {
+ NSColor *color;
+ BOOL colorIsEnabled, checkboxIsEnabled, dividerCanCollapse, collapsibleSubviewCollapsed;
+ id secondaryDelegate;
+ NSMutableDictionary *minValues, *maxValues, *minUnits, *maxUnits;
+ NSMutableDictionary *resizableSubviewPreferredProportion, *nonresizableSubviewPreferredSize;
+ NSArray *stateForLastPreferredCalculations;
+ int collapsiblePopupSelection;
+ float uncollapsedSize;
+
+ // Collapse button
+ NSButton *toggleCollapseButton;
+ BOOL isAnimating;
+}
+
+@property (retain) NSMutableDictionary *minValues, *maxValues, *minUnits, *maxUnits;
+@property (retain) NSMutableDictionary *resizableSubviewPreferredProportion, *nonresizableSubviewPreferredSize;
+@property (retain) NSArray *stateForLastPreferredCalculations;
+@property (retain) NSButton *toggleCollapseButton;
+@property BOOL collapsibleSubviewCollapsed;
+@property int collapsiblePopupSelection;
+@property BOOL dividerCanCollapse;
+
+// The split view divider color
+@property (copy) NSColor *color;
+
+// Flag for whether a custom divider color is enabled. If not, the standard divider color is used.
+@property BOOL colorIsEnabled;
+
+// Call this method to collapse or expand a subview configured as collapsible in the IB inspector.
+- (IBAction)toggleCollapse:(id)sender;
+
+@end
View
139 Libraries/GHUnit.framework/Versions/A/Headers/GHAsyncTestCase.h
@@ -0,0 +1,139 @@
+//
+// GHAsyncTestCase.h
+// GHUnit
+//
+// Created by Gabriel Handford on 4/8/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import "GHTestCase.h"
+
+// Some default statuses to use; Or define and use your own
+enum {
+ kGHUnitWaitStatusUnknown = 0,
+ kGHUnitWaitStatusSuccess,
+ kGHUnitWaitStatusFailure,
+ kGHUnitWaitStatusCancelled
+};
+
+/*!
+ Asynchronous test case with wait and notify.
+
+ If notify occurs before wait has started (if it was a synchronous call), this test
+ case will still work.
+
+ Be sure to call prepare before the asynchronous method (otherwise an exception will raise).
+
+ @code
+ - (void)testSuccess {
+ [self prepare];
+
+ // Do asynchronous task here
+ [self performSelector:@selector(_succeed) withObject:nil afterDelay:0.1];
+
+ [self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];
+ }
+
+ - (void)_succeed {
+ // Notice the forSelector points to the test above. This is so that
+ // stray notifies don't error or falsely succeed other tests.
+ // To ignore the check, forSelector can be NULL.
+ [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testSuccess)];
+ }
+ @endcode
+ */
+@interface GHAsyncTestCase : GHTestCase {
+
+ NSInteger waitForStatus_;
+ NSInteger notifiedStatus_;
+
+ BOOL prepared_; // Whether prepared was called before waitForStatus:timeout:
+ NSRecursiveLock *lock_; // Lock to synchronize on
+ SEL waitSelector_; // The selector we are waiting on
+
+ NSArray *_runLoopModes;
+}
+
+/*!
+ Run loop modes to run while waiting;
+ Defaults to NSDefaultRunLoopMode, NSRunLoopCommonModes, NSConnectionReplyMode
+ */
+@property (retain, nonatomic) NSArray *runLoopModes;
+
+/*!
+ Prepare before calling the asynchronous method.
+ */
+- (void)prepare;
+
+/*!
+ Prepare and specify the selector we will use in notify.
+
+ @param selector
+ */
+- (void)prepare:(SEL)selector;
+
+/*!
+ Wait for notification of status or timeout.
+
+ Be sure to prepare before calling your asynchronous method.
+ For example,
+
+ @code
+ - (void)testFoo {
+ [self prepare];
+ // Do asynchronous task here
+ [self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];
+ }
+ @endcode
+
+ @param status kGHUnitWaitStatusSuccess, kGHUnitWaitStatusFailure or custom status
+ @param timeout Timeout in seconds
+ */
+- (void)waitForStatus:(NSInteger)status timeout:(NSTimeInterval)timeout;
+
+// Deprecated
+- (void)waitFor:(NSInteger)status timeout:(NSTimeInterval)timeout;
+
+/*!
+ Wait for timeout to occur.
+ Fails if we did _NOT_ timeout.
+ @param timeout
+ */
+- (void)waitForTimeout:(NSTimeInterval)timeout;
+
+/*!
+ Notify waiting of status for test selector.
+ @param status Status, for example, kGHUnitWaitStatusSuccess
+ @param selector If not NULL, then will verify this selector is where we are waiting.
+ This prevents stray asynchronous callbacks to fail a later test
+ */
+- (void)notify:(NSInteger)status forSelector:(SEL)selector;
+
+/*!
+ Notify waiting of status for any selector.
+ @param status Status, for example, kGHUnitWaitStatusSuccess
+ */
+- (void)notify:(NSInteger)status;
+
+@end
View
46 Libraries/GHUnit.framework/Versions/A/Headers/GHMockNSHTTPURLResponse.h
@@ -0,0 +1,46 @@
+//
+// GHMockNSHTTPURLResponse.h
+// GHUnit
+//
+// Created by Gabriel Handford on 4/9/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import <Foundation/Foundation.h>
+
+/*!
+ NSHTTPURLResponse for use with mocking.
+ Allows us to manually set the status code and headers in the response.
+ */
+@interface GHMockNSHTTPURLResponse : NSHTTPURLResponse {
+ NSInteger statusCode_;
+ NSDictionary *headers_;
+}
+
+- (id)initWithStatusCode:(NSInteger)statusCode headers:(NSDictionary *)headers;
+
+- (void)setStatusCode:(NSInteger)code;
+- (void)setHeaders:(NSDictionary *)headers;
+
+@end
View
162 Libraries/GHUnit.framework/Versions/A/Headers/GHMockNSURLConnection.h
@@ -0,0 +1,162 @@
+//
+// GHMockNSURLConnection.h
+// GHUnit
+//
+// Created by Gabriel Handford on 4/9/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import <Foundation/Foundation.h>
+
+extern NSString *const GHMockNSURLConnectionException;
+
+/*!
+ NSURLConnection for mocking.
+
+ Use with GHAsyncTestCase to mock out connections.
+
+ @code
+
+ @interface GHNSURLConnectionMockTest : GHAsyncTestCase {}
+ @end
+
+ @implementation GHNSURLConnectionMockTest
+
+ - (void)testMock {
+ [self prepare];
+ GHMockNSURLConnection *connection = [[GHMockNSURLConnection alloc] initWithRequest:nil delegate:self];
+ [connection receiveHTTPResponseWithStatusCode:204 headers:testHeaders_ afterDelay:0.1];
+ [connection receiveData:testData_ afterDelay:0.2];
+ [connection finishAfterDelay:0.3];
+ [self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];
+ }
+
+ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+ GHAssertEquals([(NSHTTPURLResponse *)response statusCode], 204, nil);
+ GHAssertEqualObjects([(NSHTTPURLResponse *)response allHeaderFields], testHeaders_, nil);
+ }
+
+ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+ GHAssertEqualObjects(data, testData_, nil);
+ }
+
+ - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
+ [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testMock)];
+ }
+ @end
+
+ @endcode
+ */
+@interface GHMockNSURLConnection : NSObject {
+ NSURLRequest *request_;
+ id delegate_; // weak
+
+ BOOL cancelled_;
+ BOOL started_;
+}
+
+@property (readonly, nonatomic, getter=isStarted) BOOL started;
+@property (readonly, nonatomic, getter=isCancelled) BOOL cancelled;
+
+// Mocked version of NSURLConnection#initWithRequest:delegate:
+- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;
+
+// Mocked version of NSURLConnection#initWithRequest:delegate:startImmediately:
+- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately;
+
+// Mocked version of NSURLConnection#scheduleInRunLoop:forMode: (NOOP)
+- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
+
+// Mocked version of NSURLConnection#start (NOOP)
+- (void)start;
+
+/*!
+ Send generic response to delegate after delay.
+ (For asynchronous requests)
+ @param delay Delay in seconds (if < 0, there is no delay)
+ */
+- (void)receiveResponse:(NSURLResponse *)response afterDelay:(NSTimeInterval)delay;
+
+/*!
+ Send HTTP response to delegate with status code, headers, after delay.
+ This is only the HTTP response (and not data or finished).
+ (For asynchronous requests)
+ @param statusCode HTTP status code
+ @param headers Headers
+ @param delay Delay in seconds (if < 0, there is no delay)
+ */
+- (void)receiveHTTPResponseWithStatusCode:(int)statusCode headers:(NSDictionary *)headers afterDelay:(NSTimeInterval)delay;
+
+/*!
+ Send data to connection delegate after delay.
+ @param data Data to send
+ @param delay Delay in seconds
+ */
+- (void)receiveData:(NSData *)data afterDelay:(NSTimeInterval)delay;
+
+- (void)receiveData:(NSData *)data statusCode:(NSInteger)statusCode MIMEType:(NSString *)MIMEType afterDelay:(NSTimeInterval)delay;
+
+/*!
+ Send data (from file in bundle resource) to connection delegate after delay.
+ (For asynchronous requests)
+ @param path Path to file
+ @param delay Delay in seconds
+ */
+- (void)receiveDataFromPath:(NSString *)path afterDelay:(NSTimeInterval)delay;
+
+/*!
+ Calls connectionDidFinish: delegate after delay.
+ (For asynchronous requests)
+ @param delay Delay in seconds (if < 0, there is no delay)
+ */
+- (void)finishAfterDelay:(NSTimeInterval)delay;
+
+/*!
+ Sends mock response, sends data, and then calls finish.
+ (For asynchronous requests)
+ @param path Path to load data from. File should be available in Test target (bundle)
+ @param statusCode Status code for response
+ @param MIMEType Content type for response header
+ @param afterDelay Delay before responding (if < 0, there is no delay)
+ */
+- (void)receiveFromPath:(NSString *)path statusCode:(NSInteger)statusCode MIMEType:(NSString *)MIMEType afterDelay:(NSTimeInterval)delay;
+
+/*!
+ Sends mock response, sends data, and then calls finish.
+ (For asynchronous requests)
+ @param data Data to load. File should be available in Test target (bundle)
+ @param statusCode Status code for response
+ @param MIMEType Content type for response header
+ @param afterDelay Delay before responding (if < 0, there is no delay)
+ */
+- (void)receiveData:(NSData *)data statusCode:(NSInteger)statusCode MIMEType:(NSString *)MIMEType afterDelay:(NSTimeInterval)delay;
+
+/*!
+ Calls connection:didFailWithError: on delegate after specified delay.
+ @param error The error to pass to the delegate.
+ @param delay Delay before responding (if < 0, there is no delay)
+ */
+- (void)failWithError:(NSError *)error afterDelay:(NSTimeInterval)delay;
+
+@end
View
132 Libraries/GHUnit.framework/Versions/A/Headers/GHNSInvocation+Utils.h
@@ -0,0 +1,132 @@
+//
+// GHNSInvocation+Utils.h
+// GHKit
+//
+// Created by Gabriel Handford on 1/17/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import <Foundation/Foundation.h>
+
+//
+// Creates arguments NSArray from var args, with first object named 'object'
+// - (void)methodName:(id)arg1 withObjects:object, ...
+//
+#define GHConvertVarArgs(object) \
+NSMutableArray *arguments = [NSMutableArray array]; \
+do { \
+id arg; \
+va_list args; \
+if (object) { \
+[arguments addObject:object]; \
+va_start(args, object); \
+while ((arg = va_arg(args, id))) \
+[arguments addObject:arg]; \
+va_end(args); \
+} \
+} while(0);
+
+@interface NSInvocation (GHUtils_GHUNIT)
+
+/*!
+ Invoke on main thread.
+ @param waitUntilDone Whether to join on the call
+ */
+- (void)ghu_invokeOnMainThread:(BOOL)waitUntilDone;
+
+/*!
+ Invoke target selector with multiple arguments.
+ @param target Invocation target
+ @param selector Method
+ @param withObjects (Variable) Arguments list
+ */
++ (id)ghu_invokeWithTarget:(id)target selector:(SEL)selector withObjects:object, ...;
+
+/*!
+ Invoke target selector with multiple arguments.
+ @param target Invocation target
+ @param selector Method
+ @param arguments Arguments list
+ */
++ (id)ghu_invokeWithTarget:(id)target selector:(SEL)selector arguments:(NSArray *)arguments;
+
+/*!
+ Invoke target selector with multiple arguments.
+ @param target Invocation target
+ @param selector Method
+ @param afterDelay Time interval for delay (in seconds)
+ @param arguments Arguments list
+ */
++ (id)ghu_invokeWithTarget:(id)target selector:(SEL)selector afterDelay:(NSTimeInterval)delay arguments:(NSArray *)arguments;
+
+/*!
+ Invoke target selector on main thread with multiple arguments.
+ Use [NSNull null] for nil arguments.
+ @param target Target
+ @param selector Action
+ @param waitUntilDone Whether to wait for call to finish
+ @param withObjects Nil terminated list of (object) arguments; Use [NSNull null] for nil arguments
+ */
++ (void)ghu_invokeTargetOnMainThread:(id)target selector:(SEL)selector waitUntilDone:(BOOL)waitUntilDone withObjects:object, ...;
+
+/*!
+ Invoke target selector on main thread with multiple arguments.
+ @param target Target
+ @param selector Action
+ @param waitUntilDone Whether to wait for call to finish
+ @param arguments Arguments list
+ */
++ (void)ghu_invokeTargetOnMainThread:(id)target selector:(SEL)selector waitUntilDone:(BOOL)waitUntilDone arguments:(NSArray *)arguments;
+
+/*!
+Invoke target selector on main thread with multiple arguments.
+ @param target Target
+ @param selector Action
+ @param waitUntilDone Whether to wait for call to finish
+ @param afterDelay Time interval for delay (in seconds)
+ @param arguments Arguments list
+ */
++ (void)ghu_invokeTargetOnMainThread:(id)target selector:(SEL)selector waitUntilDone:(BOOL)waitUntilDone afterDelay:(NSTimeInterval)delay arguments:(NSArray *)arguments;
+
+/*!
+ Create invocation with variable arguments.
+ Use [NSNull null] for nil arguments.
+ @param target Invocation target
+ @param selector Method
+ @param hasReturnValue Will be set to YES, if there is a return value
+ @param withObjects (Variable) Arguments list
+ */
++ (NSInvocation *)ghu_invocationWithTarget:(id)target selector:(SEL)selector hasReturnValue:(BOOL *)hasReturnValue withObjects:object, ...;
+
+/*!
+ Create invocation with variable arguments.
+ Use [NSNull null] for nil arguments.
+ @param target Invocation target
+ @param selector Method
+ @param hasReturnValue Will be set to YES, if there is a return value
+ @param arguments Arguments array
+ */
++ (NSInvocation *)ghu_invocationWithTarget:target selector:(SEL)selector hasReturnValue:(BOOL *)hasReturnValue arguments:(NSArray *)arguments;
+
+@end
View
133 Libraries/GHUnit.framework/Versions/A/Headers/GHNSInvocationProxy.h
@@ -0,0 +1,133 @@
+//
+// GHNSInvocationProxy_GHUNIT.h
+// GHKit
+//
+// Modified by Gabriel Handford on 5/9/09.
+// This class is based on DDInvocationGrabber.
+//
+
+/*
+ * Copyright (c) 2007-2009 Dave Dribin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/*
+ * This class is based on CInvocationGrabber:
+ *
+ * Copyright (c) 2007, Toxic Software
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the Toxic Software nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*!
+ Proxy that allows invocation on a separate thread, or with a delay.
+
+ Use with the GHNSObject+Invocation category:
+
+ @code
+ NSMutableArray *array = ...;
+ // Adds object to array after 5 seconds
+ [[array ghu_proxyAfterDelay:5.0] addObject:@"test"];
+
+
+ NSThread *thread = ...
+ // Remove all objects from another thread
+ [[array ghu_proxyOnThread:thread waitUntilDone:NO] removeAllObjects];
+ @endcode
+
+ Create invocation proxy for a NSMutableArray.
+
+ @code
+ NSMutableArray *array = ...;
+ NSThread *thread = ...
+
+ GHNSInvocationProxy_GHUNIT *arrayProxy = [GHNSInvocationProxy_GHUNIT invocation];
+ arrayProxy.target = array;
+ arrayProxy.thread = thread;
+ arrayProxy.waitUntilDone = NO;
+
+ // Performs method on thread and doesn't wait for return
+ [arrayProxy addObject:@"test"];
+ @endcode
+ */
+@interface GHNSInvocationProxy_GHUNIT : NSProxy {
+
+ id target_;
+
+ NSThread *thread_;
+ BOOL waitUntilDone_;
+ NSTimeInterval delay_;
+
+ // If debuging time to set
+ NSTimeInterval *time_;
+
+ NSInvocation *invocation_;
+}
+
+@property (retain, nonatomic) id target;
+@property (retain, nonatomic) NSInvocation *invocation;
+@property (retain, nonatomic) NSThread *thread;
+@property (assign, nonatomic) BOOL waitUntilDone;
+@property (assign, nonatomic) NSTimeInterval delay;
+@property (assign, nonatomic) NSTimeInterval *time;
+
+/*!
+ Create autoreleased empty invocation proxy.
+ @result Invocation proxy
+ */
++ (id)invocation;
+
+/*!
+ Create invocation proxy with target.
+ @param target
+ @result Invocation proxy
+ */
+- (id)prepareWithInvocationTarget:(id)target;
+
+@end
View
59 Libraries/GHUnit.framework/Versions/A/Headers/GHNSLocale+Mock.h
@@ -0,0 +1,59 @@
+//
+// GHNSLocale+Mock.h
+// GHUnit
+//
+// Created by Gabriel Handford on 4/13/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+/*!
+ Category for overriding the current locale at runtime.
+
+ @code
+ #import "GHNSLocale+Mock.h"
+ // This aliases the currentLocale method and with the specified locale identifier
+ [NSLocale gh_setLocaleIdentifier:@"en_GB"];
+
+ [[NSLocale currentLocale] localeIdentifier] == "en_GB"
+ @endcode
+ */
+@interface NSLocale (GHMock)
+
++ (void)gh_setLocaleIdentifier:(NSString *)localeIdentifier;
+
+/*!
+ Aliases to currentLocale with locale set from gh_setLocaleIdentifier.
+ If not set, defaults to NSLocale with identifier en_US.
+ */
++ (NSLocale *)gh_currentLocale;
+
++ (void)gh_setPreferredLanguages:(NSArray *)preferredLanguages;
+
+/*!
+ Aliases to preferredLanguages set from gh_setPreferredLanguages.
+ If not set, defaults to [@"en"].
+ */
++ (NSArray *)gh_preferredLanguages;
+
+@end
View
100 Libraries/GHUnit.framework/Versions/A/Headers/GHNSObject+Invocation.h
@@ -0,0 +1,100 @@
+//
+// GHNSObject+Invocation.h
+// GHKit
+//
+// Created by Gabriel Handford on 1/18/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import "GHNSInvocation+Utils.h"
+#import "GHNSInvocationProxy.h"
+
+/*!
+ Adds performSelector methods that take a nil-terminated variable argument list,
+ for when you need to pass more arguments to performSelector.
+ */
+@interface NSObject (GHInvocation_GHUNIT)
+
+/*!
+ Perform selector if responds.
+ @param selector
+ @result nil if we don't respond to the selector, otherwise the selector result
+ */
+- (id)ghu_performIfRespondsToSelector:(SEL)selector;
+
+/*!
+ Perform selector if responds with multiple arguments.
+ @param selector
+ @param withObjects nil terminated variable argument list
+ @result nil if we don't respond to the selector, otherwise the selector result
+ */
+- (id)ghu_performIfRespondsToSelector:(SEL)selector withObjects:object, ...;
+
+/*!
+ Invoke selector with arguments.
+ @param selector
+ @param withObjects nil terminated variable argument list
+ */
+- (id)ghu_performSelector:(SEL)selector withObjects:object, ...;
+
+- (id)ghu_performSelector:(SEL)selector afterDelay:(NSTimeInterval)delay withObjects:object, ...;
+
+/*!
+ Invoke selector with arguments on main thread.
+ Does not wait until selector is finished.
+ @param selector
+ @param withObjects nil terminated variable argument list
+ */
+- (void)ghu_performSelectorOnMainThread:(SEL)selector withObjects:object, ...;
+
+/*!
+ Invoke selector with arguments on main thread.
+ @param selector
+ @param waitUntilDone Whether to join on selector and wait for it to finish.
+ @param withObjects nil terminated variable argument list
+ */
+- (void)ghu_performSelectorOnMainThread:(SEL)selector waitUntilDone:(BOOL)waitUntilDone withObjects:object, ...;
+
+
+- (void)ghu_performSelector:(SEL)selector onMainThread:(BOOL)onMainThread waitUntilDone:(BOOL)waitUntilDone withObjects:object, ...;
+
+- (void)ghu_performSelector:(SEL)selector onMainThread:(BOOL)onMainThread waitUntilDone:(BOOL)waitUntilDone arguments:(NSArray *)arguments;
+
+- (void)ghu_performSelector:(SEL)selector onMainThread:(BOOL)onMainThread waitUntilDone:(BOOL)waitUntilDone
+ afterDelay:(NSTimeInterval)delay arguments:(NSArray *)arguments;
+
+
+// Invocation proxies
+
+- (id)ghu_proxyOnMainThread;
+- (id)ghu_proxyOnMainThread:(BOOL)waitUntilDone;
+- (id)ghu_proxyOnThread:(NSThread *)thread;
+- (id)ghu_proxyOnThread:(NSThread *)thread waitUntilDone:(BOOL)waitUntilDone;
+- (id)ghu_proxyAfterDelay:(NSTimeInterval)delay;
+
+// Debug proxies
+- (id)ghu_timedProxy:(NSTimeInterval *)time;
+- (id)ghu_debugProxy:(NSTimeInterval *)time proxy:(GHNSInvocationProxy_GHUNIT **)proxy;
+
+@end
View
40 Libraries/GHUnit.framework/Versions/A/Headers/GHTest+JUnitXML.h
@@ -0,0 +1,40 @@
+//
+// GHTest+JUnitXML.h
+// GHUnit
+//
+// Created by Gabriel Handford on 6/4/10.
+// Copyright 2010. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import "GHTest.h"
+
+@interface GHTest (JUnitXML)
+
+/*!
+ Return test results in JUnit XML format for external parsing use
+ (such as a Continuous Integration system like Hudson)
+ */
+- (NSString *)JUnitXML;
+
+@end
View
181 Libraries/GHUnit.framework/Versions/A/Headers/GHTest.h
@@ -0,0 +1,181 @@
+//
+// GHTest.h
+// GHKit
+//
+// Created by Gabriel Handford on 1/18/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+/*!
+ Test status.
+ */
+typedef enum {
+ GHTestStatusNone = 0,
+ GHTestStatusRunning, // Test is running
+ GHTestStatusCancelling, // Test is being cancelled
+ GHTestStatusCancelled, // Test was cancelled
+ GHTestStatusSucceeded, // Test finished and succeeded
+ GHTestStatusErrored, // Test finished and errored
+} GHTestStatus;
+
+enum {
+ GHTestOptionReraiseExceptions = 1 << 0, // Allows exceptions to be raised (so you can trigger the debugger)
+ GHTestOptionForceSetUpTearDownClass = 1 << 1, // Runs setUpClass/tearDownClass for this (each) test; Used when re-running a single test in a group
+};
+typedef NSInteger GHTestOptions;
+
+/*!
+ Generate string from GHTestStatus
+ @param status
+ */
+extern NSString* NSStringFromGHTestStatus(GHTestStatus status);
+
+/*!
+ Check if test is running (or trying to cancel).
+ */
+extern BOOL GHTestStatusIsRunning(GHTestStatus status);
+
+/*!
+ Check if test has succeeded, errored or cancelled.
+ */
+extern BOOL GHTestStatusEnded(GHTestStatus status);
+
+/*!
+ Test stats.
+ */
+typedef struct {
+ NSInteger succeedCount; // Number of succeeded tests
+ NSInteger failureCount; // Number of failed tests
+ NSInteger cancelCount; // Number of aborted tests
+ NSInteger testCount; // Total number of tests
+} GHTestStats;
+
+/*!
+ Create GHTestStats.
+ */
+extern GHTestStats GHTestStatsMake(NSInteger succeedCount, NSInteger failureCount, NSInteger cancelCount, NSInteger testCount);
+
+extern const GHTestStats GHTestStatsEmpty;
+
+extern NSString *NSStringFromGHTestStats(GHTestStats stats);
+
+@protocol GHTestDelegate;
+
+/*!
+ The base interface for a runnable test.
+ A runnable with a unique identifier, display name, stats, timer, delegate, log and error handling.
+ */
+@protocol GHTest <NSObject, NSCoding, NSCopying>
+
+- (void)run:(GHTestOptions)options;
+
+@property (readonly, nonatomic) NSString *identifier; // Unique identifier for test
+@property (readonly, nonatomic) NSString *name;
+@property (assign, nonatomic) NSTimeInterval interval;
+@property (assign, nonatomic) GHTestStatus status;
+@property (readonly, nonatomic) GHTestStats stats;
+@property (retain, nonatomic) NSException *exception;
+@property (assign, nonatomic, getter=isDisabled) BOOL disabled;
+@property (assign, nonatomic, getter=isHidden) BOOL hidden;
+@property (assign, nonatomic) id<GHTestDelegate> delegate; // weak
+
+- (NSArray *)log;
+
+- (void)reset;
+- (void)cancel;
+
+- (NSInteger)disabledCount;
+
+@end
+
+/*!
+ Test delegate for notification when a test starts and ends.
+ */
+@protocol GHTestDelegate <NSObject>
+- (void)testDidStart:(id<GHTest>)test source:(id<GHTest>)source;
+- (void)testDidUpdate:(id<GHTest>)test source:(id<GHTest>)source;
+- (void)testDidEnd:(id<GHTest>)test source:(id<GHTest>)source;
+- (void)test:(id<GHTest>)test didLog:(NSString *)message source:(id<GHTest>)source;
+@end
+
+/*!
+ Delegate which is notified of log messages from inside GHTestCase.
+ */
+@protocol GHTestCaseLogWriter <NSObject>
+- (void)log:(NSString *)message testCase:(id)testCase;
+@end
+
+/*!
+ Default test implementation with a target/selector pair.
+ - Tests a target and selector
+ - Notifies a test delegate
+ - Keeps track of status, running time and failures
+ - Stores any test specific logging
+ */
+@interface GHTest : NSObject <GHTest, GHTestCaseLogWriter> {
+
+ NSObject<GHTestDelegate> *delegate_; // weak
+
+ id target_;
+ SEL selector_;
+
+ NSString *identifier_;
+ NSString *name_;
+ GHTestStatus status_;
+ NSTimeInterval interval_;
+ BOOL disabled_;
+ BOOL hidden_;
+ NSException *exception_; // If failed
+
+ NSMutableArray *log_;
+
+}
+
+@property (readonly, nonatomic) id target;
+@property (readonly, nonatomic) SEL selector;
+@property (readonly, nonatomic) NSArray *log;
+
+/*!
+ Create test with identifier, name.
+ @param identifier Unique identifier
+ @param name Name
+ */
+- (id)initWithIdentifier:(NSString *)identifier name:(NSString *)name;
+
+/*!
+ Create test with target/selector.
+ @param target Target (usually a test case)
+ @param selector Selector (usually a test method)
+ */
+- (id)initWithTarget:(id)target selector:(SEL)selector;
+
+/*!
+ Create autoreleased test with target/selector.
+ @param target Target (usually a test case)
+ @param selector Selector (usually a test method)
+ */
++ (id)testWithTarget:(id)target selector:(SEL)selector;
+
+@end
+
View
23 Libraries/GHUnit.framework/Versions/A/Headers/GHTestApp.h
@@ -0,0 +1,23 @@
+//
+// GHTestApp.h
+// GHUnit
+//
+// Created by Gabriel Handford on 1/20/09.
+// Copyright 2009. All rights reserved.
+//
+
+#import "GHTestWindowController.h"
+
+@interface GHTestApp : NSObject {
+ NSMutableArray *topLevelObjects_;
+
+ GHTestWindowController *windowController_;
+
+ GHTestSuite *suite_;
+}
+
+- (id)initWithSuite:(GHTestSuite *)suite;
+
+- (void)runTests;
+
+@end
View
141 Libraries/GHUnit.framework/Versions/A/Headers/GHTestCase.h
@@ -0,0 +1,141 @@
+//
+// GHTestCase.h
+// GHUnit
+//
+// Created by Gabriel Handford on 1/21/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+//
+// Portions of this file fall under the following license, marked with:
+// GTM_BEGIN : GTM_END
+//
+// Copyright 2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GHTestMacros.h"
+#import "GHTest.h"
+
+// Log to your test case logger.
+// For example, GHTestLog(@"Some debug info, %@", obj)
+#define GHTestLog(...) [self log:[NSString stringWithFormat:__VA_ARGS__, nil]]
+
+/*!
+ The base class for a test case.
+
+ @code
+ @interface MyTest : GHTestCase {}
+ @end
+
+ @implementation MyTest
+
+ // Run before each test method
+ - (void)setUp { }
+
+ // Run after each test method
+ - (void)tearDown { }
+
+ // Run before the tests are run for this class
+ - (void)setUpClass { }
+
+ // Run before the tests are run for this class
+ - (void)tearDownClass { }
+
+ // Tests are prefixed by 'test' and contain no arguments and no return value
+ - (void)testA {
+ GHTestLog(@"Log with a test with the GHTestLog(...) for test specific logging.");
+ }
+
+ // Another test; Tests are run in lexical order
+ - (void)testB { }
+
+ // Override any exceptions; By default exceptions are raised, causing a test failure
+ - (void)failWithException:(NSException *)exception { }
+
+ @end
+ @endcode
+
+ */
+@interface GHTestCase : NSObject {
+ id<GHTestCaseLogWriter> logWriter_; // weak
+
+ SEL currentSelector_;
+}
+
+//! The current test selector
+@property (assign, nonatomic) SEL currentSelector;
+@property (assign, nonatomic) id<GHTestCaseLogWriter> logWriter;
+
+// GTM_BEGIN
+//! Run before each test method
+- (void)setUp;
+
+//! Run after each test method
+- (void)tearDown;
+
+/*!
+ By default exceptions are raised, causing a test failure
+ @brief Override any exceptions
+ @param exception Exception that was raised by test
+ */
+- (void)failWithException:(NSException*)exception;
+// GTM_END
+
+//! Run before the tests (once per test case)
+- (void)setUpClass;
+
+//! Run after the tests (once per test case)
+- (void)tearDownClass;
+
+/*!
+ Whether to run the tests on a separate thread. Override this method in your
+ test case to override the default.
+ Default is NO, tests are run on a separate thread by default.
+ @result If YES runs on the main thread
+ */
+- (BOOL)shouldRunOnMainThread;
+
+//! Any special handling of exceptions after they are thrown; By default logs stack trace to standard out.
+- (void)handleException:(NSException *)exception;
+
+/*!
+ Log a message, which notifies the log delegate.
+ This is not meant to be used directly, see GHTestLog(...) macro.
+ @param message
+ */
+- (void)log:(NSString *)message;
+
+@end
View
38 Libraries/GHUnit.framework/Versions/A/Headers/GHTestGroup+JUnitXML.h
@@ -0,0 +1,38 @@
+//
+// GHTestGroup+JUnitXML.h
+// GHUnit
+//
+// Created by Gabriel Handford on 6/4/10.
+// Copyright 2010. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import "GHTestGroup.h"
+
+@interface GHTestGroup (JUnitXML)
+
+- (NSString *)JUnitXML;
+
+- (BOOL)writeJUnitXMLAtPath:(NSString *)documentsPath error:(NSError **)error;
+
+@end
View
151 Libraries/GHUnit.framework/Versions/A/Headers/GHTestGroup.h
@@ -0,0 +1,151 @@
+//
+// GHTestGroup.h
+//
+// Created by Gabriel Handford on 1/16/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#import "GHTest.h"
+#import "GHTestCase.h"
+
+/*!
+ @brief Interface for a group of tests.
+
+ This group conforms to the GHTest protocol as well (see Composite pattern).
+ */
+@protocol GHTestGroup <GHTest>
+- (NSString *)name;
+- (id<GHTestGroup>)parent;
+- (NSArray *)children;
+@end
+
+/*!
+ @brief A collection of tests (or test groups).
+
+ A test group is a collection of id<GHTest>, that may represent a set of test case methods.
+
+ For example, if you had the following GHTestCase.
+
+ @code
+ @interface FooTest : GHTestCase {}
+ - (void)testFoo;
+ - (void)testBar;
+ @end
+ @endcode
+
+ The GHTestGroup would consist of and array of GHTest, [FooTest#testFoo and FooTest#testBar],
+ each test being a target and selector pair.
+
+ A test group may also consist of a group of groups (since GHTestGroup conforms to GHTest),
+ and this might represent a GHTestSuite.
+ */
+@interface GHTestGroup : NSObject <GHTestDelegate, GHTestGroup> {
+
+ NSObject<GHTestDelegate> *delegate_; // weak
+ id<GHTestGroup> parent_; // weak
+
+ NSMutableArray */*of id<GHTest>*/children_;
+
+ NSString *name_; // The name of the test group (usually the class name of the test case
+ NSTimeInterval interval_; // Total time of child tests
+ GHTestStatus status_; // Current status of the group (current status of running or completed child tests)
+ GHTestStats stats_; // Current stats for the group (aggregate of child test stats)
+
+ BOOL didSetUpClass_;
+
+ GHTestOptions options_;
+
+ // Set if test is created from initWithTestCase:delegate:
+ // Allows use to perform setUpClass and tearDownClass (once per test case run)
+ id testCase_;
+
+ NSException *exception_; // If exception happens in group setUpClass/tearDownClass
+}
+
+@property (readonly, nonatomic) NSArray */*of id<GHTest>*/children;
+@property (assign, nonatomic) id<GHTestGroup> parent;
+@property (readonly, nonatomic) id testCase;
+@property (assign, nonatomic) GHTestOptions options;
+
+/*!
+ Create an empty test group.
+ @param name The name of the test group
+ @param delegate Delegate, notifies of test start and end
+ @result New test group
+ */
+- (id)initWithName:(NSString *)name delegate:(id<GHTestDelegate>)delegate;
+
+/*!
+ Create test group from a test case.
+ @param testCase Test case, could be a subclass of SenTestCase or GHTestCase
+ @param delegate Delegate, notifies of test start and end
+ @result New test group
+ */
+- (id)initWithTestCase:(id)testCase delegate:(id<GHTestDelegate>)delegate;
+
+/*!
+ Create test group from a single test.
+ @param testCase
+ @param selector Test to run
+ @param delegate
+ */
+- (id)initWithTestCase:(id)testCase selector:(SEL)selector delegate:(id<GHTestDelegate>)delegate;
+
+/*!
+ Create test group from a test case.
+ @param testCase Test case, could be a subclass of SenTestCase or GHTestCase
+ @param delegate Delegate, notifies of test start and end
+ @result New test group
+ */
++ (GHTestGroup *)testGroupFromTestCase:(id)testCase delegate:(id<GHTestDelegate>)delegate;
+
+/*!
+ Add a test case (or test group) to this test group.
+ @param testCase Test case, could be a subclass of SenTestCase or GHTestCase
+ */
+- (void)addTestCase:(id)testCase;
+
+- (void)addTestGroup:(GHTestGroup *)testGroup;
+
+- (void)addTests:(NSArray */*of id<GHTest>*/)tests;
+
+- (void)addTest:(id<GHTest>)test;
+
+- (BOOL)shouldRunOnMainThread;
+
+/*!
+ Get list of failed tests.
+ @result Failed tests
+ */
+- (NSArray */*of id<GHTest>*/)failedTests;
+
+/*!
+ Run in operation queue.
+ Tests from the group are added and will block until they have completed.
+ @param operationQueue If nil, then runs as is
+ @param options Options
+ */
+- (void)runInOperationQueue:(NSOperationQueue *)operationQueue options:(GHTestOptions)options;
+
+@end
View
1,010 Libraries/GHUnit.framework/Versions/A/Headers/GHTestMacros.h
@@ -0,0 +1,1010 @@
+//
+// GHTestMacros.h
+//
+// Created by Gabriel Handford on 1/17/09.
+// Copyright 2009. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+//
+// Portions of this file fall under the following license, marked with
+// SENTE_BEGIN - SENTE_END
+//
+// Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved.
+//
+// Use of this source code is governed by the following license:
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// (1) Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// (2) Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL Sente SA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Note: this license is equivalent to the FreeBSD license.
+//
+// This notice may not be removed from this file.
+
+//
+// Portions of this file fall under the following license, marked with:
+// GTM_BEGIN : GTM_END
+//
+// Copyright 2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "NSException+GHTestFailureExceptions.h"
+#import "NSValue+GHValueFormatter.h"
+
+// GTM_BEGIN
+
+extern NSString *const GHTestFilenameKey;
+extern NSString *const GHTestLineNumberKey;
+extern NSString *const GHTestFailureException;
+
+#if defined(__cplusplus)
+extern "C"
+#endif
+NSString *GHComposeString(NSString *, ...);
+
+// Generates a failure when a1 != noErr
+// Args:
+// a1: should be either an OSErr or an OSStatus
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNoErr(a1, description, ...) \
+do { \
+@try {\
+OSStatus a1value = (a1); \
+if (a1value != noErr) { \
+NSString *_expression = [NSString stringWithFormat:@"Expected noErr, got %ld for (%s)", a1value, #a1]; \
+if (description) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(description, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+} \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat:@"(%s) == noErr fails", #a1] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when a1 != a2
+// Args:
+// a1: received value. Should be either an OSErr or an OSStatus
+// a2: expected value. Should be either an OSErr or an OSStatus
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertErr(a1, a2, description, ...) \
+do { \
+@try {\
+OSStatus a1value = (a1); \
+OSStatus a2value = (a2); \
+if (a1value != a2value) { \
+NSString *_expression = [NSString stringWithFormat:@"Expected %s(%ld) but got %ld for (%s)", #a2, a2value, a1value, #a1]; \
+if (description) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(description, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+} \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat:@"(%s) == (%s) fails", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+
+// Generates a failure when a1 is NULL
+// Args:
+// a1: should be a pointer (use GHAssertNotNil for an object)
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNotNULL(a1, description, ...) \
+do { \
+@try {\
+const void* a1value = (a1); \
+if (a1value == NULL) { \
+NSString *_expression = [NSString stringWithFormat:@"(%s) != NULL", #a1]; \
+if (description) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(description, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+} \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat:@"(%s) != NULL fails", #a1] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when a1 is not NULL
+// Args:
+// a1: should be a pointer (use GHAssertNil for an object)
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNULL(a1, description, ...) \
+do { \
+@try {\
+const void* a1value = (a1); \
+if (a1value != NULL) { \
+NSString *_expression = [NSString stringWithFormat:@"(%s) == NULL", #a1]; \
+if (description) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(description, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+} \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat:@"(%s) == NULL fails", #a1] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when a1 is equal to a2. This test is for C scalars,
+// structs and unions.
+// Args:
+// a1: argument 1
+// a2: argument 2
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNotEquals(a1, a2, description, ...) \
+do { \
+@try {\
+if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:[@"Type mismatch -- " stringByAppendingString:GHComposeString(description, ##__VA_ARGS__)]]]; \
+} else { \
+__typeof__(a1) a1value = (a1); \
+__typeof__(a2) a2value = (a2); \
+NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \
+NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \
+if ([a1encoded isEqualToValue:a2encoded]) { \
+NSString *_expression = [NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2]; \
+if (description) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(description, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+} \
+} \
+} \
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when a1 is equal to a2. This test is for objects.
+// Args:
+// a1: argument 1. object.
+// a2: argument 2. object.
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNotEqualObjects(a1, a2, desc, ...) \
+do { \
+@try {\
+id a1value = (a1); \
+id a2value = (a2); \
+if ( (@encode(__typeof__(a1value)) == @encode(id)) && \
+(@encode(__typeof__(a2value)) == @encode(id)) && \
+![(id)a1value isEqual:(id)a2value] ) continue; \
+NSString *_expression = [NSString stringWithFormat:@"%s('%@') != %s('%@')", #a1, [a1 description], #a2, [a2 description]]; \
+if (desc) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(desc, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(desc, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when a1 is not 'op' to a2. This test is for C scalars.
+// Args:
+// a1: argument 1
+// a2: argument 2
+// op: operation
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertOperation(a1, a2, op, description, ...) \
+do { \
+@try {\
+if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:[@"Type mismatch -- " stringByAppendingString:GHComposeString(description, ##__VA_ARGS__)]]]; \
+} else { \
+__typeof__(a1) a1value = (a1); \
+__typeof__(a2) a2value = (a2); \
+if (!(a1value op a2value)) { \
+double a1DoubleValue = a1value; \
+double a2DoubleValue = a2value; \
+NSString *_expression = [NSString stringWithFormat:@"%s (%lg) %s %s (%lg)", #a1, a1DoubleValue, #op, #a2, a2DoubleValue]; \
+if (description) { \
+_expression = [NSString stringWithFormat:@"%@: %@", _expression, GHComposeString(description, ##__VA_ARGS__)]; \
+} \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:_expression]]; \
+} \
+} \
+} \
+@catch (id anException) {\
+[self failWithException:[NSException \
+ghu_failureInRaise:[NSString stringWithFormat:@"(%s) %s (%s)", #a1, #op, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when a1 is not > a2. This test is for C scalars.
+// Args:
+// a1: argument 1
+// a2: argument 2
+// op: operation
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertGreaterThan(a1, a2, description, ...) \
+GHAssertOperation(a1, a2, >, description, ##__VA_ARGS__)
+
+// Generates a failure when a1 is not >= a2. This test is for C scalars.
+// Args:
+// a1: argument 1
+// a2: argument 2
+// op: operation
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertGreaterThanOrEqual(a1, a2, description, ...) \
+GHAssertOperation(a1, a2, >=, description, ##__VA_ARGS__)
+
+// Generates a failure when a1 is not < a2. This test is for C scalars.
+// Args:
+// a1: argument 1
+// a2: argument 2
+// op: operation
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertLessThan(a1, a2, description, ...) \
+GHAssertOperation(a1, a2, <, description, ##__VA_ARGS__)
+
+// Generates a failure when a1 is not <= a2. This test is for C scalars.
+// Args:
+// a1: argument 1
+// a2: argument 2
+// op: operation
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertLessThanOrEqual(a1, a2, description, ...) \
+GHAssertOperation(a1, a2, <=, description, ##__VA_ARGS__)
+
+// Generates a failure when string a1 is not equal to string a2. This call
+// differs from GHAssertEqualObjects in that strings that are different in
+// composition (precomposed vs decomposed) will compare equal if their final
+// representation is equal.
+// ex O + umlaut decomposed is the same as O + umlaut composed.
+// Args:
+// a1: string 1
+// a2: string 2
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertEqualStrings(a1, a2, description, ...) \
+do { \
+@try {\
+id a1value = (a1); \
+id a2value = (a2); \
+if (a1value == a2value) continue; \
+if ([a1value isKindOfClass:[NSString class]] && \
+[a2value isKindOfClass:[NSString class]] && \
+[a1value compare:a2value options:0] == NSOrderedSame) continue; \
+[self failWithException:[NSException ghu_failureInEqualityBetweenObject: a1value \
+andObject: a2value \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when string a1 is equal to string a2. This call
+// differs from GHAssertEqualObjects in that strings that are different in
+// composition (precomposed vs decomposed) will compare equal if their final
+// representation is equal.
+// ex O + umlaut decomposed is the same as O + umlaut composed.
+// Args:
+// a1: string 1
+// a2: string 2
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNotEqualStrings(a1, a2, description, ...) \
+do { \
+@try {\
+id a1value = (a1); \
+id a2value = (a2); \
+if ([a1value isKindOfClass:[NSString class]] && \
+[a2value isKindOfClass:[NSString class]] && \
+[a1value compare:a2value options:0] != NSOrderedSame) continue; \
+[self failWithException:[NSException ghu_failureInEqualityBetweenObject: a1value \
+andObject: a2value \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when c-string a1 is not equal to c-string a2.
+// Args:
+// a1: string 1
+// a2: string 2
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertEqualCStrings(a1, a2, description, ...) \
+do { \
+@try {\
+const char* a1value = (a1); \
+const char* a2value = (a2); \
+if (a1value == a2value) continue; \
+if (strcmp(a1value, a2value) == 0) continue; \
+[self failWithException:[NSException ghu_failureInEqualityBetweenObject: [NSString stringWithUTF8String:a1value] \
+andObject: [NSString stringWithUTF8String:a2value] \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// Generates a failure when c-string a1 is equal to c-string a2.
+// Args:
+// a1: string 1
+// a2: string 2
+// description: A format string as in the printf() function. Can be nil or
+// an empty string but must be present.
+// ...: A variable number of arguments to the format string. Can be absent.
+#define GHAssertNotEqualCStrings(a1, a2, description, ...) \
+do { \
+@try {\
+const char* a1value = (a1); \
+const char* a2value = (a2); \
+if (strcmp(a1value, a2value) != 0) continue; \
+[self failWithException:[NSException ghu_failureInEqualityBetweenObject: [NSString stringWithUTF8String:a1value] \
+andObject: [NSString stringWithUTF8String:a2value] \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) != (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+// GTM_END
+
+// SENTE_BEGIN
+/*" Generates a failure when !{ [a1 isEqualTo:a2] } is false
+ (or one is nil and the other is not).
+ _{a1 The object on the left.}
+ _{a2 The object on the right.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertEqualObjects(a1, a2, description, ...) \
+do { \
+@try {\
+id a1value = (a1); \
+id a2value = (a2); \
+if (a1value == a2value) continue; \
+if ( (strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \
+(strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \
+[(id)a1value isEqual: (id)a2value] ) continue; \
+[self failWithException:[NSException ghu_failureInEqualityBetweenObject: a1value \
+andObject: a2value \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+
+/*" Generates a failure when a1 is not equal to a2. This test is for
+ C scalars, structs and unions.
+ _{a1 The argument on the left.}
+ _{a2 The argument on the right.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertEquals(a1, a2, description, ...) \
+do { \
+@try {\
+if ( strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2))) != 0 ) { \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:[@"Type mismatch -- " stringByAppendingString:GHComposeString(description, ##__VA_ARGS__)]]]; \
+} else { \
+__typeof__(a1) a1value = (a1); \
+__typeof__(a2) a2value = (a2); \
+NSValue *a1encoded = [NSValue value:&a1value withObjCType: @encode(__typeof__(a1))]; \
+NSValue *a2encoded = [NSValue value:&a2value withObjCType: @encode(__typeof__(a2))]; \
+if (![a1encoded isEqualToValue:a2encoded]) { \
+[self failWithException:[NSException ghu_failureInEqualityBetweenValue: a1encoded \
+andValue: a2encoded \
+withAccuracy: nil \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+} \
+} \
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+#define GHAbsoluteDifference(left,right) (MAX(left,right)-MIN(left,right))
+
+
+/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false.
+ This test is for scalars such as floats and doubles where small differences
+ could make these items not exactly equal, but also works for all scalars.
+ _{a1 The scalar on the left.}
+ _{a2 The scalar on the right.}
+ _{accuracy The maximum difference between a1 and a2 for these values to be
+ considered equal.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+
+#define GHAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...) \
+do { \
+@try {\
+if (@encode(__typeof__(a1)) != @encode(__typeof__(a2))) { \
+[self failWithException:[NSException ghu_failureInFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:[@"Type mismatch -- " stringByAppendingString:GHComposeString(description, ##__VA_ARGS__)]]]; \
+} else { \
+__typeof__(a1) a1value = (a1); \
+__typeof__(a2) a2value = (a2); \
+__typeof__(accuracy) accuracyvalue = (accuracy); \
+if (GHAbsoluteDifference(a1value, a2value) > accuracyvalue) { \
+NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \
+NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \
+NSValue *accuracyencoded = [NSValue value:&accuracyvalue withObjCType:@encode(__typeof__(accuracy))]; \
+[self failWithException:[NSException ghu_failureInEqualityBetweenValue: a1encoded \
+andValue: a2encoded \
+withAccuracy: accuracyencoded \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+} \
+} \
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) == (%s)", #a1, #a2] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+
+
+/*" Generates a failure unconditionally.
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHFail(description, ...) \
+[self failWithException:[NSException ghu_failureInFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]
+
+
+
+/*" Generates a failure when a1 is not nil.
+ _{a1 An object.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertNil(a1, description, ...) \
+do { \
+@try {\
+id a1value = (a1); \
+if (a1value != nil) { \
+NSString *_a1 = [NSString stringWithUTF8String: #a1]; \
+NSString *_expression = [NSString stringWithFormat:@"((%@) == nil)", _a1]; \
+[self failWithException:[NSException ghu_failureInCondition: _expression \
+isTrue: NO \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) == nil fails", #a1] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+
+/*" Generates a failure when a1 is nil.
+ _{a1 An object.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertNotNil(a1, description, ...) \
+do { \
+@try {\
+id a1value = (a1); \
+if (a1value == nil) { \
+NSString *_a1 = [NSString stringWithUTF8String: #a1]; \
+NSString *_expression = [NSString stringWithFormat:@"((%@) != nil)", _a1]; \
+[self failWithException:[NSException ghu_failureInCondition: _expression \
+isTrue: NO \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+}\
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) != nil fails", #a1] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while(0)
+
+
+/*" Generates a failure when expression evaluates to false.
+ _{expr The expression that is tested.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertTrue(expr, description, ...) \
+do { \
+BOOL _evaluatedExpression = (expr);\
+if (!_evaluatedExpression) {\
+NSString *_expression = [NSString stringWithUTF8String: #expr];\
+[self failWithException:[NSException ghu_failureInCondition: _expression \
+isTrue: YES \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+} while (0)
+
+
+/*" Generates a failure when expression evaluates to false and in addition will
+ generate error messages if an exception is encountered.
+ _{expr The expression that is tested.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertTrueNoThrow(expr, description, ...) \
+do { \
+@try {\
+BOOL _evaluatedExpression = (expr);\
+if (!_evaluatedExpression) {\
+NSString *_expression = [NSString stringWithUTF8String: #expr];\
+[self failWithException:[NSException ghu_failureInCondition: _expression \
+isTrue: NO \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+} \
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"(%s) ", #expr] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while (0)
+
+
+/*" Generates a failure when the expression evaluates to true.
+ _{expr The expression that is tested.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertFalse(expr, description, ...) \
+do { \
+BOOL _evaluatedExpression = (expr);\
+if (_evaluatedExpression) {\
+NSString *_expression = [NSString stringWithUTF8String: #expr];\
+[self failWithException:[NSException ghu_failureInCondition: _expression \
+isTrue: NO \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+} while (0)
+
+
+/*" Generates a failure when the expression evaluates to true and in addition
+ will generate error messages if an exception is encountered.
+ _{expr The expression that is tested.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertFalseNoThrow(expr, description, ...) \
+do { \
+@try {\
+BOOL _evaluatedExpression = (expr);\
+if (_evaluatedExpression) {\
+NSString *_expression = [NSString stringWithUTF8String: #expr];\
+[self failWithException:[NSException ghu_failureInCondition: _expression \
+isTrue: YES \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} \
+} \
+@catch (id anException) {\
+[self failWithException:[NSException ghu_failureInRaise:[NSString stringWithFormat: @"!(%s) ", #expr] \
+exception:anException \
+inFile:[NSString stringWithUTF8String:__FILE__] \
+atLine:__LINE__ \
+withDescription:GHComposeString(description, ##__VA_ARGS__)]]; \
+}\
+} while (0)
+
+
+/*" Generates a failure when expression does not throw an exception.
+ _{expression The expression that is evaluated.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.
+ "*/
+#define GHAssertThrows(expr, description, ...) \
+do { \
+@try { \
+(expr);\
+} \
+@catch (id anException) { \
+continue; \
+}\
+[self failWithException:[NSException ghu_failureInRaise: [NSString stringWithUTF8String:#expr] \
+exception: nil \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(description, ##__VA_ARGS__)]]; \
+} while (0)
+
+
+/*" Generates a failure when expression does not throw an exception of a
+ specific class.
+ _{expression The expression that is evaluated.}
+ _{specificException The specified class of the exception.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}
+ _{... A variable number of arguments to the format string. Can be absent.}
+ "*/
+#define GHAssertThrowsSpecific(expr, specificException, description, ...) \
+do { \
+@try { \
+(expr);\
+} \
+@catch (specificException *anException) { \
+continue; \
+}\
+@catch (id anException) {\
+NSString *_descrip = GHComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description);\
+[self failWithException:[NSException ghu_failureInRaise: [NSString stringWithUTF8String:#expr] \
+exception: anException \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(_descrip, ##__VA_ARGS__)]]; \
+continue; \
+}\
+NSString *_descrip = GHComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description);\
+[self failWithException:[NSException ghu_failureInRaise: [NSString stringWithUTF8String:#expr] \
+exception: nil \
+inFile: [NSString stringWithUTF8String:__FILE__] \
+atLine: __LINE__ \
+withDescription: GHComposeString(_descrip, ##__VA_ARGS__)]]; \
+} while (0)
+
+
+/*" Generates a failure when expression does not throw an exception of a
+ specific class with a specific name. Useful for those frameworks like
+ AppKit or Foundation that throw generic NSException w/specific names
+ (NSInvalidArgumentException, etc).
+ _{expression The expression that is evaluated.}
+ _{specificException The specified class of the exception.}
+ _{aName The name of the specified exception.}
+ _{description A format string as in the printf() function. Can be nil or
+ an empty string but must be present.}