paulanthonywilson-iphone_testify 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.0 / 2009-02-25
2
+
3
+ * Getting started
data/README.rdoc ADDED
@@ -0,0 +1,89 @@
1
+ iphone_testify
2
+ by Paul Wilson
3
+ http://merecomplexities.com
4
+
5
+ == DESCRIPTION:
6
+
7
+ Utility to help set up and iPhone project for testing using code from {The Google Toolbox for Mac}[http://code.google.com/p/google-toolbox-for-mac/].
8
+
9
+ == FEATURES:
10
+
11
+ * Copies google test files into the "google_testing" directory
12
+ * Creates a UnitTests directory
13
+ * Adds Rakefile for compiling (via xcode) and reporting test failures (on console and via Growl)
14
+ * Adds an 'autoiphonetest.rb' file for _autotest_ style running of all tests when a change has been detected.
15
+
16
+ == TODO:
17
+
18
+ There are a few more things I'd like this gem to do.
19
+
20
+ * Generation of test stubs
21
+ * Automatic setup of _Unit Test_ target through XCode (via automation?)
22
+ * Automatic addition of test files to _Unit Test_ target
23
+
24
+ == SYNOPSIS:
25
+
26
+ From console cd to your project root directory. Type
27
+ % iphone_testify
28
+
29
+ Unfortunately there are some manual stages needed to add a _Unit Test_ target to your Xcode project. This is based on the {Google Toolbox Wiki instructions}[http://code.google.com/p/google-toolbox-for-mac/wiki/iPhoneUnitTesting]
30
+
31
+ 1. Create a new iPhone Target (Cocoa Touch Application) via "Project Menu > New Target..." called "Unit Test".
32
+ 2. Add all the ObjectiveC files that have been copied to your 'google_testing' directory to this target
33
+ 3. Add your project files to this target
34
+ 4. Add a new 'run script' build phase as the last step of your target build via "Project Menu > New Build Phase > New Run Script Build Phase", and dragging it to the end of the build steps if needed.
35
+ 5. Edit your Run Script Build Phase by double clicking it, and set the shell to "/bin/sh" and the script to "google_testing/RunIPhoneUnitTest.sh"
36
+
37
+
38
+ To autocompile/autorun all tests every time code changes
39
+
40
+ % ./autoiphonetest.rb
41
+
42
+
43
+ To compile and run tests if code has changed since the last run
44
+
45
+ % rake
46
+
47
+ To compile and run all tests even if nothing has changed since the last time
48
+
49
+ % rake test_all
50
+
51
+
52
+ == REQUIREMENTS:
53
+
54
+ * OS X Leopard
55
+ * XCode 3.1 (containing the iPhone SDK)
56
+ * Ruby (comes on Leopard)
57
+
58
+ == INSTALL:
59
+
60
+ % sudo gem sources -a http://gems.github.com # (you only need to do this once)
61
+ % sudo gem install paulanthonywilson-iphone_testify
62
+
63
+ == LICENSE:
64
+
65
+ Contains file taken from {The Google Toolbox for Mac}[http://code.google.com/p/google-toolbox-for-mac/]. See skeleton/google_testing/GoogleToolboxForMac.license which is also copied into the google_testing directory.
66
+
67
+
68
+ (The MIT License)
69
+
70
+ Copyright (c) 2008
71
+
72
+ Permission is hereby granted, free of charge, to any person obtaining
73
+ a copy of this software and associated documentation files (the
74
+ 'Software'), to deal in the Software without restriction, including
75
+ without limitation the rights to use, copy, modify, merge, publish,
76
+ distribute, sublicense, and/or sell copies of the Software, and to
77
+ permit persons to whom the Software is furnished to do so, subject to
78
+ the following conditions:
79
+
80
+ The above copyright notice and this permission notice shall be
81
+ included in all copies or substantial portions of the Software.
82
+
83
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
84
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
85
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
86
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
87
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
88
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
89
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'iphone_testify'
18
+
19
+ task :default => 'test:run'
20
+
21
+ PROJ.name = 'iphone_testify'
22
+ PROJ.authors = 'Paul Wilson'
23
+ PROJ.email = 'paul.wilson@merecomplexities.com'
24
+ PROJ.url = 'http://github.com/paulanthonywilson/iphone_testify/'
25
+ PROJ.version = IphoneTestify::VERSION
26
+
27
+ PROJ.exclude << '\.gitignore'
28
+ PROJ.notes.exclude = %w(^README\.txt$ ^data/)
29
+ PROJ.readme_file = 'README.rdoc'
30
+
31
+ depend_on "paulanthonywilson-osx_filewatcher"
32
+ depend_on "rake"
33
+
34
+ # EOF
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib iphone_testify]))
5
+
6
+ # Put your code here
7
+ IphoneTestify::Setup::setup
8
+
9
+ # EOF
Binary file
@@ -0,0 +1,13 @@
1
+ require 'fileutils'
2
+
3
+ module IphoneTestify
4
+
5
+ module Setup
6
+ SKELETONDIR = GEMDIR + "/skeleton"
7
+ extend FileUtils
8
+ def self.setup
9
+ cp_r "#{SKELETONDIR}/.", "."
10
+ mkdir_p "UnitTests"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+
2
+ module IphoneTestify
3
+ GEMDIR = File.expand_path(File.dirname(__FILE__) + "/..")
4
+ # :stopdoc:
5
+ VERSION = '0.0.1'
6
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
7
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
8
+ # :startdoc:
9
+
10
+ # Returns the version string for the library.
11
+ #
12
+ def self.version
13
+ VERSION
14
+ end
15
+
16
+ # Returns the library path for the module. If any arguments are given,
17
+ # they will be joined to the end of the libray path using
18
+ # <tt>File.join</tt>.
19
+ #
20
+ def self.libpath( *args )
21
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
22
+ end
23
+
24
+ # Returns the lpath for the module. If any arguments are given,
25
+ # they will be joined to the end of the path using
26
+ # <tt>File.join</tt>.
27
+ #
28
+ def self.path( *args )
29
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
30
+ end
31
+
32
+ # Utility method used to require all files ending in .rb that lie in the
33
+ # directory below this file that has the same name as the filename passed
34
+ # in. Optionally, a specific _directory_ name can be passed in such that
35
+ # the _filename_ does not have to be equivalent to the directory.
36
+ #
37
+ def self.require_all_libs_relative_to( fname, dir = nil )
38
+ dir ||= ::File.basename(fname, '.*')
39
+ search_me = ::File.expand_path(
40
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
41
+
42
+ Dir.glob(search_me).sort.each {|rb| require rb}
43
+ end
44
+
45
+ end # module IphoneTestify
46
+
47
+ IphoneTestify.require_all_libs_relative_to(__FILE__)
48
+
49
+ # EOF
data/skeleton/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+
2
+ BUILD_STATUS_FILE=".built"
3
+
4
+ class String
5
+ attr_accessor :colour
6
+ RESET="\e[00;m"
7
+
8
+ def coloured(colour = nil)
9
+ colour||=@colour
10
+ "#{colour_code(colour)}#{self}#{RESET}"
11
+ end
12
+
13
+ private
14
+ def colour_code colour
15
+ case colour
16
+ when :red : "\e[01;31m"
17
+ when :green : "\e[01;32m"
18
+ end
19
+ end
20
+ end
21
+
22
+ file BUILD_STATUS_FILE => Dir.glob("Classes/*.[hm]") + Dir.glob("UnitTests/*.m") do
23
+ failure_line = test
24
+ if failure_line
25
+ notice = ['Fail', failure_line.chomp]
26
+ else
27
+ notice = ['Pass']
28
+ end
29
+ growl *notice
30
+ File.open(BUILD_STATUS_FILE, 'w') {|f| f.write(notice * ": ")}
31
+ end
32
+
33
+ task :remove_built_file do
34
+ FileUtils.rm(BUILD_STATUS_FILE)
35
+ end
36
+
37
+ task :test_all=>[:remove_built_file, :test]
38
+
39
+ task :test=>[BUILD_STATUS_FILE] do
40
+ out = File.open('.built') {|f| f.read}
41
+ print out.coloured(out =~ /Pass/ ? :green : :red) + "\n"
42
+ end
43
+
44
+
45
+
46
+ task :default => [:test]
47
+
48
+ def test
49
+ output = `xcodebuild -target "Unit Test" -configuration Debug -sdk iphonesimulator2.1`
50
+ failure_line = nil
51
+ output.each do |line|
52
+ if line =~ /error:|^Executed.*(\d+) failures/
53
+ if $1.nil? || $1.to_i > 0
54
+ failure_line||= line
55
+ line.colour = :red
56
+ else
57
+ line.colour = :green
58
+ end
59
+ end
60
+ print line.coloured
61
+ end
62
+ failure_line
63
+ end
64
+
65
+ def growl title, msg =""
66
+ img = "~/.autotest_images/#{title.downcase}.png"
67
+ `growlnotify -H localhost -n autotest --image #{img} -p 0 -m #{msg.inspect} #{title}`
68
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'osx_watchfolder'
5
+ gem 'rake'
6
+
7
+
8
+ ARGV.clear
9
+
10
+ fork do
11
+ ARGV << 'test_all'
12
+ load 'rake'
13
+ end
14
+ OsxWatchfolder::FolderWatcher.new("Classes", "UnitTests") do
15
+ fork{load 'rake'}
16
+ end.start
@@ -0,0 +1,166 @@
1
+ //
2
+ // GTMDefines.h
3
+ //
4
+ // Copyright 2008 Google Inc.
5
+ //
6
+ // Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ // use this file except in compliance with the License. You may obtain a copy
8
+ // of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ // License for the specific language governing permissions and limitations under
16
+ // the License.
17
+ //
18
+
19
+ // ============================================================================
20
+
21
+ // ----------------------------------------------------------------------------
22
+ // CPP symbols that can be overridden in a prefix to control how the toolbox
23
+ // is compiled.
24
+ // ----------------------------------------------------------------------------
25
+
26
+
27
+ // GTMHTTPFetcher will support logging by default but only hook its input
28
+ // stream support for logging when requested. You can control the inclusion of
29
+ // the code by providing your own definitions for these w/in a prefix header.
30
+ //
31
+ #ifndef GTM_HTTPFETCHER_ENABLE_LOGGING
32
+ # define GTM_HTTPFETCHER_ENABLE_LOGGING 1
33
+ #endif // GTM_HTTPFETCHER_ENABLE_LOGGING
34
+ #ifndef GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING
35
+ # define GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING 0
36
+ #endif // GTM_HTTPFETCHER_ENABLE_INPUTSTREAM_LOGGING
37
+
38
+
39
+ // _GTMDevLog & _GTMDevAssert
40
+ //
41
+ // _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
42
+ // developer level errors. This implementation simply macros to NSLog/NSAssert.
43
+ // It is not intended to be a general logging/reporting system.
44
+ //
45
+ // Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert
46
+ // for a little more background on the usage of these macros.
47
+ //
48
+ // _GTMDevLog log some error/problem in debug builds
49
+ // _GTMDevAssert assert if conditon isn't met w/in a method/function
50
+ // in all builds.
51
+ //
52
+ // To replace this system, just provide different macro definitions in your
53
+ // prefix header. Remember, any implementation you provide *must* be thread
54
+ // safe since this could be called by anything in what ever situtation it has
55
+ // been placed in.
56
+ //
57
+
58
+ // We only define the simple macros if nothing else has defined this.
59
+ #ifndef _GTMDevLog
60
+
61
+ #ifdef DEBUG
62
+ #define _GTMDevLog(...) NSLog(__VA_ARGS__)
63
+ #else
64
+ #define _GTMDevLog(...) do { } while (0)
65
+ #endif
66
+
67
+ #endif // _GTMDevLog
68
+
69
+ // Declared here so that it can easily be used for logging tracking if
70
+ // necessary. See GTMUnitTestDevLog.h for details.
71
+ @class NSString;
72
+ extern void _GTMUnittestDevLog(NSString *format, ...);
73
+
74
+ #ifndef _GTMDevAssert
75
+ // we directly invoke the NSAssert handler so we can pass on the varargs
76
+ // (NSAssert doesn't have a macro we can use that takes varargs)
77
+ #if !defined(NS_BLOCK_ASSERTIONS)
78
+ #define _GTMDevAssert(condition, ...) \
79
+ do { \
80
+ if (!(condition)) { \
81
+ [[NSAssertionHandler currentHandler] \
82
+ handleFailureInFunction:[NSString stringWithCString:__PRETTY_FUNCTION__] \
83
+ file:[NSString stringWithCString:__FILE__] \
84
+ lineNumber:__LINE__ \
85
+ description:__VA_ARGS__]; \
86
+ } \
87
+ } while(0)
88
+ #else // !defined(NS_BLOCK_ASSERTIONS)
89
+ #define _GTMDevAssert(condition, ...) do { } while (0)
90
+ #endif // !defined(NS_BLOCK_ASSERTIONS)
91
+
92
+ #endif // _GTMDevAssert
93
+
94
+ // _GTMCompileAssert
95
+ // _GTMCompileAssert is an assert that is meant to fire at compile time if you
96
+ // want to check things at compile instead of runtime. For example if you
97
+ // want to check that a wchar is 4 bytes instead of 2 you would use
98
+ // _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X)
99
+ // Note that the second "arg" is not in quotes, and must be a valid processor
100
+ // symbol in it's own right (no spaces, punctuation etc).
101
+
102
+ // Wrapping this in an #ifndef allows external groups to define their own
103
+ // compile time assert scheme.
104
+ #ifndef _GTMCompileAssert
105
+ // We got this technique from here:
106
+ // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html
107
+
108
+ #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg
109
+ #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)
110
+ #define _GTMCompileAssert(test, msg) \
111
+ typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
112
+ #endif // _GTMCompileAssert
113
+
114
+ // ============================================================================
115
+
116
+ // ----------------------------------------------------------------------------
117
+ // CPP symbols defined based on the project settings so the GTM code has
118
+ // simple things to test against w/o scattering the knowledge of project
119
+ // setting through all the code.
120
+ // ----------------------------------------------------------------------------
121
+
122
+ // Provide a single constant CPP symbol that all of GTM uses for ifdefing
123
+ // iPhone code.
124
+ #include <TargetConditionals.h>
125
+ #if TARGET_OS_IPHONE // iPhone SDK
126
+ // For iPhone specific stuff
127
+ #define GTM_IPHONE_SDK 1
128
+ #else
129
+ // For MacOS specific stuff
130
+ #define GTM_MACOS_SDK 1
131
+ #endif
132
+
133
+ // To simplify support for 64bit (and Leopard in general), we provide the type
134
+ // defines for non Leopard SDKs
135
+ #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
136
+ // NSInteger/NSUInteger and Max/Mins
137
+ #ifndef NSINTEGER_DEFINED
138
+ #if __LP64__ || NS_BUILD_32_LIKE_64
139
+ typedef long NSInteger;
140
+ typedef unsigned long NSUInteger;
141
+ #else
142
+ typedef int NSInteger;
143
+ typedef unsigned int NSUInteger;
144
+ #endif
145
+ #define NSIntegerMax LONG_MAX
146
+ #define NSIntegerMin LONG_MIN
147
+ #define NSUIntegerMax ULONG_MAX
148
+ #define NSINTEGER_DEFINED 1
149
+ #endif // NSINTEGER_DEFINED
150
+ // CGFloat
151
+ #ifndef CGFLOAT_DEFINED
152
+ #if defined(__LP64__) && __LP64__
153
+ // This really is an untested path (64bit on Tiger?)
154
+ typedef double CGFloat;
155
+ #define CGFLOAT_MIN DBL_MIN
156
+ #define CGFLOAT_MAX DBL_MAX
157
+ #define CGFLOAT_IS_DOUBLE 1
158
+ #else /* !defined(__LP64__) || !__LP64__ */
159
+ typedef float CGFloat;
160
+ #define CGFLOAT_MIN FLT_MIN
161
+ #define CGFLOAT_MAX FLT_MAX
162
+ #define CGFLOAT_IS_DOUBLE 0
163
+ #endif /* !defined(__LP64__) || !__LP64__ */
164
+ #define CGFLOAT_DEFINED 1
165
+ #endif // CGFLOAT_DEFINED
166
+ #endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
@@ -0,0 +1,29 @@
1
+ //
2
+ // GTMIPhoneUnitTestDelegate.h
3
+ //
4
+ // Copyright 2008 Google Inc.
5
+ //
6
+ // Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ // use this file except in compliance with the License. You may obtain a copy
8
+ // of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ // License for the specific language governing permissions and limitations under
16
+ // the License.
17
+ //
18
+
19
+ // Application delegate that runs all test methods in registered classes
20
+ // extending SenTestCase. The application is terminated afterwards.
21
+ // You can also run the tests directly from your application by invoking
22
+ // gtm_runTests and clean up, restore data, etc. before the application
23
+ // terminates.
24
+ @interface GTMIPhoneUnitTestDelegate : NSObject
25
+ // Runs through all the registered classes and runs test methods on any
26
+ // that are subclasses of SenTestCase. Prints results and run time to
27
+ // the default output.
28
+ - (void)runTests;
29
+ @end
@@ -0,0 +1,160 @@
1
+ //
2
+ // GTMIPhoneUnitTestDelegate.m
3
+ //
4
+ // Copyright 2008 Google Inc.
5
+ //
6
+ // Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ // use this file except in compliance with the License. You may obtain a copy
8
+ // of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ // License for the specific language governing permissions and limitations under
16
+ // the License.
17
+ //
18
+
19
+ #import "GTMIPhoneUnitTestDelegate.h"
20
+
21
+ #import "GTMDefines.h"
22
+ #if !GTM_IPHONE_SDK
23
+ #error GTMIPhoneUnitTestDelegate for iPhone only
24
+ #endif
25
+ #import <objc/runtime.h>
26
+ #import <stdio.h>
27
+ #import <UIKit/UIKit.h>
28
+ #import "GTMSenTestCase.h"
29
+
30
+ // Used for sorting methods below
31
+ static int MethodSort(const void *a, const void *b) {
32
+ const char *nameA = sel_getName(method_getName(*(Method*)a));
33
+ const char *nameB = sel_getName(method_getName(*(Method*)b));
34
+ return strcmp(nameA, nameB);
35
+ }
36
+
37
+ @interface UIApplication (iPhoneUnitTestAdditions)
38
+ // "Private" method that we need
39
+ - (void)terminate;
40
+ @end
41
+
42
+ @implementation GTMIPhoneUnitTestDelegate
43
+
44
+ // Return YES if class is subclass (1 or more generations) of SenTestCase
45
+ - (BOOL)isTestFixture:(Class)aClass {
46
+ BOOL iscase = NO;
47
+ Class testCaseClass = [SenTestCase class];
48
+ Class superclass;
49
+ for (superclass = aClass;
50
+ !iscase && superclass;
51
+ superclass = class_getSuperclass(superclass)) {
52
+ iscase = superclass == testCaseClass ? YES : NO;
53
+ }
54
+ return iscase;
55
+ }
56
+
57
+ // Run through all the registered classes and run test methods on any
58
+ // that are subclasses of SenTestCase. Terminate the application upon
59
+ // test completion.
60
+ - (void)applicationDidFinishLaunching:(UIApplication *)application {
61
+ [self runTests];
62
+ // Using private call to end our tests
63
+ [[UIApplication sharedApplication] terminate];
64
+ }
65
+
66
+ // Run through all the registered classes and run test methods on any
67
+ // that are subclasses of SenTestCase. Print results and run time to
68
+ // the default output.
69
+ - (void)runTests {
70
+ int count = objc_getClassList(NULL, 0);
71
+ Class *classes = (Class*)malloc(sizeof(Class) * count);
72
+ _GTMDevAssert(classes, @"Couldn't allocate class list");
73
+ objc_getClassList(classes, count);
74
+ int suiteSuccesses = 0;
75
+ int suiteFailures = 0;
76
+ int suiteTotal = 0;
77
+ NSString *suiteName = [[NSBundle mainBundle] bundlePath];
78
+ NSDate *suiteStartDate = [NSDate date];
79
+ NSString *suiteStartString = [NSString stringWithFormat:@"Test Suite '%@' started at %@\n",
80
+ suiteName, suiteStartDate];
81
+ fputs([suiteStartString UTF8String], stderr);
82
+ fflush(stderr);
83
+ for (int i = 0; i < count; ++i) {
84
+ Class currClass = classes[i];
85
+ if ([self isTestFixture:currClass]) {
86
+ NSDate *fixtureStartDate = [NSDate date];
87
+ NSString *fixtureName = NSStringFromClass(currClass);
88
+ NSString *fixtureStartString = [NSString stringWithFormat:@"Test Suite '%@' started at %@\n",
89
+ fixtureName, fixtureStartDate];
90
+ int fixtureSuccesses = 0;
91
+ int fixtureFailures = 0;
92
+ int fixtureTotal = 0;
93
+ fputs([fixtureStartString UTF8String], stderr);
94
+ fflush(stderr);
95
+ id testcase = [[currClass alloc] init];
96
+ _GTMDevAssert(testcase, @"Unable to instantiate Test Suite: '%@'\n",
97
+ fixtureName);
98
+ unsigned int methodCount;
99
+ Method *methods = class_copyMethodList(currClass, &methodCount);
100
+ // Sort our methods so they are called in Alphabetical order just
101
+ // because we can.
102
+ qsort(methods, methodCount, sizeof(Method), MethodSort);
103
+ for (size_t j = 0; j < methodCount; ++j) {
104
+ Method currMethod = methods[j];
105
+ SEL sel = method_getName(currMethod);
106
+ const char *name = sel_getName(sel);
107
+ // If it starts with test, run it.
108
+ if (strstr(name, "test") == name) {
109
+ fixtureTotal += 1;
110
+ BOOL failed = NO;
111
+ NSDate *caseStartDate = [NSDate date];
112
+ @try {
113
+ [testcase performTest:sel];
114
+ } @catch (NSException *exception) {
115
+ failed = YES;
116
+ }
117
+ if (failed) {
118
+ fixtureFailures += 1;
119
+ } else {
120
+ fixtureSuccesses += 1;
121
+ }
122
+ NSTimeInterval caseEndTime = [[NSDate date] timeIntervalSinceDate:caseStartDate];
123
+ NSString *caseEndString = [NSString stringWithFormat:@"Test Case '-[%@ %s]' %s (%0.3f seconds).\n",
124
+ fixtureName, name,
125
+ failed ? "failed" : "passed", caseEndTime];
126
+ fputs([caseEndString UTF8String], stderr);
127
+ fflush(stderr);
128
+ }
129
+ }
130
+ if (methods) {
131
+ free(methods);
132
+ }
133
+ [testcase release];
134
+ NSDate *fixtureEndDate = [NSDate date];
135
+ NSTimeInterval fixtureEndTime = [fixtureEndDate timeIntervalSinceDate:fixtureStartDate];
136
+ NSString *fixtureEndString = [NSString stringWithFormat:@"Test Suite '%@' finished at %@.\n"
137
+ "Executed %d tests, with %d failures (%d unexpected) in %0.3f (%0.3f) seconds\n",
138
+ fixtureName, fixtureEndDate, fixtureTotal,
139
+ fixtureFailures, fixtureFailures,
140
+ fixtureEndTime, fixtureEndTime];
141
+
142
+ fputs([fixtureEndString UTF8String], stderr);
143
+ fflush(stderr);
144
+ suiteTotal += fixtureTotal;
145
+ suiteSuccesses += fixtureSuccesses;
146
+ suiteFailures += fixtureFailures;
147
+ }
148
+ }
149
+ NSDate *suiteEndDate = [NSDate date];
150
+ NSTimeInterval suiteEndTime = [suiteEndDate timeIntervalSinceDate:suiteStartDate];
151
+ NSString *suiteEndString = [NSString stringWithFormat:@"Test Suite '%@' finished at %@.\n"
152
+ "Executed %d tests, with %d failures (%d unexpected) in %0.3f (%0.3f) seconds\n",
153
+ suiteName, suiteEndDate, suiteTotal,
154
+ suiteFailures, suiteFailures,
155
+ suiteEndTime, suiteEndTime];
156
+ fputs([suiteEndString UTF8String], stderr);
157
+ fflush(stderr);
158
+ }
159
+
160
+ @end
@@ -0,0 +1,33 @@
1
+ //
2
+ // GTMIPhoneUnitTestMain.m
3
+ //
4
+ // Copyright 2008 Google Inc.
5
+ //
6
+ // Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
+ // use this file except in compliance with the License. You may obtain a copy
8
+ // of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ // License for the specific language governing permissions and limitations under
16
+ // the License.
17
+ //
18
+
19
+ #import "GTMDefines.h"
20
+ #if !GTM_IPHONE_SDK
21
+ #error GTMIPhoneUnitTestMain for iPhone only
22
+ #endif
23
+ #import <UIKit/UIKit.h>
24
+
25
+ // Creates an application that runs all tests from classes extending
26
+ // SenTestCase, outputs results and test run time, and terminates right
27
+ // afterwards.
28
+ int main(int argc, char *argv[]) {
29
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
30
+ int retVal = UIApplicationMain(argc, argv, nil, @"GTMIPhoneUnitTestDelegate");
31
+ [pool release];
32
+ return retVal;
33
+ }