add GHUnit and some tests for -[NSDate relativeToNow]

This commit is contained in:
Sami Samhuri 2011-09-05 21:23:55 -07:00
parent f0fc9129f2
commit f401375380
33 changed files with 3998 additions and 1 deletions

View file

@ -0,0 +1 @@
Versions/Current/GHUnitIOS

1
GHUnitIOS.framework/Headers Symbolic link
View file

@ -0,0 +1 @@
Versions/Current/Headers

View file

@ -0,0 +1 @@
Versions/Current/Resources

Binary file not shown.

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,187 @@
//
// 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
#import <Foundation/Foundation.h>
/*!
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

View file

@ -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

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,169 @@
//
// 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"
#import "GHTestSuite.h"
#import "GHTestRunner.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

View file

@ -0,0 +1,151 @@
//
// 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.
//
#import <Foundation/Foundation.h>
#import "GHUnit.h"
#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

View file

@ -0,0 +1,723 @@
//
// GHUnit.h
// GHUnit
//
// Created by Gabriel Handford on 1/19/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"
#import "GHAsyncTestCase.h"
#import "GHTestSuite.h"
#import "GHTestMacros.h"
#import "GHTestRunner.h"
#import "GHTest.h"
#import "GHTesting.h"
#import "GHTestOperation.h"
#import "GHTestGroup.h"
#import "GHTest+JUnitXML.h"
#import "GHTestGroup+JUnitXML.h"
#import "NSException+GHTestFailureExceptions.h"
#import "NSValue+GHValueFormatter.h"
#if TARGET_OS_IPHONE
#import "GHUnitIOSAppDelegate.h"
#endif
#ifdef DEBUG
#define GHUDebug(fmt, ...) do { \
fputs([[[NSString stringWithFormat:fmt, ##__VA_ARGS__] stringByAppendingString:@"\n"] UTF8String], stdout); \
} while(0)
#else
#define GHUDebug(fmt, ...) do {} while(0)
#endif
/*!
@mainpage GHUnit
GHUnit is a test framework for Objective-C (Mac OS X 10.5 and above and iPhone 3.x and above).
It can be used with SenTestingKit, GTM or all by itself.
For example, your test cases will be run if they subclass any of the following:
- GHTestCase
- SenTestCase
- GTMTestCase
Source: http://github.com/gabriel/gh-unit
View docs online: http://gabriel.github.com/gh-unit/
This manual is divided in the following sections:
- @subpage Installing
- @subpage Examples
- @subpage CommandLine "Command Line & Makefiles"
- @subpage TestMacros
- @subpage Building
- @subpage EnvVariables
- @subpage Customizing
- @subpage Hudson
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/GHUnit-IPhone-0.4.18.png
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/GHUnit-0.4.18.png
@section Notes Notes
GHUnit was inspired by and uses parts of GTM (google-toolbox-for-mac) code, mostly from UnitTesting: http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/UnitTesting/
*/
/*!
@page Installing Installing
@ref InstallingIOSXcode4
@ref InstallMacOSXXcode4
@subpage InstallingXcode3
@section InstallingIOSXcode4 Installing in Xcode 4 (iOS)
@subsection CreateTestTargetXcode4 Create a Test Target
- You'll want to create a separate Test target. Select the project file for your app in the Project Navigator. From there, select the Add Target + symbol at the bottom of the window.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/1_add_target.png
- Select iOS, Application, Window-based Application. Select Next.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/2_select_application.png
- Name it Tests or something similar. Select Finish.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/3_name_it.png
@subsection ConfigureTestTargetXcode4 Configure the Test Target
- Download and copy the GHUnitIOS.framework to your project. Command click on Frameworks in the Project Navigator and select: Add Files to "MyTestable"...
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/6_add_framework.png
- Select GHUnitIOS.framework and make sure the only the Tests target is selected.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/7_add_framework_dialog.png
- We want to enable use of Objective-C categories, which isn't enabled for static libraries by default. In the Tests target, Build Settings, under Other Linker Flags, add <tt>-ObjC</tt> and <tt>-all_load</tt>.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/8_other_linker_flags.png
- Select and delete the files from the existing Tests folder. Leave the Supporting Files folder. GHUnit will provide the application delegate below.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/9_remove_test_files.png
- By default, the Tests-Info.plist file includes MainWindow_iPhone and MainWindow_iPad for Main nib file base name. You should remove both these fields.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/9b_fix_plist.png
- After removing these entries, the Tests-Info.plist should look like this.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/9c_fixed_plist.png
- In Tests folder, in Supporting Files, main.m, replace the last argument of UIApplicationMain with @"GHUnitIPhoneAppDelegate".
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/10_main.png
- Select the Tests target, iPhone Simulator configuration:
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/11_select_target.png
- Hit Run, and you'll hopefully see the test application running (but without any tests).
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/12_running.png
@subsection CreateTestXcode4 Create a Test
- Command click on the Tests folder and select: New File...
- Under iOS, Cocoa Touch, select Objective-C class and select Next. Leave the default subclass and select Next again.
- Name the file MyTest.m and make sure its enabled only for the "Tests" target.
- Delete the MyTest.h file and replace the MyTest.m file with:
@code
#import <GHUnitIOS/GHUnit.h>
@interface MyTest : GHTestCase { }
@end
@implementation MyTest
- (void)testStrings {
NSString *string1 = @"a string";
GHTestLog(@"I can log to the GHUnit test console: %@", string1);
// Assert string1 is not NULL, with no custom error description
GHAssertNotNULL(string1, nil);
// Assert equal objects, add custom error description
NSString *string2 = @"a string";
GHAssertEqualObjects(string1, string2, @"A custom error message. string1 should be equal to: %@.", string2);
}
@end
@endcode
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/13_adding_test.png
- Now run the "Tests" target. Hit the Run button in the top right.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/Installing/14_running_with_test.png
@subsection InstallWhatsNextXcode4 Whats next?
There aren't any more steps required, but you might be interested in:
- @ref Examples "More Examples"
- @ref CommandLine "Running from the Command Line"
- @ref Makefile "Install a Makefile"
*/
/*!
@page InstallingXcode3 Installing in Xcode 3
@section InstallingIOSXcode3 Installing in Xcode 3 (iOS)
- Add a <tt>New Target</tt>. Select <tt>iOS -> Application</tt>. Name it <tt>Tests</tt> (or something similar).
- Copy and add <tt>GHUnitIOS.framework</tt> into your project: Add Files to ..., select <tt>GHUnitIOS.framework</tt>, and select the <tt>Tests</tt> target.
- Add the following frameworks to <tt>Linked Libraries</tt>:
- <tt>GHUnitIOS.framework</tt>
- <tt>CoreGraphics.framework</tt>
- <tt>Foundation.framework</tt>
- <tt>UIKit.framework</tt>
- In Build Settings, under 'Framework Search Paths' make sure the (parent) directory to GHUnitIOS.framework is listed.
- In Build Settings, under 'Other Linker Flags' in the <tt>Tests</tt> target, add <tt>-ObjC</tt> and <tt>-all_load</tt>
- By default, the Tests-Info.plist file includes <tt>MainWindow</tt> for <tt>Main nib file base name</tt>. You should clear this field.
- Add the GHUnitIOSTestMain.m (http://github.com/gabriel/gh-unit/blob/master/Project-iOS/GHUnitIOSTestMain.m) file into your project and make sure its enabled for the "Tests" target.
- (Optional) Create and and set a prefix header (<tt>Tests_Prefix.pch</tt>) and add <tt>#import <GHUnitIOS/GHUnit.h></tt> to it, and then you won't have to include that import for every test.
- @ref Examples "Create a test"
- Build and run the "Tests" target.
- (Optional) @ref Makefile "Install Makefile"
@section InstallMacOSXXcode4 Installing in Xcode 4 (Mac OS X)
- Add a <tt>New Target</tt>. Select <tt>Application -> Cocoa Application</tt>. Name it <tt>Tests</tt> (or something similar).
- Copy and add <tt>GHUnit.framework</tt> into your project: Add Files to 'App'..., select <tt>GHUnit.framework</tt>, and select only the "Tests" target.
- In the "Tests" target, in Build Settings, add <tt>@@loader_path/../Frameworks</tt> to <tt>Runpath Search Paths</tt>.
- In the "Tests" target, in Build Phases, select <tt>Add Build Phase</tt> and then <tt>Add Copy Files</tt>.
- Change the Destination to <tt>Frameworks</tt>.
- Drag <tt>GHUnit.framework</tt> from the project file view into the the Copy Files build phase.
- Make sure the copy phase appears before any <tt>Run Script</tt> phases.
- Copy GHUnitTestMain.m (http://github.com/gabriel/gh-unit/tree/master/Classes-MacOSX/GHUnitTestMain.m) into your project and include in the Test target. You should delete the existing main.m file (or replace the contents of the existing main.m with GHUnitTestMain.m).
- By default, the Tests-Info.plist file includes <tt>MainWindow</tt> for <tt>Main nib file base name</tt>. You should clear this field. You can also delete the existing MainMenu.xib and files like TestsAppDelegate.*.
- @ref Examples "Create a test"
- Build and run the "Tests" target.
- (Optional) @ref Makefile "Install Makefile"
@section InstallMacOSXXcode3 Installing in Xcode 3 (Mac OS X)
You can install it globally in /Library/Frameworks or with a little extra effort embed it with your project.
@subsection InstallLibraryFrameworks Installing in /Library/Frameworks
- Copy <tt>GHUnit.framework</tt> to <tt>/Library/Frameworks/</tt>
- Add a <tt>New Target</tt>. Select <tt>Cocoa -> Application</tt>. Name it <tt>Tests</tt> (or something similar).
- In the <tt>Target 'Tests' Info</tt> window, <tt>General</tt> tab:
- Add a linked library, under <tt>Mac OS X 10.X SDK</tt> section, select <tt>GHUnit.framework</tt>
- If your main target is a library: Add a linked library, and select your main target.
- If your main target is an application, you will need to include these source files in the <tt>Test</tt> project manually.
- Add a direct dependency, and select your project. (This will cause your application or framework to build before the test target.)
- Copy GHUnitTestMain.m (http://github.com/gabriel/gh-unit/tree/master/Classes-MacOSX/GHUnitTestMain.m) into your project and include in the Test target.
- Now create a test (either by subclassing <tt>SenTestCase</tt> or <tt>GHTestCase</tt>), adding it to your test target. (See example test case below.)
- By default, the Tests-Info.plist file includes <tt>MainWindow</tt> for <tt>Main nib file base name</tt>. You should clear this field.
- @ref Examples "Create a test"
- (Optional) @ref Makefile "Install Makefile"
@subsection InstallProject Installing in your project
- Add a <tt>New Target</tt>. Select <tt>Cocoa -> Application</tt>. Name it <tt>Tests</tt> (or something similar).
- In the Finder, copy <tt>GHUnit.framework</tt> to your project directory (maybe in MyProject/Frameworks/.)
- In the <tt>Tests</tt> target, add the <tt>GHUnit.framework</tt> files (from MyProject/Frameworks/). It should now be visible as a <tt>Linked Framework</tt> in the target.
- In the <tt>Tests</tt> target, under Build Settings, add <tt>@loader_path/../Frameworks</tt> to <tt>Runpath Search Paths</tt> (Under All Configurations)
- In the <tt>Tests</tt> target, add <tt>New Build Phase</tt> | <tt>New Copy Files Build Phase</tt>.
- Change the Destination to <tt>Frameworks</tt>.
- Drag <tt>GHUnit.framework</tt> into the the build phase
- Make sure the copy phase appears before any <tt>Run Script</tt> phases
- Copy GHUnitTestMain.m (http://github.com/gabriel/gh-unit/tree/master/Classes-MacOSX/GHUnitTestMain.m) into your project and include in the Test target.
- If your main target is a library:
- In the <tt>Target 'Tests' Info</tt> window, <tt>General</tt> tab:
- Add a linked library, and select your main target; This is so you can link your test target against your main target, and then you don't have to manually include source files in both targets.
- If your main target is an application, you will need to include these source files to the <tt>Test</tt> project manually.
- Now create a test (either by subclassing <tt>SenTestCase</tt> or <tt>GHTestCase</tt>), adding it to your test target. (See example test case below.)
- By default, the Tests-Info.plist file includes <tt>MainWindow</tt> for <tt>Main nib file base name</tt>. You should clear this field.
- @ref Examples "Create a test"
- (Optional) @ref Makefile "Install Makefile"
*/
/*!
@page Building Building
For iOS, run <tt>make</tt> from within the <tt>Project-iOS</tt> directory. The framework is in <tt>Project-iOS/build/Framework/</tt>.
For Mac OS X, the framework build is stored in <tt>Project/build/Release/</tt>.
*/
/*!
@page Examples Examples
- @ref ExampleTestCase
- @ref ExampleAsyncTestCase
@section ExampleTestCase Example Test Case
For example <tt>ExampleTest.m</tt>:
@code
// For iOS
#import <GHUnitIOS/GHUnit.h>
// For Mac OS X
//#import <GHUnit/GHUnit.h>
@interface ExampleTest : GHTestCase { }
@end
@implementation ExampleTest
- (BOOL)shouldRunOnMainThread {
// By default NO, but if you have a UI test or test dependent on running on the main thread return YES.
// Also an async test that calls back on the main thread, you'll probably want to return YES.
return NO;
}
- (void)setUpClass {
// Run at start of all tests in the class
}
- (void)tearDownClass {
// Run at end of all tests in the class
}
- (void)setUp {
// Run before each test method
}
- (void)tearDown {
// Run after each test method
}
- (void)testFoo {
NSString *a = @"foo";
GHTestLog(@"I can log to the GHUnit test console: %@", a);
// Assert a is not NULL, with no custom error description
GHAssertNotNULL(a, nil);
// Assert equal objects, add custom error description
NSString *b = @"bar";
GHAssertEqualObjects(a, b, @"A custom error message. a should be equal to: %@.", b);
}
- (void)testBar {
// Another test
}
@end
@endcode
@section ExampleAsyncTestCase Example Async Test Case
@code
// For iOS
#import <GHUnitIOS/GHUnit.h>
// For Mac OS X
//#import <GHUnit/GHUnit.h>
@interface ExampleAsyncTest : GHAsyncTestCase { }
@end
@implementation ExampleAsyncTest
- (void)testURLConnection {
// Call prepare to setup the asynchronous action.
// This helps in cases where the action is synchronous and the
// action occurs before the wait is actually called.
[self prepare];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
// Wait until notify called for timeout (seconds); If notify is not called with kGHUnitWaitStatusSuccess then
// we will throw an error.
[self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.0];
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Notify of success, specifying the method where wait is called.
// This prevents stray notifies from affecting other tests.
[self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testURLConnection)];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// Notify of connection failure
[self notify:kGHUnitWaitStatusFailure forSelector:@selector(testURLConnection)];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
GHTestLog(@"%@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
}
@end
@endcode
@section ExampleProjects Example Projects
Example projects can be found at: http://github.com/gabriel/gh-unit/tree/master/Examples/
*/
/*!
@page EnvVariables Environment Variables
@section GHUnitEnvVariables GHUnit Environment Variables
Go into the "Get Info" contextual menu of your (Tests) executable (inside the "Executables" group in the left panel of Xcode).
Then go in the "Arguments" tab. You can add the following environment variables:
@verbatim
GHUNIT_CLI - Default NO; Runs tests on the command line (see Debugger Console, Cmd-Shift-R)
GHUNIT_RERAISE - Default NO; If an exception is encountered it re-raises it allowing you to crash into the debugger
GHUNIT_AUTORUN - Default NO; If YES, tests will start automatically
GHUNIT_AUTOEXIT - Default NO; If YES, will exit upon test completion (no matter what); For command line MacOSX testing
@endverbatim
@section EnvVariablesTest Test Environment Variables (Recommended)
Go into the "Get Info" contextual menu of your (Tests) executable (inside the "Executables" group in the left panel of Xcode).
Then go in the "Arguments" tab. You can add the following environment variables:
@verbatim
Environment Variable: Default: Set to:
NSDebugEnabled NO YES
NSZombieEnabled NO YES
NSDeallocateZombies NO NO (or YES)
NSHangOnUncaughtException NO YES
NSAutoreleaseFreedObjectCheckEnabled NO YES
@endverbatim
If Using NSDeallocateZombies=NO, then all objects will leak so be sure to turn it off when debugging memory leaks.
For more info on these varaiables see NSDebug.h (http://theshadow.uw.hu/iPhoneSDKdoc/Foundation.framework/NSDebug.h.html)
For malloc debugging:
@verbatim
MallocStackLogging
MallocStackLoggingNoCompact
MallocScribble
MallocPreScribble
MallocGuardEdges
MallocDoNotProtectPrelude
MallocDoNotProtectPostlude
MallocCheckHeapStart
MallocCheckHeapEach
@endverbatim
If you see a message like:
@verbatim
2009-10-15 13:02:24.746 Tests[38615:40b] *** -[Foo class]: message sent to deallocated instance 0x1c8e680
@endverbatim
Re-run (in gdb) with <tt>MallocStackLogging=YES</tt> (or <tt>MallocStackLoggingNoCompact=YES</tt>), then if you run under gdb:
@verbatim
(gdb) shell malloc_history 38615 0x1c8e680
ALLOC 0x1a9ad10-0x1a9ad6f [size=96]: thread_a024a500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __NSThreadPerformPerform | -[GHTestGroup _run:] | -[GHTest run] | +[GHTesting runTest:selector:withObject:exception:interval:] | -[Foo foo] | +[NSObject alloc] | +[NSObject allocWithZone:] | _internal_class_createInstance | _internal_class_createInstanceFromZone | calloc | malloc_zone_calloc
@endverbatim
Somewhere between runTest and NSObject alloc (in [Foo foo]) there may be an object that wasn't retained. 38615 is the thread id from "2009-10-15 13:02:24.746 Tests[38615:40b]", and 0x1c8e680 is the address in "message sent to deallocated instance 0x1c8e680".
Also using <tt>MallocScribble=YES</tt> causes the malloc library to overwrite freed memory with a well-known value (0x55), and occasionally checks freed malloc blocks to make sure the memory has not been over-written overwritten written since it was cleared.
For more info on these variables see MallocDebug (http://developer.apple.com/mac/library/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html)
For more info on malloc_history see malloc_history (http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/malloc_history.1.html)
*/
/*!
@page CommandLine Command Line
@section CommandLineRunningTests Running from the Command Line
To run the tests from the command line:
- Copy the RunTests.sh (http://github.com/gabriel/gh-unit/tree/master/Scripts/RunTests.sh) file into your project in the same directory as the xcodeproj file.
- In the Tests target, Build Phases, Select Add Build Phase + button, and select Add Run Script.
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/RunningCLI/2_add_build_phase.png
- For the script enter: <tt>sh RunTests.sh</tt>
@image html http://rel.me.s3.amazonaws.com/gh-unit/images/RunningCLI/3_configure_phase.png
The path to RunTests.sh should be relative to the xcode project file (.xcodeproj). You can uncheck 'Show environment variables in build log' if you want.
- Now run the tests From the command line:
@verbatim
// For iOS app
GHUNIT_CLI=1 xcodebuild -target Tests -configuration Debug -sdk iphonesimulator build
// For mac app
GHUNIT_CLI=1 xcodebuild -target Tests -configuration Debug -sdk macosx build
@endverbatim
If you get and error like: <tt>Couldn't register Tests with the bootstrap server.</tt> it means an iPhone simulator is running and you need to close it.
@subsection CommandLineEnv Command Line Environment
The RunTests.sh script will only run the tests if the env variable GHUNIT_CLI is set. This is why this RunScript phase is ignored when running the test GUI. This is how we use a single Test target for both the GUI and command line testing.
This may seem strange that we run via xcodebuild with a RunScript phase in order to work on the command line, but otherwise we may not have the environment settings or other Xcode specific configuration right.
@section Makefile Makefile
Follow the directions above for adding command line support.
Example Makefile's for Mac or iPhone apps:
- Makefile (Mac OS X): http://github.com/gabriel/gh-unit/tree/master/Project/Makefile.example (for a Mac App)
- Makefile (iOS): http://github.com/gabriel/gh-unit/tree/master/Project-iOS/Makefile.example (for an iOS App)
The script will return a non-zero exit code on test failure.
To run the tests via the Makefile:
@verbatim
make test
@endverbatim
Unfortunately, running Mac OS X from the command line isn't always supported since certain frameworks can't work
headless and will seg fault.
@section RunningATest Running a Test Case / Single Test
The <tt>TEST</tt> environment variable can be used to run a single test or test case.
@verbatim
// Run all tests in GHSlowTest
make test TEST="GHSlowTest"
// Run the method testSlowA in GHSlowTest
make test TEST="GHSlowTest/testSlowA"
@endverbatim
*/
/*!
@page TestMacros Test Macros
The following test macros are included.
These macros are directly from: GTMSenTestCase.h (http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/UnitTesting/GTMSenTestCase.h)
prefixed with GH so as not to conflict with the GTM macros if you are using those in your project.
The <tt>description</tt> argument appends extra information for when the assert fails; though most of the time you might leave it as nil.
@code
GHAssertNoErr(a1, description, ...)
GHAssertErr(a1, a2, description, ...)
GHAssertNotNULL(a1, description, ...)
GHAssertNULL(a1, description, ...)
GHAssertNotEquals(a1, a2, description, ...)
GHAssertNotEqualObjects(a1, a2, desc, ...)
GHAssertOperation(a1, a2, op, description, ...)
GHAssertGreaterThan(a1, a2, description, ...)
GHAssertGreaterThanOrEqual(a1, a2, description, ...)
GHAssertLessThan(a1, a2, description, ...)
GHAssertLessThanOrEqual(a1, a2, description, ...)
GHAssertEqualStrings(a1, a2, description, ...)
GHAssertNotEqualStrings(a1, a2, description, ...)
GHAssertEqualCStrings(a1, a2, description, ...)
GHAssertNotEqualCStrings(a1, a2, description, ...)
GHAssertEqualObjects(a1, a2, description, ...)
GHAssertEquals(a1, a2, description, ...)
GHAbsoluteDifference(left,right) (MAX(left,right)-MIN(left,right))
GHAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...)
GHFail(description, ...)
GHAssertNil(a1, description, ...)
GHAssertNotNil(a1, description, ...)
GHAssertTrue(expr, description, ...)
GHAssertTrueNoThrow(expr, description, ...)
GHAssertFalse(expr, description, ...)
GHAssertFalseNoThrow(expr, description, ...)
GHAssertThrows(expr, description, ...)
GHAssertThrowsSpecific(expr, specificException, description, ...)
GHAssertThrowsSpecificNamed(expr, specificException, aName, description, ...)
GHAssertNoThrow(expr, description, ...)
GHAssertNoThrowSpecific(expr, specificException, description, ...)
GHAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...)
@endcode
*/
/*!
@page Customizing Customizing
@section CustomTests Custom Test Case Classes
You can register additional classes at runtime; if you have your own. For example:
@code
[[GHTesting sharedInstance] registerClassName:@"MySpecialTestCase"];
@endcode
@section AlternateIOSAppDelegate Using an Alternate iOS Application Delegate
If you want to use a custom application delegate in your test environment, you should subclass GHUnitIOSAppDelegate:
@code
@interface MyTestApplicationDelegate : GHUnitIOSAppDelegate { }
@end
@endcode
Then in GHUnitIOSTestMain.m:
@code
retVal = UIApplicationMain(argc, argv, nil, @"MyTestApplicationDelegate");
@endcode
I am looking into removing this dependency but this will work in the meantime.
@section UsingSenTesting Using SenTestingKit
You can also use GHUnit with SenTestCase, for example:
@code
#import <SenTestingKit/SenTestingKit.h>
@interface MyTest : SenTestCase { }
@end
@implementation MyTest
- (void)setUp {
// Run before each test method
}
- (void)tearDown {
// Run after each test method
}
- (void)testFoo {
// Assert a is not NULL, with no custom error description
STAssertNotNULL(a, nil);
// Assert equal objects, add custom error description
STAssertEqualObjects(a, b, @"Foo should be equal to: %@. Something bad happened", bar);
}
- (void)testBar {
// Another test
}
@end
@endcode
*/
/*!
@page Hudson Hudson
@section Using Using Hudson with GHUnit
Hudson (http://hudson-ci.org/) is a continuous
integration server that has a broad set of support and plugins, and is easy to set up. You
can use Hudson to run your GHUnit tests after every checkin, and report the
results to your development group in a variety of ways (by email, to Campfire,
and so on).
Here's how to set up Hudson with GHUnit.
1. Follow the instructions to set up a Makefile for your GHUnit project.
2. Download <tt>hudson.war</tt> from http://hudson-ci.org/.
Run it with <tt>java -jar hudson.war</tt>. It will start up on
http://localhost:8080/
3. Go to <tt>Manage Hudson -> Manage Plugins</tt> and install whatever plugins you
need for your project. For instance, you might want to install the Git
and GitHub plugins if you host your code on GitHub (http://www.github.com)
4. Create a new job for your project and click on <tt>Configure</tt>. Most of the options
are self-explanatory or can be figured out with the online help. You probably
want to configure <tt>Source Code Management</tt>, and then under <tt>Build Triggers</tt> check
<tt>Poll SCM</tt> and add a schedule of <tt>* * * * *</tt> (which checks your source control
system for new changes once a minute).
5. Under <tt>Build</tt>, enter the following command:
@verbatim
make clean && WRITE_JUNIT_XML=YES make test
@endverbatim
6. Under <tt/>Post-build Actions</tt>, check <tt/>Publish JUnit test result report</tt> and enter
the following in <tt>Test report XMLs</tt>:
@verbatim
build/test-results/ *.xml (Remove the extra-space, which is there to work around doxygen bug)
@endverbatim
That's all it takes. Check in a change that breaks one of your tests. Hudson
should detect the change, run a build and test, and then report the failure.
Fix the test, check in again, and you should see a successful build report.
@section Troubleshooting Troubleshooting
If your Xcode build fails with a set of font-related errors, you may be running
Hudson headless (e.g., via an SSH session). Launch Hudson via Terminal.app on
the build machine (or otherwise attach a DISPLAY to the session) in order to
address this.
*/

