@@ -0,0 +1,173 @@
//
// 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.
//

//! @cond DEV

#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;

/*!
Send data to connection delegate.
@param data Data to send
@param statusCode HTTP status code
@param MIMEType Mime type
@param afterDelay 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

//! @endcond
@@ -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
@@ -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
@@ -0,0 +1,63 @@
//
// 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.
//

//! @cond DEV

/*!
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

//! @endcond
@@ -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
@@ -0,0 +1,44 @@
//
// 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.
//

//! @cond DEV

#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

//! @endcond
@@ -0,0 +1,184 @@
//
// GHTest.h
// GHUnit
//
// 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.
//

//! @cond DEV

/*!
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

//! @endcond
@@ -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
@@ -0,0 +1,146 @@
//
// 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,
@code
GHTestLog(@"Some debug info, %@", obj);
@endcode
*/
#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
@@ -0,0 +1,42 @@
//
// 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.
//

//! @cond DEV

#import "GHTestGroup.h"

@interface GHTestGroup(JUnitXML)

- (NSString *)JUnitXML;

- (BOOL)writeJUnitXMLAtPath:(NSString *)documentsPath error:(NSError **)error;

@end

//! @endcond
@@ -0,0 +1,176 @@
//
// 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.
//

//! @cond DEV

#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;

/*!
Add a test group to this test group.
@param testGroup Test group to add
*/
- (void)addTestGroup:(GHTestGroup *)testGroup;

/*!
Add tests to this group.
@param tests Tests to add
*/
- (void)addTests:(NSArray */*of id<GHTest>*/)tests;

/*!
Add test to this group.
@param test Test to add
*/
- (void)addTest:(id<GHTest>)test;

/*!
Whether the test group should run on the main thread.
Call passes to test case instance if enabled.
*/
- (BOOL)shouldRunOnMainThread;

/*!
@result YES if we have any enabled chilren, NO if all children have been disabled.
*/
- (BOOL)hasEnabledChildren;

/*!
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

//! @endcond

Large diffs are not rendered by default.

@@ -0,0 +1,46 @@
//
// GHTestOperation.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.
//

//! @cond DEV

#import "GHTest.h"

/*!
Test for running in the context of an NSOperationQueue.
*/
@interface GHTestOperation : NSOperation {
id<GHTest> test_;
GHTestOptions options_;
}

- (id)initWithTest:(id<GHTest>)test options:(GHTestOptions)options;

@end

//! @endcond
@@ -0,0 +1,31 @@
//
// GHTestOutlineViewModel.h
// GHUnit
//
// Created by Gabriel Handford on 7/17/09.
// Copyright 2009. All rights reserved.
//

#import "GHTestViewModel.h"
@class GHTestOutlineViewModel;


@protocol GHTestOutlineViewModelDelegate <NSObject>
- (void)testOutlineViewModelDidChangeSelection:(GHTestOutlineViewModel *)testOutlineViewModel;
@end



@interface GHTestOutlineViewModel : GHTestViewModel
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 // on lines like this to not confuse IB
<NSOutlineViewDelegate, NSOutlineViewDataSource>
#endif
{
id<GHTestOutlineViewModelDelegate> delegate_; // weak

NSButtonCell *editCell_;
}

@property (assign, nonatomic) id<GHTestOutlineViewModelDelegate> delegate;

@end
@@ -0,0 +1,162 @@
//
// GHTestRunner.h
//
// Created by Gabriel Handford on 1/16/09.
// Copyright 2008 Gabriel Handford
//
// 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.
//

//! @cond DEV

//
// 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 "GHTestGroup.h"
#import "GHTestSuite.h"

@class GHTestRunner;

// Delegates can be guaranteed to be notified on the main thread (using #delegateOnMainThread)
@protocol GHTestRunnerDelegate <NSObject>
@optional
- (void)testRunnerDidStart:(GHTestRunner *)runner;
- (void)testRunner:(GHTestRunner *)runner didStartTest:(id<GHTest>)test; // Test started
- (void)testRunner:(GHTestRunner *)runner didUpdateTest:(id<GHTest>)test; // Test changed
- (void)testRunner:(GHTestRunner *)runner didEndTest:(id<GHTest>)test; // Test finished
- (void)testRunnerDidCancel:(GHTestRunner *)runner;
- (void)testRunnerDidEnd:(GHTestRunner *)runner;

- (void)testRunner:(GHTestRunner *)runner didLog:(NSString *)message; // Runner logged message
- (void)testRunner:(GHTestRunner *)runner test:(id<GHTest>)test didLog:(NSString *)message; // Test logged message
@end

