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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
//---------------------------------------------------------------------------------------
// $Id: OCMockObject.m 53 2009-08-14 07:37:55Z erik $
// Copyright (c) 2004-2009 by Mulle Kybernetik. See License file for details.
//---------------------------------------------------------------------------------------
#import <OCMock/OCMockObject.h>
#import "OCClassMockObject.h"
#import "OCProtocolMockObject.h"
#import "OCPartialMockObject.h"
#import "OCObserverMockObject.h"
#import <OCMock/OCMockRecorder.h>
#import "NSInvocation+OCMAdditions.h"
@interface OCMockObject(Private)
+ (id)_makeNice:(OCMockObject *)mock;
- (NSString *)_recorderDescriptions:(BOOL)onlyExpectations;
@end
#pragma mark -
@implementation OCMockObject
#pragma mark Factory methods
+ (id)mockForClass:(Class)aClass
{
return [[[OCClassMockObject alloc] initWithClass:aClass] autorelease];
}
+ (id)mockForProtocol:(Protocol *)aProtocol
{
return [[[OCProtocolMockObject alloc] initWithProtocol:aProtocol] autorelease];
}
+ (id)partialMockForObject:(NSObject *)anObject
{
return [[[OCPartialMockObject alloc] initWithObject:anObject] autorelease];
}
+ (id)niceMockForClass:(Class)aClass
{
return [self _makeNice:[self mockForClass:aClass]];
}
+ (id)niceMockForProtocol:(Protocol *)aProtocol
{
return [self _makeNice:[self mockForProtocol:aProtocol]];
}
+ (id)_makeNice:(OCMockObject *)mock
{
mock->isNice = YES;
return mock;
}
+ (id)observerMock
{
return [[[OCObserverMockObject alloc] init] autorelease];
}
#pragma mark Initialisers, description, accessors, etc.
- (id)init
{
// no [super init], we're inheriting from NSProxy
expectationOrderMatters = NO;
recorders = [[NSMutableArray alloc] init];
expectations = [[NSMutableArray alloc] init];
exceptions = [[NSMutableArray alloc] init];
return self;
}
- (void)dealloc
{
[recorders release];
[expectations release];
[exceptions release];
[super dealloc];
}
- (NSString *)description
{
return @"OCMockObject";
}
- (void)setExpectationOrderMatters:(BOOL)flag
{
expectationOrderMatters = flag;
}
#pragma mark Public API
- (id)stub
{
OCMockRecorder *recorder = [self getNewRecorder];
[recorders addObject:recorder];
return recorder;
}
- (id)expect
{
OCMockRecorder *recorder = [self stub];
[expectations addObject:recorder];
return recorder;
}
- (void)verify
{
if([expectations count] == 1)
{
[NSException raise:NSInternalInconsistencyException format:@"%@: expected method was not invoked: %@",
[self description], [[expectations objectAtIndex:0] description]];
}
if([expectations count] > 0)
{
[NSException raise:NSInternalInconsistencyException format:@"%@ : %d expected methods were not invoked: %@",
[self description], [expectations count], [self _recorderDescriptions:YES]];
}
if([exceptions count] > 0)
{
[[exceptions objectAtIndex:0] raise];
}
}
#pragma mark Handling invocations
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if([self handleInvocation:anInvocation] == NO)
[self handleUnRecordedInvocation:anInvocation];
}
- (BOOL)handleInvocation:(NSInvocation *)anInvocation
{
OCMockRecorder *recorder = nil;
int i;
for(i = 0; i < [recorders count]; i++)
{
recorder = [recorders objectAtIndex:i];
if([recorder matchesInvocation:anInvocation])
break;
}
if(i == [recorders count])
return NO;
if([expectations containsObject:recorder])
{
if(expectationOrderMatters && ([expectations objectAtIndex:0] != recorder))
{
[NSException raise:NSInternalInconsistencyException format:@"%@: unexpected method invoked: %@\n\texpected:\t%@",
[self description], [recorder description], [[expectations objectAtIndex:0] description]];
}
[[recorder retain] autorelease];
[expectations removeObject:recorder];
[recorders removeObjectAtIndex:i];
}
[[recorder invocationHandlers] makeObjectsPerformSelector:@selector(handleInvocation:) withObject:anInvocation];
return YES;
}
- (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation
{
if(isNice == NO)
{
NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException reason:
[NSString stringWithFormat:@"%@: unexpected method invoked: %@ %@", [self description],
[anInvocation invocationDescription], [self _recorderDescriptions:NO]] userInfo:nil];
[exceptions addObject:exception];
[exception raise];
}
}
#pragma mark Helper methods
- (id)getNewRecorder
{
return [[[OCMockRecorder alloc] initWithSignatureResolver:self] autorelease];
}
- (NSString *)_recorderDescriptions:(BOOL)onlyExpectations
{
NSMutableString *outputString = [NSMutableString string];
OCMockRecorder *currentObject;
NSEnumerator *recorderEnumerator = [recorders objectEnumerator];
while((currentObject = [recorderEnumerator nextObject]) != nil)
{
NSString *prefix;
if(onlyExpectations)
{
if(![expectations containsObject:currentObject])
continue;
prefix = @" ";
}
else
{
if ([expectations containsObject:currentObject])
prefix = @"expected: ";
else
prefix = @"stubbed: ";
}
[outputString appendFormat:@"\n\t%@\t%@", prefix, [currentObject description]];
}
return outputString;
}
@end
|