View file

@ -0,0 +1,39 @@
//
// GHUnitIOSAppDelegate.h
// GHUnitIOS
//
// 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.
//
#import <UIKit/UIKit.h>
@interface GHUnitIOSAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window_;
UINavigationController *navigationController_;
}
@end

View file

@ -0,0 +1,41 @@
//
// GHUnitIOSTableViewDataSource.h
// GHUnitIOS
//
// Created by Gabriel Handford on 5/5/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 <UIKit/UIKit.h>
#import "GHTestViewModel.h"
@interface GHUnitIOSTableViewDataSource : GHTestViewModel <UITableViewDataSource> {
}
- (GHTestNode *)nodeForIndexPath:(NSIndexPath *)indexPath;
- (void)setSelectedForAllNodes:(BOOL)selected;
@end

View file

@ -0,0 +1,43 @@
//
// GHUnitIOSTestViewController.h
// GHUnitIOS
//
// Created by Gabriel Handford on 2/20/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 <UIKit/UIKit.h>
#import "GHTestViewModel.h"
@interface GHUnitIOSTestViewController : UIViewController <GHTestRunnerDelegate> {
UITextView *textView_;
GHTestNode *testNode_;
GHTestRunner *runner_;
}
- (void)setTest:(id<GHTest>)test;
@end