/*!
Runs the tests.
Tests are run a separate thread though delegates are called on the
main thread by default (see #delegateOnMainThread).
*/
@interface GHTestRunner : NSObject <GHTestDelegate> {

id<GHTest> test_; // The test to run; Could be a GHTestGroup (suite), GHTestGroup (test case), or GHTest (target/selector)

NSObject<GHTestRunnerDelegate> *delegate_; // weak

GHTestOptions options_;

BOOL running_;
BOOL cancelling_;

NSTimeInterval startInterval_;

NSOperationQueue *operationQueue_; //! If running a suite in operation queue
}

@property (retain) id<GHTest> test;
@property (assign) NSObject<GHTestRunnerDelegate> *delegate;
@property (assign) GHTestOptions options;
@property (readonly) GHTestStats stats;
@property (readonly, getter=isRunning) BOOL running;
@property (readonly, getter=isCancelling) BOOL cancelling;
@property (readonly) NSTimeInterval interval;
@property (retain, nonatomic) NSOperationQueue *operationQueue;


/*!
Create runner for test.
@param test
*/
- (id)initWithTest:(id<GHTest>)test;

/*!
Create runner for all tests.
@see GHTesting#loadAllTestCases.
@result Runner
*/
+ (GHTestRunner *)runnerForAllTests;

/*!
Create runner for test suite.
@param suite
@result Runner
*/
+ (GHTestRunner *)runnerForSuite:(GHTestSuite *)suite;

/*!
Create runner for class and method.
@param testClassName
@param methodName
@result Runner
*/
+ (GHTestRunner *)runnerForTestClassName:(NSString *)testClassName methodName:(NSString *)methodName;

/*!
Get the runner from the environment.
If the TEST env is set, then we will only run that test case or test method.
*/
+ (GHTestRunner *)runnerFromEnv;

/*!
Run the test runner. Usually called from the test main.
Reads the TEST environment variable and filters on that; or all tests are run.
@result 0 is success, otherwise the failure count
*/
+ (int)run;

- (void)runInBackground;

/*!
Start the test runner with the default test.
@result 0 is success, otherwise the failure count
*/
- (int)runTests;

- (void)cancel;

- (void)setInParallel:(BOOL)inParallel;
- (BOOL)isInParallel;

/*!
Write message to console.
*/
- (void)log:(NSString *)message;

@end

//! @endcond

@@ -0,0 +1,118 @@
//
// GHTestSuite.h
// GHUnit
//
// Created by Gabriel Handford on 1/25/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.
//

//! @cond DEV

#import "GHTestGroup.h"

/*!
If set, will run it as a "test filter" like the env variable TEST.
*/
extern NSString *GHUnitTest;


/*!
Test suite is an alias for test group.
A test case is an instance of a test case class with test methods.
A test is a id<GHTest> which represents a target and a selector.
A test group is a collection of tests; A collection of id<GHTest> (GHTest or GHTestGroup).
For example, if you have 2 test cases, GHTestCase1 (with some test methods) and GHTestCase2 (with some test methods),
your test suite might look like:
"Tests" (GHTestSuite)
GHTestGroup (collection of tests from GHTestCase1)
- (void)testA1 (GHTest with target GHTestCase1 + testA1)
- (void)testA2 (GHTest with target GHTestCase1 + testA2)
GHTestGroup (collection of tests from GHTestCase2)
- (void)testB1; (GHTest with target GHTestCase2 + testB1)
- (void)testB2; (GHTest with target GHTestCase2 + testB2)
*/
@interface GHTestSuite : GHTestGroup { }

/*!
Create test suite with test cases.
@param name Label to give the suite
@param testCases Array of init'ed test case classes
@param delegate
*/
- (id)initWithName:(NSString *)name testCases:(NSArray *)testCases delegate:(id<GHTestDelegate>)delegate;

/*!
Creates a suite of all tests.
Will load all classes that subclass from GHTestCase, SenTestCase or GTMTestCase (or register test case class).
@result Suite
*/
+ (GHTestSuite *)allTests;

/*!
Create suite of tests with filter.
This is useful for running a single test or all tests in a single test case.
For example,
'GHSlowTest' -- Runs all test method in GHSlowTest
'GHSlowTest/testSlowA -- Only runs the test method testSlowA in GHSlowTest
@param testFilter Test filter
@result Suite
*/
+ (GHTestSuite *)suiteWithTestFilter:(NSString *)testFilter;

