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
|
//
// 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>
// 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;
@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;
// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode.
- (BOOL)gtm_runUntilDate:(NSDate *)date
context:(id<GTMUnitTestingRunLoopContext>)context;
// Calls -gtm_runUntilDate:mode:context: with mode set to NSDefaultRunLoopMode,
// and the timeout date set to 60 seconds.
- (BOOL)gtm_runUpToSixtySecondsWithContext:(id<GTMUnitTestingRunLoopContext>)context;
@end
|