View file

@ -0,0 +1,55 @@
//
// GHUnitIOSView.h
// GHUnitIOS
//
// Created by Gabriel Handford on 4/12/10.
// Copyright 2010. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface GHUnitIOSView : UIView {
UISearchBar *searchBar_;
UITableView *tableView_;
//! Status label at bottom of the view
UILabel *statusLabel_;
UISegmentedControl *filterControl_;
UIToolbar *runToolbar_;
UIView *footerView_;
}
@property (readonly, nonatomic) UILabel *statusLabel;
@property (readonly, nonatomic) UISegmentedControl *filterControl;
@property (readonly, nonatomic) UISearchBar *searchBar;
@property (readonly, nonatomic) UITableView *tableView;
@end

View file

@ -0,0 +1,71 @@
//
// GHUnitIOSViewController.h
// GHUnitIOS
//
// 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.
//
#import "GHUnitIOSView.h"
#import "GHUnitIOSTableViewDataSource.h"
#import "GHUnitIOSTestViewController.h"
@interface GHUnitIOSViewController : UIViewController <UITableViewDelegate, GHTestRunnerDelegate, UISearchBarDelegate> {
GHUnitIOSView *view_;
//! Data source for table view
GHUnitIOSTableViewDataSource *dataSource_;
GHTestSuite *suite_;
UIBarButtonItem *runButton_;
//! If set then we will no longer auto scroll as tests are run
BOOL userDidDrag_;
}
@property (retain, nonatomic) GHTestSuite *suite;
- (void)reloadTest:(id<GHTest>)test;
- (void)scrollToTest:(id<GHTest>)test;
- (void)scrollToBottom;
- (void)setStatusText:(NSString *)message;
- (void)runTests;
- (void)cancel;
- (void)reload;
- (void)loadDefaults;
- (void)saveDefaults;
- (GHUnitIOSTableViewDataSource *)dataSource;
@end