/*!
Create suite of tests that start with prefix.
@param prefix If test case class starts with the prefix; If nil or empty string, returns all tests
@param options Compare options
*/
+ (GHTestSuite *)suiteWithPrefix:(NSString *)prefix options:(NSStringCompareOptions)options;

/*!
Suite for a single test/method.
@param testCaseClass
@param method
@result Suite
*/
+ (GHTestSuite *)suiteWithTestCaseClass:(Class)testCaseClass method:(SEL)method;

/*!
Return test suite based on environment (TEST=TestFoo/foo)
@result Suite
*/
+ (GHTestSuite *)suiteFromEnv;

@end

@interface GHTestSuite (JUnitXML)

- (BOOL)writeJUnitXML:(NSError **)error;

@end

//! @endcond
@@ -0,0 +1,103 @@
//
// GHTestViewController.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 "GHTestViewModel.h"
#import "GHTestGroup.h"
#import "GHTestOutlineViewModel.h"

#import "BWSplitView.h"

@interface GHTestViewController : NSViewController <GHTestRunnerDelegate, GHTestOutlineViewModelDelegate> {

IBOutlet BWSplitView *_splitView;
IBOutlet NSView *_statusView;
IBOutlet NSView *_detailsView;
IBOutlet NSOutlineView *_outlineView;
IBOutlet NSTextView *_textView;
IBOutlet NSSegmentedControl *_textSegmentedControl;
IBOutlet NSSegmentedControl *_segmentedControl;
IBOutlet NSSearchField *_searchField;

BOOL wrapInTextView_;
NSString *status_;
double statusProgress_;
BOOL runInParallel_;
NSString *runLabel_;

NSString *exceptionFilename_;
NSInteger exceptionLineNumber_;

GHTestSuite *suite_;

GHTestOutlineViewModel *dataSource_;
BOOL running_;
}

@property (assign, nonatomic) BOOL wrapInTextView;
@property (readonly, nonatomic) id<GHTest> selectedTest;
@property (readonly, nonatomic) GHTestOutlineViewModel *dataSource;

@property (retain, nonatomic) NSString *status;
@property (assign, nonatomic) double statusProgress;
@property (retain, nonatomic) NSString *runLabel;

@property (retain, nonatomic) GHTestSuite *suite;
@property (assign, nonatomic, getter=isRunning) BOOL running;

@property (retain, nonatomic) NSString *exceptionFilename;
@property (assign, nonatomic) NSInteger exceptionLineNumber;


- (void)loadTestSuite;

- (void)selectFirstFailure;

- (IBAction)copy:(id)sender;
- (IBAction)runTests:(id)sender;
- (IBAction)toggleDetails:(id)sender;
- (IBAction)updateTextSegment:(id)sender;
- (IBAction)updateMode:(id)sender;
- (IBAction)updateSearchFilter:(id)sender;
- (IBAction)openExceptionFilename:(id)sender;
- (IBAction)rerunTest:(id)sender;

- (id<GHTest>)selectedTest;

- (void)runTests;

- (void)reload;

- (void)loadDefaults;
- (void)saveDefaults;

- (BOOL)isShowingDetails;

- (void)selectRow:(NSInteger)row;

@end
@@ -0,0 +1,167 @@
//
// GHTest.h
// GHUnit
//
// 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.
//

//! @cond DEV

#import "GHTestGroup.h"

@class GHTestNode;

@protocol GHTestNodeDelegate <NSObject>
- (void)testNodeDidChange:(GHTestNode *)node;
@end

typedef enum {
GHTestNodeFilterNone = 0,
GHTestNodeFilterFailed = 1
} GHTestNodeFilter;

/*!
Test view model for use in a tree view.
*/
@interface GHTestViewModel : NSObject <GHTestNodeDelegate> {

NSString *identifier_;
GHTestSuite *suite_;
GHTestNode *root_;

GHTestRunner *runner_;

NSMutableDictionary *map_; // id<GHTest>#identifier -> GHTestNode

BOOL editing_;

NSMutableDictionary *defaults_;
}

@property (readonly, nonatomic) GHTestNode *root;
@property (assign, nonatomic, getter=isEditing) BOOL editing;

/*!
Create view model with root test group node.
@param identifier Unique identifier for test model (used to load defaults)
@param suite
*/
- (id)initWithIdentifier:(NSString *)identifier suite:(GHTestSuite *)suite;

- (NSString *)name;
- (NSString *)statusString:(NSString *)prefix;

