Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 594 lines (465 sloc) 20.601 kb
4f0c627 @allending First release.
authored
1 //
2 // Licensed under the terms in License.txt
3 //
4 // Copyright 2010 Allen Ding. All rights reserved.
5 //
6
7 #import "KWMock.h"
419fea1 @lukeredpath Don't load the runtime from absolute path; this will break on Lion in
lukeredpath authored
8 #import <objc/runtime.h>
4f0c627 @allending First release.
authored
9 #import "KWFormatter.h"
10 #import "KWMessagePattern.h"
11 #import "KWMessageSpying.h"
12 #import "KWStringUtilities.h"
13 #import "KWStub.h"
14 #import "KWWorkarounds.h"
15 #import "NSInvocation+KiwiAdditions.h"
d322d9c @dewind Integrating capture additions to Kiwi
dewind authored
16 #import "KWCaptureSpy.h"
4f0c627 @allending First release.
authored
17
18 static NSString * const ExpectOrStubTagKey = @"ExpectOrStubTagKey";
19 static NSString * const StubTag = @"StubTag";
20 static NSString * const ExpectTag = @"ExpectTag";
21 static NSString * const StubValueKey = @"StubValueKey";
eff7f47 @Bensk1 Implement stubAndReturn with different return values.
Bensk1 authored
22 static NSString * const StubSecondValueKey = @"StubSecondValueKey";
23 static NSString * const ChangeStubValueAfterTimesKey = @"ChangeStubValueAfterTimesKey";
4f0c627 @allending First release.
authored
24
25 @interface KWMock()
26
27 #pragma mark -
28 #pragma mark Initializing
29
30 - (id)initAsNullMock:(BOOL)nullMockFlag withName:(NSString *)aName forClass:(Class)aClass protocol:(Protocol *)aProtocol;
31
32 #pragma mark -
33 #pragma mark Properties
34
35 @property (nonatomic, readonly) NSMutableArray *stubs;
36 @property (nonatomic, readonly) NSMutableArray *expectedMessagePatterns;
37 @property (nonatomic, readonly) NSMutableDictionary *messageSpies;
38
39
40 #pragma mark -
41 #pragma mark Handling Invocations
42
43 - (BOOL)processReceivedInvocation:(NSInvocation *)invocation;
44
45 @end
46
47 @implementation KWMock
48
49 #pragma mark -
50 #pragma mark Initializing
51
52 - (id)init {
53 // May already have been initialized since stubbing -init is allowed!
54 if (self.stubs != nil) {
55 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:_cmd];
56 [self expectMessagePattern:messagePattern];
57 NSInvocation *invocation = [NSInvocation invocationWithTarget:self selector:_cmd];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
58
4f0c627 @allending First release.
authored
59 if ([self processReceivedInvocation:invocation]) {
60 id result = nil;
61 [invocation getReturnValue:&result];
62 return result;
63 } else {
64 return self;
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
65 }
4f0c627 @allending First release.
authored
66 }
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
67
4f0c627 @allending First release.
authored
68 return [self initAsNullMock:NO withName:nil forClass:nil protocol:nil];
69 }
70
71 - (id)initForClass:(Class)aClass {
72 return [self initAsNullMock:NO withName:nil forClass:aClass protocol:nil];
73 }
74
75 - (id)initForProtocol:(Protocol *)aProtocol {
76 return [self initAsNullMock:NO withName:nil forClass:nil protocol:aProtocol];
77 }
78
79 - (id)initWithName:(NSString *)aName forClass:(Class)aClass {
80 return [self initAsNullMock:NO withName:aName forClass:aClass protocol:nil];
81 }
82
83 - (id)initWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol {
84 return [self initAsNullMock:NO withName:aName forClass:nil protocol:aProtocol];
85 }
86
87 - (id)initAsNullMockForClass:(Class)aClass {
88 return [self initAsNullMock:YES withName:nil forClass:aClass protocol:nil];
89 }
90
91 - (id)initAsNullMockForProtocol:(Protocol *)aProtocol {
92 return [self initAsNullMock:YES withName:nil forClass:nil protocol:aProtocol];
93 }
94
95 - (id)initAsNullMockWithName:(NSString *)aName forClass:(Class)aClass {
96 return [self initAsNullMock:YES withName:aName forClass:aClass protocol:nil];
97 }
98
99 - (id)initAsNullMockWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol {
100 return [self initAsNullMock:YES withName:aName forClass:nil protocol:aProtocol];
101 }
102
103 - (id)initAsNullMock:(BOOL)nullMockFlag withName:(NSString *)aName forClass:(Class)aClass protocol:(Protocol *)aProtocol {
104 if ((self = [super init])) {
105 isNullMock = nullMockFlag;
106 name = [aName copy];
107 mockedClass = aClass;
108 mockedProtocol = aProtocol;
109 stubs = [[NSMutableArray alloc] init];
110 expectedMessagePatterns = [[NSMutableArray alloc] init];
111 messageSpies = [[NSMutableDictionary alloc] init];
112 }
113
114 return self;
115 }
116
117 + (id)mockForClass:(Class)aClass {
118 return [[[self alloc] initForClass:aClass] autorelease];
119 }
120
121 + (id)mockForProtocol:(Protocol *)aProtocol {
122 return [[[self alloc] initForProtocol:aProtocol] autorelease];
123 }
124
125 + (id)mockWithName:(NSString *)aName forClass:(Class)aClass {
126 return [[[self alloc] initWithName:aName forClass:aClass] autorelease];
127 }
128
129 + (id)mockWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol {
130 return [[[self alloc] initWithName:aName forProtocol:aProtocol] autorelease];
131 }
132
133 + (id)nullMockForClass:(Class)aClass {
134 return [[[self alloc] initAsNullMockForClass:aClass] autorelease];
135 }
136
137 + (id)nullMockForProtocol:(Protocol *)aProtocol {
138 return [[[self alloc] initAsNullMockForProtocol:aProtocol] autorelease];
139 }
140
141 + (id)nullMockWithName:(NSString *)aName forClass:(Class)aClass {
142 return [[[self alloc] initAsNullMockWithName:aName forClass:aClass] autorelease];
143 }
144
145 + (id)nullMockWithName:(NSString *)aName forProtocol:(Protocol *)aProtocol {
146 return [[[self alloc] initAsNullMockWithName:aName forProtocol:aProtocol] autorelease];
147 }
148
149 - (void)dealloc {
150 [name release];
151 [stubs release];
152 [expectedMessagePatterns release];
153 [messageSpies release];
154 [super dealloc];
155 }
156
157 #pragma mark -
158 #pragma mark Properties
159
160 @synthesize isNullMock;
161 @synthesize name;
162 @synthesize mockedClass;
163 @synthesize mockedProtocol;
164 @synthesize stubs;
165 @synthesize expectedMessagePatterns;
166 @synthesize messageSpies;
167
168 #pragma mark -
169 #pragma mark Getting Transitive Closure For Mocked Protocols
170
171 - (NSSet *)mockedProtocolTransitiveClosureSet {
172 if (self.mockedProtocol == nil)
173 return nil;
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
174
4f0c627 @allending First release.
authored
175 NSMutableSet *protocolSet = [NSMutableSet set];
176 NSMutableArray *protocolQueue = [NSMutableArray array];
177 [protocolQueue addObject:self.mockedProtocol];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
178
4f0c627 @allending First release.
authored
179 do {
180 Protocol *protocol = [protocolQueue lastObject];
181 [protocolSet addObject:protocol];
182 [protocolQueue removeLastObject];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
183
4f0c627 @allending First release.
authored
184 unsigned int count = 0;
1b476ac @blakewatters Fixed a couple of warnings present in Xcode 4.2
blakewatters authored
185 Protocol **protocols = (Protocol **)protocol_copyProtocolList(protocol, &count);
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
186
4f0c627 @allending First release.
authored
187 if (count == 0)
188 continue;
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
189
4f0c627 @allending First release.
authored
190 for (unsigned int i = 0; i < count; ++i)
191 [protocolQueue addObject:protocols[i]];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
192
4f0c627 @allending First release.
authored
193 free(protocols);
194 } while ([protocolQueue count] != 0);
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
195
4f0c627 @allending First release.
authored
196 return protocolSet;
197 }
198
199 #pragma mark -
200 #pragma mark Stubbing Methods
201
202 - (void)removeStubWithMessagePattern:(KWMessagePattern *)messagePattern {
203 NSUInteger stubCount = [self.stubs count];
204
60cf949 @tonyarnold Fix a couple of comparison warnings
tonyarnold authored
205 for (NSUInteger i = 0; i < stubCount; ++i) {
4f0c627 @allending First release.
authored
206 KWStub *stub = [self.stubs objectAtIndex:i];
207
208 if ([stub.messagePattern isEqualToMessagePattern:messagePattern]) {
209 [self.stubs removeObjectAtIndex:i];
210 return;
211 }
212 }
213 }
214
215 - (void)stub:(SEL)aSelector {
216 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
217 [self stubMessagePattern:messagePattern andReturn:nil];
218 }
219
a39aea7 @roustem Adding stub:withBlock: method to Mock objects. It let's you implement an...
roustem authored
220 - (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *params))block {
221 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
222 [self stubMessagePattern:messagePattern withBlock:block];
223 }
224
4f0c627 @allending First release.
authored
225 - (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ... {
226 va_list argumentList;
227 va_start(argumentList, firstArgument);
228 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
229 [self stubMessagePattern:messagePattern andReturn:nil];
230 }
231
232 - (void)stub:(SEL)aSelector andReturn:(id)aValue {
233 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
234 [self stubMessagePattern:messagePattern andReturn:aValue];
235 }
236
237 - (void)stub:(SEL)aSelector andReturn:(id)aValue withArguments:(id)firstArgument, ... {
238 va_list argumentList;
239 va_start(argumentList, firstArgument);
240 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
241 [self stubMessagePattern:messagePattern andReturn:aValue];
242 }
243
244 - (id)stub {
245 NSDictionary *userInfo = [NSDictionary dictionaryWithObject:StubTag forKey:ExpectOrStubTagKey];
246 return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo];
247 }
248
249 - (id)stubAndReturn:(id)aValue {
250 NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:StubTag, ExpectOrStubTagKey,
251 aValue, StubValueKey, nil];
252 return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo];
253 }
254
eff7f47 @Bensk1 Implement stubAndReturn with different return values.
Bensk1 authored
255 - (id)stubAndReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue {
256 NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:StubTag, ExpectOrStubTagKey, aValue, StubValueKey, times, ChangeStubValueAfterTimesKey, aSecondValue, StubSecondValueKey, nil];
257 return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo];
258 }
259
4f0c627 @allending First release.
authored
260 - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue {
261 [self expectMessagePattern:aMessagePattern];
262 [self removeStubWithMessagePattern:aMessagePattern];
263 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern value:aValue];
264 [self.stubs addObject:stub];
265 }
266
a39aea7 @roustem Adding stub:withBlock: method to Mock objects. It let's you implement an...
roustem authored
267 - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block {
268 [self expectMessagePattern:aMessagePattern];
269 [self removeStubWithMessagePattern:aMessagePattern];
270 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern block:block];
271 [self.stubs addObject:stub];
272 }
273
eff7f47 @Bensk1 Implement stubAndReturn with different return values.
Bensk1 authored
274 - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue {
275 [self expectMessagePattern:aMessagePattern];
276 [self removeStubWithMessagePattern:aMessagePattern];
277 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern value:aValue times:times afterThatReturn:aSecondValue];
278 [self.stubs addObject:stub];
279 }
280
4f0c627 @allending First release.
authored
281 - (void)clearStubs {
282 [self.stubs removeAllObjects];
283 }
284
285 #pragma mark -
286 #pragma mark Spying on Messages
287
d322d9c @dewind Integrating capture additions to Kiwi
dewind authored
288 - (KWCaptureSpy *)captureArgument:(SEL)selector atIndex:(NSUInteger)index {
289 KWCaptureSpy *spy = [[[KWCaptureSpy alloc] initWithArgumentIndex:index] autorelease];
290 [self addMessageSpy:spy forMessagePattern:[KWMessagePattern messagePatternWithSelector:selector]];
291 return spy;
292 }
293
4f0c627 @allending First release.
authored
294 - (void)addMessageSpy:(id<KWMessageSpying>)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern {
295 [self expectMessagePattern:aMessagePattern];
296 NSMutableArray *messagePatternSpies = [self.messageSpies objectForKey:aMessagePattern];
297
298 if (messagePatternSpies == nil) {
299 messagePatternSpies = [[NSMutableArray alloc] init];
300 [self.messageSpies setObject:messagePatternSpies forKey:aMessagePattern];
301 [messagePatternSpies release];
302 }
303 NSValue *spyWrapper = [NSValue valueWithNonretainedObject:aSpy];
304
305 if (![messagePatternSpies containsObject:spyWrapper])
306 [messagePatternSpies addObject:spyWrapper];
307 }
308
309 - (void)removeMessageSpy:(id<KWMessageSpying>)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern {
310 NSValue *spyWrapper = [NSValue valueWithNonretainedObject:aSpy];
311 NSMutableArray *messagePatternSpies = [self.messageSpies objectForKey:aMessagePattern];
312 [messagePatternSpies removeObject:spyWrapper];
313 }
314
315 #pragma mark -
316 #pragma mark Expecting Message Patterns
317
318 - (void)expect:(SEL)aSelector {
319 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
320 [self expectMessagePattern:messagePattern];
321 }
322
323 - (void)expect:(SEL)aSelector withArguments:(id)firstArgument, ... {
324 va_list argumentList;
325 va_start(argumentList, firstArgument);
326 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
327 [self expectMessagePattern:messagePattern];
328 }
329
330 - (id)expect {
331 NSDictionary *userInfo = [NSDictionary dictionaryWithObject:ExpectTag forKey:ExpectOrStubTagKey];
332 return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo];
333 }
334
335 - (void)expectMessagePattern:(KWMessagePattern *)aMessagePattern {
336 if (![self.expectedMessagePatterns containsObject:aMessagePattern])
337 [self.expectedMessagePatterns addObject:aMessagePattern];
338 }
339
340 #pragma mark -
341 #pragma mark Capturing Invocations
342
343 - (NSMethodSignature *)invocationCapturer:(KWInvocationCapturer *)anInvocationCapturer methodSignatureForSelector:(SEL)aSelector {
344 return [self methodSignatureForSelector:aSelector];
345 }
346
347 - (void)invocationCapturer:(KWInvocationCapturer *)anInvocationCapturer didCaptureInvocation:(NSInvocation *)anInvocation {
348 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternFromInvocation:anInvocation];
349 NSString *tag = [anInvocationCapturer.userInfo objectForKey:ExpectOrStubTagKey];
350 if ([tag isEqualToString:StubTag]) {
351 id value = [anInvocationCapturer.userInfo objectForKey:StubValueKey];
eff7f47 @Bensk1 Implement stubAndReturn with different return values.
Bensk1 authored
352 if (![anInvocationCapturer.userInfo objectForKey:StubSecondValueKey]) {
353 [self stubMessagePattern:messagePattern andReturn:value];
354 } else {
355 id times = [anInvocationCapturer.userInfo objectForKey:ChangeStubValueAfterTimesKey];
356 id secondValue = [anInvocationCapturer.userInfo objectForKey:StubSecondValueKey];
357 [self stubMessagePattern:messagePattern andReturn:value times:times afterThatReturn:secondValue];
358 }
4f0c627 @allending First release.
authored
359 } else {
360 [self expectMessagePattern:messagePattern];
361 }
362 }
363
364 #pragma mark -
365 #pragma mark Handling Invocations
366
367 - (NSString *)namePhrase {
368 if (self.name == nil)
369 return @"mock";
370 else
371 return [NSString stringWithFormat:@"mock \"%@\"", self.name];
372 }
373
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
374 - (BOOL)processReceivedInvocation:(NSInvocation *)invocation {
4f0c627 @allending First release.
authored
375 for (KWMessagePattern *messagePattern in self.messageSpies) {
376 if ([messagePattern matchesInvocation:invocation]) {
377 NSArray *spies = [self.messageSpies objectForKey:messagePattern];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
378
4f0c627 @allending First release.
authored
379 for (NSValue *spyWrapper in spies) {
380 id spy = [spyWrapper nonretainedObjectValue];
381 [spy object:self didReceiveInvocation:invocation];
382 }
383 }
384 }
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
385
4f0c627 @allending First release.
authored
386 for (KWStub *stub in self.stubs) {
387 if ([stub processInvocation:invocation])
388 return YES;
389 }
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
390
4f0c627 @allending First release.
authored
391 return NO;
392 }
393
394 - (NSMethodSignature *)mockedProtocolMethodSignatureForSelector:(SEL)aSelector {
395 NSSet *protocols = [self mockedProtocolTransitiveClosureSet];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
396
4f0c627 @allending First release.
authored
397 for (Protocol *protocol in protocols) {
398 struct objc_method_description description = protocol_getMethodDescription(protocol, aSelector, NO, YES);
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
399
4f0c627 @allending First release.
authored
400 if (description.types == nil)
401 description = protocol_getMethodDescription(protocol, aSelector, YES, YES);
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
402
4f0c627 @allending First release.
authored
403 if (description.types != nil)
404 return [NSMethodSignature signatureWithObjCTypes:description.types];
405 }
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
406
4f0c627 @allending First release.
authored
407 return nil;
408 }
409
410 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
411 NSMethodSignature *methodSignature = [self.mockedClass instanceMethodSignatureForSelector:aSelector];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
412
4f0c627 @allending First release.
authored
413 if (methodSignature != nil)
414 return methodSignature;
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
415
4f0c627 @allending First release.
authored
416 methodSignature = [self mockedProtocolMethodSignatureForSelector:aSelector];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
417
4f0c627 @allending First release.
authored
418 if (methodSignature != nil)
419 return methodSignature;
420
421 NSString *encoding = KWEncodingForVoidMethod();
422 return [NSMethodSignature signatureWithObjCTypes:[encoding UTF8String]];
423 }
424
425 - (void)forwardInvocation:(NSInvocation *)anInvocation {
426 #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG
427 @try {
428 #endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG
429
430 if ([self processReceivedInvocation:anInvocation])
431 return;
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
432
4f0c627 @allending First release.
authored
433 if (self.isNullMock)
434 return;
435
436 for (KWMessagePattern *expectedMessagePattern in self.expectedMessagePatterns) {
437 if ([expectedMessagePattern matchesInvocation:anInvocation])
438 return;
439 }
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
440
4f0c627 @allending First release.
authored
441 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternFromInvocation:anInvocation];
442 [NSException raise:@"KWMockException" format:@"%@ received unexpected message -%@",
443 [self namePhrase],
444 [messagePattern stringValue]];
445
446 #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG
447 } @catch (NSException *exception) {
448 KWSetExceptionFromAcrossInvocationBoundary(exception);
449 }
450 #endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG
451 }
452
453 #pragma mark -
454 #pragma mark Testing Objects
455
456 - (BOOL)mockedClassHasAncestorClass:(Class)aClass {
457 Class currentClass = self.mockedClass;
458
459 while (currentClass != nil) {
460 if (currentClass == aClass)
461 return YES;
462
463 currentClass = [currentClass superclass];
464 }
465
466 return NO;
467 }
468
469 - (BOOL)mockedClassRespondsToSelector:(SEL)aSelector {
470 return [self.mockedClass instancesRespondToSelector:aSelector];
471 }
472
473 - (BOOL)mockedClassConformsToProtocol:(Protocol *)aProtocol {
474 return [self.mockedClass conformsToProtocol:aProtocol];
475 }
476
477 - (BOOL)mockedProtocolRespondsToSelector:(SEL)aSelector {
478 NSSet *protocols = [self mockedProtocolTransitiveClosureSet];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
479
4f0c627 @allending First release.
authored
480 for (Protocol *protocol in protocols) {
481 struct objc_method_description description = protocol_getMethodDescription(protocol, aSelector, NO, YES);
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
482
4f0c627 @allending First release.
authored
483 if (description.types == nil)
484 description = protocol_getMethodDescription(protocol, aSelector, YES, YES);
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
485
4f0c627 @allending First release.
authored
486 if (description.types != nil)
487 return YES;
488 }
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
489
490 return NO;
4f0c627 @allending First release.
authored
491 }
492
493 - (BOOL)mockedProtocolConformsToProtocol:(Protocol *)aProtocol {
494 if (self.mockedProtocol == nil)
495 return NO;
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
496
4f0c627 @allending First release.
authored
497 return protocol_isEqual(self.mockedProtocol, aProtocol) || protocol_conformsToProtocol(self.mockedProtocol, aProtocol);
498 }
499
500 - (BOOL)isKindOfClass:(Class)aClass {
501 return [self mockedClassHasAncestorClass:aClass] || [super isKindOfClass:aClass];
502 }
503
504 - (BOOL)isMemberOfClass:(Class)aClass {
505 return self.mockedClass == aClass || [super isMemberOfClass:aClass];
506 }
507
508 - (BOOL)respondsToSelector:(SEL)aSelector {
509 return [self mockedClassRespondsToSelector:aSelector] ||
510 [self mockedProtocolRespondsToSelector:aSelector] ||
511 [super respondsToSelector:aSelector];
512 }
513
514 - (BOOL)conformsToProtocol:(Protocol *)aProtocol {
515 return [self mockedClassConformsToProtocol:aProtocol] ||
516 [self mockedProtocolConformsToProtocol:aProtocol] ||
517 [super conformsToProtocol:aProtocol];
518 }
519
520 #pragma mark -
521 #pragma mark Whitelisted NSObject Methods
522
523 - (BOOL)isEqual:(id)anObject {
524 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:_cmd];
525 [self expectMessagePattern:messagePattern];
526 NSInvocation *invocation = [NSInvocation invocationWithTarget:self selector:_cmd messageArguments:&anObject];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
527
4f0c627 @allending First release.
authored
528 if ([self processReceivedInvocation:invocation]) {
529 BOOL result = NO;
530 [invocation getReturnValue:&result];
531 return result;
532 } else {
533 return [super isEqual:anObject];
534 }
535 }
536
537 - (NSUInteger)hash {
538 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:_cmd];
539 [self expectMessagePattern:messagePattern];
540 NSInvocation *invocation = [NSInvocation invocationWithTarget:self selector:_cmd];
541
542 if ([self processReceivedInvocation:invocation]) {
543 NSUInteger result = 0;
544 [invocation getReturnValue:&result];
545 return result;
546 } else {
547 return [super hash];
548 }
549 }
550
551 - (NSString *)description {
552 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:_cmd];
553 [self expectMessagePattern:messagePattern];
554 NSInvocation *invocation = [NSInvocation invocationWithTarget:self selector:_cmd];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
555
4f0c627 @allending First release.
authored
556 if ([self processReceivedInvocation:invocation]) {
557 NSString *result = nil;
558 [invocation getReturnValue:&result];
559 return result;
560 } else {
561 return [super description];
562 }
563 }
564
565 - (id)copy {
566 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:_cmd];
567 [self expectMessagePattern:messagePattern];
568 NSInvocation *invocation = [NSInvocation invocationWithTarget:self selector:_cmd];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
569
4f0c627 @allending First release.
authored
570 if ([self processReceivedInvocation:invocation]) {
571 id result = nil;
572 [invocation getReturnValue:&result];
573 return result;
574 } else {
575 return [super copy];
576 }
577 }
578
579 - (id)mutableCopy {
580 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:_cmd];
581 [self expectMessagePattern:messagePattern];
582 NSInvocation *invocation = [NSInvocation invocationWithTarget:self selector:_cmd];
b940a6e @mattdipasquale Convert \t to 4 spaces. Rm trailing whitespace.
mattdipasquale authored
583
4f0c627 @allending First release.
authored
584 if ([self processReceivedInvocation:invocation]) {
585 id result = nil;
586 [invocation getReturnValue:&result];
587 return result;
588 } else {
589 return [super mutableCopy];
590 }
591 }
592
593 @end
Something went wrong with that request. Please try again.