View file

@ -0,0 +1,36 @@
//
// GHUnitIPhoneAppDelegate.h
// GHUnitIOS
//
// Created by Gabriel Handford on 6/28/11.
//
// 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 "GHUnitIOSAppDelegate.h"
// For backwards compatibility (see GHUnitIOSAppDelegate)
@interface GHUnitIPhoneAppDelegate : GHUnitIOSAppDelegate {
}
@end

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,18 @@
<?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>CFBundleIdentifier</key>
<string>me.rel.ghunit</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(GHUNIT_VERSION)</string>
</dict>
</plist>

View file

@ -0,0 +1 @@
A

View file

@ -22,11 +22,25 @@
7BD100D714136F7500A9921B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BD100B61413675100A9921B /* UIKit.framework */; }; 7BD100D714136F7500A9921B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BD100B61413675100A9921B /* UIKit.framework */; };
7BD100D814136F7500A9921B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BE32D0914132EE4008F2DEA /* Foundation.framework */; }; 7BD100D814136F7500A9921B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BE32D0914132EE4008F2DEA /* Foundation.framework */; };
7BD100D914136F7500A9921B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BD100B91413675100A9921B /* CoreGraphics.framework */; }; 7BD100D914136F7500A9921B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BD100B91413675100A9921B /* CoreGraphics.framework */; };
7BD100DF14136F7500A9921B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7BD100DD14136F7500A9921B /* InfoPlist.strings */; };
7BD100E114136F7500A9921B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD100E014136F7500A9921B /* main.m */; };
7BD100F814136FD200A9921B /* GHUnitIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BD100F714136FD200A9921B /* GHUnitIOS.framework */; };
7BD100FB141370B800A9921B /* NSDateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD100FA141370B800A9921B /* NSDateTest.m */; };
7BE32D0A14132EE4008F2DEA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BE32D0914132EE4008F2DEA /* Foundation.framework */; }; 7BE32D0A14132EE4008F2DEA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BE32D0914132EE4008F2DEA /* Foundation.framework */; };
7BE32D6A14133618008F2DEA /* NSString+sanity.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BE32D6814133618008F2DEA /* NSString+sanity.h */; }; 7BE32D6A14133618008F2DEA /* NSString+sanity.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BE32D6814133618008F2DEA /* NSString+sanity.h */; };
7BE32D6B14133618008F2DEA /* NSString+sanity.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BE32D6914133618008F2DEA /* NSString+sanity.m */; }; 7BE32D6B14133618008F2DEA /* NSString+sanity.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BE32D6914133618008F2DEA /* NSString+sanity.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
7B13A56B1415CDA70033DCC2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7BE32CFD14132EE3008F2DEA /* Project object */;
proxyType = 1;
remoteGlobalIDString = 7BE32D0514132EE4008F2DEA;
remoteInfo = Marshmallows;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
7B2C8D7414159642004E1123 /* UIAlertView+simple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+simple.h"; sourceTree = "<group>"; }; 7B2C8D7414159642004E1123 /* UIAlertView+simple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+simple.h"; sourceTree = "<group>"; };
7B2C8D7514159642004E1123 /* UIAlertView+simple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+simple.m"; sourceTree = "<group>"; }; 7B2C8D7514159642004E1123 /* UIAlertView+simple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+simple.m"; sourceTree = "<group>"; };
@ -38,9 +52,15 @@
7BD100A514134FBE00A9921B /* MMHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMHTTPRequest.m; sourceTree = "<group>"; }; 7BD100A514134FBE00A9921B /* MMHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMHTTPRequest.m; sourceTree = "<group>"; };
7BD100A8141353B700A9921B /* NSDate+relative.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+relative.h"; sourceTree = "<group>"; }; 7BD100A8141353B700A9921B /* NSDate+relative.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+relative.h"; sourceTree = "<group>"; };
7BD100A9141353B700A9921B /* NSDate+relative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+relative.m"; sourceTree = "<group>"; }; 7BD100A9141353B700A9921B /* NSDate+relative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+relative.m"; sourceTree = "<group>"; };
7BD100B41413675100A9921B /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
7BD100B61413675100A9921B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 7BD100B61413675100A9921B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
7BD100B91413675100A9921B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; 7BD100B91413675100A9921B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
7BD100D514136F7500A9921B /* MarshmallowsTesting.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarshmallowsTesting.app; sourceTree = BUILT_PRODUCTS_DIR; };
7BD100DC14136F7500A9921B /* MarshmallowsTesting-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MarshmallowsTesting-Info.plist"; sourceTree = "<group>"; };
7BD100DE14136F7500A9921B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
7BD100E014136F7500A9921B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
7BD100E214136F7500A9921B /* MarshmallowsTesting-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MarshmallowsTesting-Prefix.pch"; sourceTree = "<group>"; };
7BD100F714136FD200A9921B /* GHUnitIOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GHUnitIOS.framework; sourceTree = "<group>"; };
7BD100FA141370B800A9921B /* NSDateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDateTest.m; sourceTree = "<group>"; };
7BE32D0614132EE4008F2DEA /* libMarshmallows.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMarshmallows.a; sourceTree = BUILT_PRODUCTS_DIR; }; 7BE32D0614132EE4008F2DEA /* libMarshmallows.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMarshmallows.a; sourceTree = BUILT_PRODUCTS_DIR; };
7BE32D0914132EE4008F2DEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 7BE32D0914132EE4008F2DEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
7BE32D0D14132EE4008F2DEA /* Marshmallows-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Marshmallows-Prefix.pch"; sourceTree = "<group>"; }; 7BE32D0D14132EE4008F2DEA /* Marshmallows-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Marshmallows-Prefix.pch"; sourceTree = "<group>"; };
@ -50,6 +70,18 @@
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
7BD100D214136F7500A9921B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7B13A56E1415CE360033DCC2 /* libMarshmallows.a in Frameworks */,
7BD100D714136F7500A9921B /* UIKit.framework in Frameworks */,
7BD100D814136F7500A9921B /* Foundation.framework in Frameworks */,
7BD100D914136F7500A9921B /* CoreGraphics.framework in Frameworks */,
7BD100F814136FD200A9921B /* GHUnitIOS.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7BE32D0314132EE4008F2DEA /* Frameworks */ = { 7BE32D0314132EE4008F2DEA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -61,10 +93,31 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
7BD100DA14136F7500A9921B /* MarshmallowsTesting */ = {
isa = PBXGroup;
children = (
7BD100FA141370B800A9921B /* NSDateTest.m */,
7BD100DB14136F7500A9921B /* Supporting Files */,
);
path = MarshmallowsTesting;
sourceTree = "<group>";
};
7BD100DB14136F7500A9921B /* Supporting Files */ = {
isa = PBXGroup;
children = (
7BD100DC14136F7500A9921B /* MarshmallowsTesting-Info.plist */,
7BD100DD14136F7500A9921B /* InfoPlist.strings */,
7BD100E014136F7500A9921B /* main.m */,
7BD100E214136F7500A9921B /* MarshmallowsTesting-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
7BE32CFB14132EE3008F2DEA = { 7BE32CFB14132EE3008F2DEA = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7BE32D0B14132EE4008F2DEA /* Marshmallows */, 7BE32D0B14132EE4008F2DEA /* Marshmallows */,
7BD100DA14136F7500A9921B /* MarshmallowsTesting */,
7BE32D0814132EE4008F2DEA /* Frameworks */, 7BE32D0814132EE4008F2DEA /* Frameworks */,
7BE32D0714132EE4008F2DEA /* Products */, 7BE32D0714132EE4008F2DEA /* Products */,
); );
@ -74,6 +127,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7BE32D0614132EE4008F2DEA /* libMarshmallows.a */, 7BE32D0614132EE4008F2DEA /* libMarshmallows.a */,
7BD100D514136F7500A9921B /* MarshmallowsTesting.app */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -81,7 +135,10 @@
7BE32D0814132EE4008F2DEA /* Frameworks */ = { 7BE32D0814132EE4008F2DEA /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7BD100F714136FD200A9921B /* GHUnitIOS.framework */,
7BE32D0914132EE4008F2DEA /* Foundation.framework */, 7BE32D0914132EE4008F2DEA /* Foundation.framework */,
7BD100B61413675100A9921B /* UIKit.framework */,
7BD100B91413675100A9921B /* CoreGraphics.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -135,6 +192,24 @@
/* End PBXHeadersBuildPhase section */ /* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
7BD100D414136F7500A9921B /* MarshmallowsTesting */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7BD100F414136F7500A9921B /* Build configuration list for PBXNativeTarget "MarshmallowsTesting" */;
buildPhases = (
7BD100D114136F7500A9921B /* Sources */,
7BD100D214136F7500A9921B /* Frameworks */,
7BD100D314136F7500A9921B /* Resources */,
);
buildRules = (
);
dependencies = (
7B13A56C1415CDA70033DCC2 /* PBXTargetDependency */,
);
name = MarshmallowsTesting;
productName = MarshmallowsTesting;
productReference = 7BD100D514136F7500A9921B /* MarshmallowsTesting.app */;
productType = "com.apple.product-type.application";
};
7BE32D0514132EE4008F2DEA /* Marshmallows */ = { 7BE32D0514132EE4008F2DEA /* Marshmallows */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 7BE32D1314132EE4008F2DEA /* Build configuration list for PBXNativeTarget "Marshmallows" */; buildConfigurationList = 7BE32D1314132EE4008F2DEA /* Build configuration list for PBXNativeTarget "Marshmallows" */;
@ -173,11 +248,32 @@
projectRoot = ""; projectRoot = "";
targets = ( targets = (
7BE32D0514132EE4008F2DEA /* Marshmallows */, 7BE32D0514132EE4008F2DEA /* Marshmallows */,
7BD100D414136F7500A9921B /* MarshmallowsTesting */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
7BD100D314136F7500A9921B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7BD100DF14136F7500A9921B /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
7BD100D114136F7500A9921B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7BD100E114136F7500A9921B /* main.m in Sources */,
7BD100FB141370B800A9921B /* NSDateTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7BE32D0214132EE4008F2DEA /* Sources */ = { 7BE32D0214132EE4008F2DEA /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -193,7 +289,71 @@
}; };
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
7B13A56C1415CDA70033DCC2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 7BE32D0514132EE4008F2DEA /* Marshmallows */;
targetProxy = 7B13A56B1415CDA70033DCC2 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
7BD100DD14136F7500A9921B /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
7BD100DE14136F7500A9921B /* en */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
7BD100F514136F7500A9921B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
"\"$(SRCROOT)\"",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "MarshmallowsTesting/MarshmallowsTesting-Prefix.pch";
INFOPLIST_FILE = "MarshmallowsTesting/MarshmallowsTesting-Info.plist";
OTHER_LDFLAGS = (
"-all_load",
"-ObjC",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Debug;
};
7BD100F614136F7500A9921B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(DEVELOPER_FRAMEWORKS_DIR)\"",
"\"$(SRCROOT)\"",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "MarshmallowsTesting/MarshmallowsTesting-Prefix.pch";
INFOPLIST_FILE = "MarshmallowsTesting/MarshmallowsTesting-Info.plist";
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = (
"-all_load",
"-ObjC",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
name = Release;
};
7BE32D1114132EE4008F2DEA /* Debug */ = { 7BE32D1114132EE4008F2DEA /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -269,6 +429,15 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
7BD100F414136F7500A9921B /* Build configuration list for PBXNativeTarget "MarshmallowsTesting" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7BD100F514136F7500A9921B /* Debug */,
7BD100F614136F7500A9921B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7BE32D0014132EE3008F2DEA /* Build configuration list for PBXProject "Marshmallows" */ = { 7BE32D0014132EE3008F2DEA /* Build configuration list for PBXProject "Marshmallows" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (

View file

@ -0,0 +1,43 @@
<?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>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>net.samhuri.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,14 @@
//
// Prefix header for all source files of the 'MarshmallowsTesting' target in the 'MarshmallowsTesting' project
//
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iPhone SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif

View file

@ -0,0 +1,144 @@
//
// NSDateTest.m
// Marshmallows
//
// Created by Sami Samhuri on 11-09-04.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import <GHUnitIOS/GHUnit.h>
#import "NSDate+relative.h"
#define MINUTE 60.0
#define HOUR (60.0 * MINUTE)
#define DAY (24.0 * HOUR)
#define WEEK (7.0 * DAY)
#define MONTH (30.0 * DAY)
#define YEAR (365.25 * DAY)
@interface NSDateTest : GHTestCase { }
@end
@implementation NSDateTest
- (void) testMethodExists
{
NSDate *date = [NSDate date];
GHAssertTrue([date respondsToSelector: @selector(relativeToNow)], @"Extension method -[NSDate relativeToNow] not available");
}
- (void) testPastDates
{
NSDate *date;
// < 1 minute ago
date = [NSDate dateWithTimeIntervalSinceNow: -59.0];
GHAssertEqualStrings(@"right now", [date relativeToNow], @"Incorrect relative date.");
// < 2 minutes ago
date = [NSDate dateWithTimeIntervalSinceNow: -119.0];
GHAssertEqualStrings(@"a minute ago", [date relativeToNow], @"Incorrect relative date.");
// < 1 hour ago
date = [NSDate dateWithTimeIntervalSinceNow: -57 * MINUTE];
GHAssertEqualStrings(@"57 minutes ago", [date relativeToNow], @"Incorrect relative date.");
// < 2 hours ago
date = [NSDate dateWithTimeIntervalSinceNow: -117 * MINUTE];
GHAssertEqualStrings(@"an hour ago", [date relativeToNow], @"Incorrect relative date.");
// < 1 day ago
date = [NSDate dateWithTimeIntervalSinceNow: -23 * HOUR];
GHAssertEqualStrings(@"23 hours ago", [date relativeToNow], @"Incorrect relative date.");
// < 2 days ago
date = [NSDate dateWithTimeIntervalSinceNow: -47 * HOUR];
GHAssertEqualStrings(@"yesterday", [date relativeToNow], @"Incorrect relative date.");
// < 1 week ago
date = [NSDate dateWithTimeIntervalSinceNow: -6 * DAY];
GHAssertEqualStrings(@"6 days ago", [date relativeToNow], @"Incorrect relative date.");
// < 2 weeks ago
date = [NSDate dateWithTimeIntervalSinceNow: -13 * DAY];
GHAssertEqualStrings(@"last week", [date relativeToNow], @"Incorrect relative date.");
// < 4 weeks ago
date = [NSDate dateWithTimeIntervalSinceNow: -3 * WEEK];
GHAssertEqualStrings(@"3 weeks ago", [date relativeToNow], @"Incorrect relative date.");
// < 8 weeks ago
date = [NSDate dateWithTimeIntervalSinceNow: -7 * WEEK];
GHAssertEqualStrings(@"last month", [date relativeToNow], @"Incorrect relative date.");
// < 1 year ago
date = [NSDate dateWithTimeIntervalSinceNow: -11 * MONTH];
GHAssertEqualStrings(@"11 months ago", [date relativeToNow], @"Incorrect relative date.");
// last year
date = [NSDate dateWithTimeIntervalSinceNow: -729 * DAY];
GHAssertEqualStrings(@"last year", [date relativeToNow], @"Incorrect relative date.");
// 5 years ago
date = [NSDate dateWithTimeIntervalSinceNow: -5 * YEAR - 1];
GHAssertEqualStrings(@"5 years ago", [date relativeToNow], @"Incorrect relative date.");
}
- (void) testFutureDates
{
NSDate *date;
// within 1 minute
date = [NSDate dateWithTimeIntervalSinceNow: 59.0];
GHAssertEqualStrings(@"right now", [date relativeToNow], @"Incorrect relative date.");
// within 2 minutes
date = [NSDate dateWithTimeIntervalSinceNow: 119.0];
GHAssertEqualStrings(@"in a minute", [date relativeToNow], @"Incorrect relative date.");
// within 1 hour
date = [NSDate dateWithTimeIntervalSinceNow: 57 * MINUTE + 1];
GHAssertEqualStrings(@"in 57 minutes", [date relativeToNow], @"Incorrect relative date.");
// in an hour
date = [NSDate dateWithTimeIntervalSinceNow: 117 * MINUTE];
GHAssertEqualStrings(@"in an hour", [date relativeToNow], @"Incorrect relative date.");
// within 1 day
date = [NSDate dateWithTimeIntervalSinceNow: 23 * HOUR + 1];
GHAssertEqualStrings(@"in 23 hours", [date relativeToNow], @"Incorrect relative date.");
// tomorrow
date = [NSDate dateWithTimeIntervalSinceNow: 47 * HOUR];
GHAssertEqualStrings(@"tomorrow", [date relativeToNow], @"Incorrect relative date.");
// within 1 week
date = [NSDate dateWithTimeIntervalSinceNow: 6 * DAY + 1];
GHAssertEqualStrings(@"in 6 days", [date relativeToNow], @"Incorrect relative date.");
// next week
date = [NSDate dateWithTimeIntervalSinceNow: 13 * DAY];
GHAssertEqualStrings(@"next week", [date relativeToNow], @"Incorrect relative date.");
// within 4 weeks
date = [NSDate dateWithTimeIntervalSinceNow: 3 * WEEK + 1];
GHAssertEqualStrings(@"in 3 weeks", [date relativeToNow], @"Incorrect relative date.");
// next month
date = [NSDate dateWithTimeIntervalSinceNow: 7 * WEEK];
GHAssertEqualStrings(@"next month", [date relativeToNow], @"Incorrect relative date.");
// within 1 year
date = [NSDate dateWithTimeIntervalSinceNow: 11 * MONTH + 1];
GHAssertEqualStrings(@"in 11 months", [date relativeToNow], @"Incorrect relative date.");
// next year
date = [NSDate dateWithTimeIntervalSinceNow: 729 * DAY];
GHAssertEqualStrings(@"next year", [date relativeToNow], @"Incorrect relative date.");
// in year 5 years
date = [NSDate dateWithTimeIntervalSinceNow: 5 * YEAR + 1];
GHAssertEqualStrings(@"in 5 years", [date relativeToNow], @"Incorrect relative date.");
}
@end

View file

@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */

View file

@ -0,0 +1,17 @@
//
// main.m
// MarshmallowsTesting
//
// Created by Sami Samhuri on 11-09-04.
// Copyright 2011 Guru Logic. All rights reserved.
//
#import <UIKit/UIKit.h>
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, @"GHUnitIPhoneAppDelegate");
[pool release];
return retVal;
}