/*!
Get the test node from the test.
@param test
*/
- (GHTestNode *)findTestNode:(id<GHTest>)test;

- (GHTestNode *)findFailure;
- (GHTestNode *)findFailureFromNode:(GHTestNode *)node;

/*!
Register node, so that we can do a lookup later (see #findTestNode).
@param node
*/
- (void)registerNode:(GHTestNode *)node;

// Return number of test groups
- (NSInteger)numberOfGroups;

// Return number of tests in group
- (NSInteger)numberOfTestsInGroup:(NSInteger)group;

/*!
Search for path to test.
@param test
@result Index path
*/
- (NSIndexPath *)indexPathToTest:(id<GHTest>)test;

- (void)loadDefaults;
- (void)saveDefaults;

/*!
Run with current test suite.
*/
- (void)run:(id<GHTestRunnerDelegate>)delegate inParallel:(BOOL)inParallel options:(GHTestOptions)options;

- (void)cancel;

- (BOOL)isRunning;

@end


@interface GHTestNode : NSObject {

id<GHTest> test_;
NSMutableArray */*of GHTestNode*/children_;
NSMutableArray */* of GHTestNode*/filteredChildren_;

id<GHTestNodeDelegate> delegate_;
GHTestNodeFilter filter_;
NSString *textFilter_;
}

@property (readonly, nonatomic) NSArray */* of GHTestNode*/children;
@property (readonly, nonatomic) id<GHTest> test;
@property (assign, nonatomic) id<GHTestNodeDelegate> delegate;
@property (assign, nonatomic) GHTestNodeFilter filter;
@property (retain, nonatomic) NSString *textFilter;

- (id)initWithTest:(id<GHTest>)test children:(NSArray */*of id<GHTest>*/)children source:(GHTestViewModel *)source;
+ (GHTestNode *)nodeWithTest:(id<GHTest>)test children:(NSArray */*of id<GHTest>*/)children source:(GHTestViewModel *)source;

- (NSString *)identifier;
- (NSString *)name;
- (NSString *)nameWithStatus;

- (GHTestStatus)status;
- (NSString *)statusString;
- (NSString *)stackTrace;
- (NSString *)exceptionFilename;
- (NSInteger)exceptionLineNumber;
- (NSString *)log;
- (BOOL)isRunning;
- (BOOL)isDisabled;
- (BOOL)isHidden;
- (BOOL)isEnded;
- (BOOL)isGroupTest; // YES if test has "sub tests"

- (BOOL)isSelected;
- (void)setSelected:(BOOL)selected;

- (BOOL)hasChildren;
- (BOOL)failed;

- (void)notifyChanged;

- (void)setFilter:(GHTestNodeFilter)filter textFilter:(NSString *)textFilter;

@end

//! @endcond
@@ -0,0 +1,41 @@
//
// GHTestWindowController.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 "GHTestViewController.h"

@interface GHTestWindowController : NSWindowController {
GHTestViewController *viewController_;
}

@property (retain, nonatomic) IBOutlet GHTestViewController *viewController;

- (IBAction)runTests:(id)sender;
- (IBAction)copy:(id)sender;

@end
@@ -0,0 +1,148 @@
//
// GHTesting.h
// GHUnit
//
// Created by Gabriel Handford on 1/30/09.
// Copyright 2008 Gabriel Handford
//
// 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.
//

//! @cond DEV

//
// 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.
//

#ifdef __cplusplus
extern "C" NSString *GHUStackTraceFromException(NSException *e);
#else
extern NSString *GHUStackTraceFromException(NSException *e);
#endif

// GTM_BEGIN
BOOL isTestFixtureOfClass(Class aClass, Class testCaseClass);
// GTM_END

/*!
Utility test for loading and running tests.
@note Much of this is borrowed from GTM/UnitTesting.
*/
@interface GHTesting : NSObject {

NSMutableArray/* of NSString*/ *testCaseClassNames_;

}

/*!
The shared testing instance.
*/
+ (GHTesting *)sharedInstance;

/*!
Load all test classes that we can "see".
@result Array of initialized (and autoreleased) test case classes in an autoreleased array.
*/
- (NSArray *)loadAllTestCases;

/*!
Load tests from target.
@result Array of id<GHTest>
*/
- (NSArray *)loadTestsFromTarget:(id)target;

/*!
See if class is of a registered test case class.
*/
- (BOOL)isTestCaseClass:(Class)aClass;

/*!
Register test case class.
@param aClass
*/
- (void)registerClass:(Class)aClass;

