aboutsummaryrefslogtreecommitdiff
path: root/UnitTesting/GTMFoundationUnitTestingUtilities.h
blob: 715a37285f5a20c378191517acd74defc2251f22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
//  GTMFoundationUnitTestingUtilities.h
//
//  Copyright 2006-2010 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 <objc/objc.h>

// NOTE:  These utilities predate XCTestExpectation (introduced with Xcode 6).
//        Newer unit tests should use [self waitForExpectationsWithTimeout:]
//        to spin the run loop instead of using the context utilities below.

// Many tests need to spin the runloop and wait for an event to happen. This is
// often done by calling:
// NSDate* next = [NSDate dateWithTimeIntervalSinceNow:resolution];
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
//                          beforeDate:next];
// where |resolution| is a guess at how long it will take for the event to
// happen. There are two major problems with this approach:
// a) By guessing we force the test to take at least |resolution| time.
// b) It makes for flaky tests in that sometimes this guess isn't good, and the
//    test takes slightly longer than |resolution| time causing the test to post
//    a possibly false-negative failure.
// To make timing callback tests easier use this class and the
// GTMUnitTestingAdditions additions to NSRunLoop and NSApplication.
// Your call would look something like this:
// id<GTMUnitTestingRunLoopContext> context = [self getMeAContext];
// [[NSRunLoop currentRunLoop] gtm_runUpToSixtySecondsWithContext:context];
// Then in some callback method within your test you would call
// [context setShouldStop:YES];
// Internally gtm_runUpToSixtySecondsWithContext will poll the runloop really
// quickly to keep test times down to a minimum, but will stop after a good time
// interval (in this case 60 seconds) for failures.
@protocol GTMUnitTestingRunLoopContext
// Return YES if the NSRunLoop (or equivalent) that this context applies to
// should stop as soon as possible.
- (BOOL)shouldStop;
@end

// Collection of utilities for unit testing
@interface GTMFoundationUnitTestingUtilities : NSObject

// Returns YES if we are currently being unittested.
+ (BOOL)areWeBeingUnitTested;


// Installs a timer to quit the process after the given time, as a catch all for
// something not working.  There is a problem that of the testing bundle fails
// to load when is is being hosted in a custom app, the app will remain running
// until the user quits it.  This provides a way out of that.  When the timer
// fires, a message is logged, and the process is directly exited, no clean
// shutdown.  This requires a runloop be running.
+ (void)installTestingTimeout:(NSTimeInterval)maxRunInterval;

@end

// An implementation of the GTMUnitTestingRunLoopContext that is a simple
// BOOL flag. See GTMUnitTestingRunLoopContext documentation.
@interface GTMUnitTestingBooleanRunLoopContext : NSObject <GTMUnitTestingRunLoopContext> {
 @private
  BOOL shouldStop_;
}
+ (id)context;
- (BOOL)shouldStop;
- (void)setShouldStop:(BOOL)stop;
- (void)reset;
@end

// Some category methods to simplify spinning the runloops in such a way as
// to make tests less flaky, but have them complete as fast as possible.
@interface NSRunLoop (GTMUnitTestingAdditions)
// Will spin the runloop in mode until date in mode until the runloop returns
// because all sources have been removed or the current date is greater than
// |date| or [context shouldStop] returns YES.
// Return YES if the runloop was stopped because [context shouldStop] returned
// YES.
- (BOOL)gtm_runUntilDate:(NSDate *)date
                    mode:(NSString *)mode
                 context:(id<GTMUnitTestingRunLoopContext>)context
    NS_DEPRECATED(10_4, 10_8, 1_0, 7_0, "Please move to XCTestExpectations");

// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode.
- (BOOL)gtm_runUntilDate:(NSDate *)date
                 context:(id<GTMUnitTestingRunLoopContext>)context
    NS_DEPRECATED(10_4, 10_8, 1_0, 7_0, "Please move to XCTestExpectations");

// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode,
// and the timeout date set to |seconds| seconds.
- (BOOL)gtm_runUpToNSeconds:(NSTimeInterval)seconds
                    context:(id<GTMUnitTestingRunLoopContext>)context
    NS_DEPRECATED(10_4, 10_8, 1_0, 7_0, "Please move to XCTestExpectations");

// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode,
// and the timeout date set to 60 seconds.
// This is a good time to use for AppleEvent calls (which default to 60 seconds)
// but may be a bit long for standard unit tests, and could cause a long unit
// testing run if you have multiple failures.
// Calling -[gtm_runUpToNSeconds:context:] is preferred.
- (BOOL)gtm_runUpToSixtySecondsWithContext:(id<GTMUnitTestingRunLoopContext>)context
    NS_DEPRECATED(10_4, 10_8, 1_0, 7_0, "Please move to XCTestExpectations");

@end