/*!
Register test case class by name.
@param className Class name (via NSStringFromClass(aClass)
*/
- (void)registerClassName:(NSString *)className;

/*!
Format test exception.
@param exception
@result Description
*/
+ (NSString *)descriptionForException:(NSException *)exception;

/*!
Filename for cause of test exception.
@param test
@result Filename
*/
+ (NSString *)exceptionFilenameForTest:(id<GHTest>)test;

/*!
Line number for cause of test exception.
@param test
@result Line number
*/
+ (NSInteger)exceptionLineNumberForTest:(id<GHTest>)test;

/*!
Run test.
@param target
@param selector
@param exception Exception, if set, is retained and should be released by the caller.
@param interval Time to run the test
@param reraiseExceptions If YES, will re-raise exceptions
*/
+ (BOOL)runTestWithTarget:(id)target selector:(SEL)selector exception:(NSException **)exception
interval:(NSTimeInterval *)interval reraiseExceptions:(BOOL)reraiseExceptions;

/*!
Same as normal runTest without catching exceptions.
*/
+ (BOOL)runTestOrRaiseWithTarget:(id)target selector:(SEL)selector exception:(NSException **)exception interval:(NSTimeInterval *)interval;

@end

@protocol GHSenTestCase
- (void)raiseAfterFailure;
@end

//! @endcond
@@ -0,0 +1,40 @@
//
// GHNSObject+Swizzle.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.
//

//! @cond DEV

@interface NSObject(GHUSwizzle)

+ (void)ghu_swizzleMethod:(SEL)original withMethod:(SEL)alternate;
+ (void)ghu_swizzleClassMethod:(SEL)original withClassMethod:(SEL)alternate;

@end

//! @endcond

Large diffs are not rendered by default.

@@ -0,0 +1,105 @@
//
// GTMStackTrace.h
//
// Copyright 2007-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.
//

#include <CoreFoundation/CoreFoundation.h>
#import "GTMDefines.h"

#ifdef __cplusplus
extern "C" {
#endif

struct GHU_GTMAddressDescriptor {
const void *address; // address
const char *symbol; // nearest symbol to address
const char *class_name; // if it is an obj-c method, the method's class
BOOL is_class_method; // if it is an obj-c method, type of method
const char *filename; // file that the method came from.
};

// Returns a string containing a nicely formatted stack trace.
//
// This function gets the stack trace for the current thread. It will
// be from the caller of GTMStackTrace upwards to the top the calling stack.
// Typically this function will be used along with some logging,
// as in the following:
//
// MyAppLogger(@"Should never get here:\n%@", GTMStackTrace());
//
// Here is a sample stack trace returned from this function:
//
// #0 0x00002d92 D () [/Users/me/./StackLog]
// #1 0x00002e45 C () [/Users/me/./StackLog]
// #2 0x00002e53 B () [/Users/me/./StackLog]
// #3 0x00002e61 A () [/Users/me/./StackLog]
// #4 0x00002e6f main () [/Users/me/./StackLog]
// #5 0x00002692 tart () [/Users/me/./StackLog]
// #6 0x000025b9 tart () [/Users/me/./StackLog]
//

NSString *GHU_GTMStackTrace(void);

#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
// Returns a string containing a nicely formatted stack trace from the
// exception. Only available on 10.5 or later, uses
// -[NSException callStackReturnAddresses].
//
NSString *GHU_GTMStackTraceFromException(NSException *e);
#endif

#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
// Returns an array of program counters from the current thread's stack.
// *** You should probably use GTMStackTrace() instead of this function ***
// However, if you actually want all the PCs in "void *" form, then this
// funtion is more convenient. This will include PCs of GTMStaceTrace and
// its inner utility functions that you may want to strip out.
//
// You can use +[NSThread callStackReturnAddresses] in 10.5 or later.
//
// Args:
// outPcs - an array of "void *" pointers to the program counters found on the
// current thread's stack.
// count - the number of entries in the outPcs array
//
// Returns:
// The number of program counters actually added to outPcs.
//
NSUInteger GHU_GTMGetStackProgramCounters(void *outPcs[], NSUInteger count);
#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5

// Returns an array of GTMAddressDescriptors from the current thread's stack.
// *** You should probably use GTMStackTrace() instead of this function ***
// However, if you actually want all the PCs with symbols, this is the way
// to get them. There is no memory allocations done, so no clean up is required
// except for the caller to free outDescs if they allocated it themselves.
// This will include PCs of GTMStaceTrace and its inner utility functions that
// you may want to strip out.
//
// Args:
// outDescs - an array of "struct GTMAddressDescriptor" pointers corresponding
// to the program counters found on the current thread's stack.
// count - the number of entries in the outDescs array
//
// Returns:
// The number of program counters actually added to outPcs.
//
NSUInteger GHU_GTMGetStackAddressDescriptors(struct GHU_GTMAddressDescriptor outDescs[],
NSUInteger count);

#ifdef __cplusplus
}
#endif
@@ -0,0 +1,97 @@
//
// NSException+GHTestFailureExceptions.h
//
// Created by Johannes Rudolph on 23.09.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.
//

//! @cond DEV

//
// 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.
//

extern NSString *const GHTestFilenameKey;
extern NSString *const GHTestLineNumberKey;
extern NSString *const GHTestFailureException;


// GTM_BEGIN

#import <Foundation/Foundation.h>

@interface NSException(GHUTestFailureExceptions)
+ (NSException *)ghu_failureInFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
+ (NSException *)ghu_failureInCondition:(NSString *)condition
isTrue:(BOOL)isTrue
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
+ (NSException *)ghu_failureInEqualityBetweenObject:(id)left
andObject:(id)right
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
+ (NSException *)ghu_failureInInequalityBetweenObject:(id)left
andObject:(id)right
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
+ (NSException *)ghu_failureInEqualityBetweenValue:(NSValue *)left
andValue:(NSValue *)right
withAccuracy:(NSValue *)accuracy
inFile:(NSString *)filename
atLine:(int) ineNumber
withDescription:(NSString *)formatString, ...;
+ (NSException *)ghu_failureInRaise:(NSString *)expression
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
+ (NSException *)ghu_failureInRaise:(NSString *)expression
exception:(NSException *)exception
inFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
@end

// GTM_END

//! @endcond
@@ -0,0 +1,71 @@
//
// NSValue+GHValueFormatter.h
//
// Created by Johannes Rudolph on 23.9.2009.
// 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.
//

//! @cond DEV

//
// 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.

#import <Foundation/Foundation.h>

// SENTE_BEGIN
@interface NSValue(GHValueFormatter)
- (NSString *)ghu_contentDescription;
@end
// SENTE_END

//! @endcond
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,4 @@

#include "GHUnit.xcconfig"

GCC_OPTIMIZATION_LEVEL = 0
@@ -0,0 +1,15 @@

#include "Shared.xcconfig"

ARCHS = $(ARCHS_STANDARD_32_64_BIT)
INSTALL_PATH = @rpath
DYLIB_COMPATIBILITY_VERSION = 0
DYLIB_CURRENT_VERSION = $(GHUNIT_VERSION)
LD_RUNPATH_SEARCH_PATHS = @loader_path/../Frameworks
INFOPLIST_FILE = Info.plist
PRODUCT_NAME = GHUnit
WRAPPER_EXTENSION = framework
GCC_ENABLE_OBJC_GC = supported
GCC_PRECOMPILE_PREFIX_HEADER = YES
GCC_PREFIX_HEADER = GHUnit_Prefix.pch
GCC_MODEL_TUNING = G5
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>GHUnit</string>
<key>CFBundleIdentifier</key>
<string>me.rel.GHUnit</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>GHUnit</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>GABE</string>
<key>CFBundleVersion</key>
<string>0.4.28</string>
</dict>
</plist>
@@ -0,0 +1,47 @@
//
// 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
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 // on lines like this to not confuse IB
<NSSplitViewDelegate>
#endif
{
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
@@ -0,0 +1,155 @@
//
// 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, //!< Unknown wait status
kGHUnitWaitStatusSuccess, //!< Wait status success
kGHUnitWaitStatusFailure, //!< Wait status failure
kGHUnitWaitStatusCancelled //!< Wait status cancelled
};

/*!
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
@interface MyAsyncTest : GHAsyncTestCase { }
@end
@implementation MyAsyncTest
- (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)];
}
@end
@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;

/*!
Run the run loops for the specified interval.
@param interval
@author Adapted from Robert Palmer, pauseForTimeout
*/
- (void)runForInterval:(NSTimeInterval)interval;

@end
@@ -0,0 +1,50 @@
//
// 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.
//

//! @cond DEV

#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

//! @endcond
@@ -0,0 +1,173 @@
//
// 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.
//

//! @cond DEV

#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;

/*!
Send data to connection delegate.
@param data Data to send
@param statusCode HTTP status code
@param MIMEType Mime type
@param afterDelay 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

//! @endcond
@@ -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