main
1//
2// Licensed under the terms in License.txt
3//
4// Copyright 2010 Allen Ding. All rights reserved.
5//
6
7#import "NSObject+KiwiStubAdditions.h"
8#import "KWIntercept.h"
9#import "KWInvocationCapturer.h"
10#import "KWMessagePattern.h"
11#import "KWObjCUtilities.h"
12#import "KWStringUtilities.h"
13#import "KWStub.h"
14
15static NSString * const StubValueKey = @"StubValueKey";
16static NSString * const StubSecondValueKey = @"StubSecondValueKey";
17static NSString * const ChangeStubValueAfterTimesKey = @"ChangeStubValueAfterTimesKey";
18
19@implementation NSObject(KiwiStubAdditions)
20
21#pragma mark -
22#pragma mark Capturing Invocations
23
24- (NSMethodSignature *)invocationCapturer:(KWInvocationCapturer *)anInvocationCapturer methodSignatureForSelector:(SEL)aSelector {
25 NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
26
27 if (signature != nil)
28 return signature;
29
30 NSString *encoding = KWEncodingForVoidMethod();
31 return [NSMethodSignature signatureWithObjCTypes:[encoding UTF8String]];
32}
33
34- (void)invocationCapturer:(KWInvocationCapturer *)anInvocationCapturer didCaptureInvocation:(NSInvocation *)anInvocation {
35 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternFromInvocation:anInvocation];
36 id value = (anInvocationCapturer.userInfo)[StubValueKey];
37 if (!(anInvocationCapturer.userInfo)[StubSecondValueKey]) {
38 [self stubMessagePattern:messagePattern andReturn:value];
39 } else {
40 id times = (anInvocationCapturer.userInfo)[ChangeStubValueAfterTimesKey];
41 id secondValue = (anInvocationCapturer.userInfo)[StubSecondValueKey];
42 [self stubMessagePattern:messagePattern andReturn:value times:times afterThatReturn:secondValue];
43 }
44}
45
46#pragma mark -
47#pragma mark Stubbing Methods
48
49- (void)stub:(SEL)aSelector {
50 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
51 [self stubMessagePattern:messagePattern andReturn:nil];
52}
53
54- (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *))block {
55 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
56 [self stubMessagePattern:messagePattern withBlock:block];
57}
58
59- (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ... {
60 va_list argumentList;
61 va_start(argumentList, firstArgument);
62 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
63 [self stubMessagePattern:messagePattern andReturn:nil];
64}
65
66- (void)stub:(SEL)aSelector andReturn:(id)aValue {
67 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
68 [self stubMessagePattern:messagePattern andReturn:aValue];
69}
70
71- (void)stub:(SEL)aSelector andReturn:(id)aValue withArguments:(id)firstArgument, ... {
72 va_list argumentList;
73 va_start(argumentList, firstArgument);
74 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
75 [self stubMessagePattern:messagePattern andReturn:aValue];
76}
77
78+ (void)stub:(SEL)aSelector {
79 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
80 [self stubMessagePattern:messagePattern andReturn:nil];
81}
82
83+ (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *))block {
84 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
85 [self stubMessagePattern:messagePattern withBlock:block];
86}
87
88+ (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ... {
89 va_list argumentList;
90 va_start(argumentList, firstArgument);
91 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
92 [self stubMessagePattern:messagePattern andReturn:nil];
93}
94
95+ (void)stub:(SEL)aSelector andReturn:(id)aValue {
96 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector];
97 [self stubMessagePattern:messagePattern andReturn:aValue];
98}
99
100+ (void)stub:(SEL)aSelector andReturn:(id)aValue withArguments:(id)firstArgument, ... {
101 va_list argumentList;
102 va_start(argumentList, firstArgument);
103 KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList];
104 [self stubMessagePattern:messagePattern andReturn:aValue];
105}
106
107- (id)stub {
108 return [KWInvocationCapturer invocationCapturerWithDelegate:self];
109}
110
111- (id)stubAndReturn:(id)aValue {
112 NSDictionary *userInfo = @{StubValueKey: aValue};
113 return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo];
114}
115
116- (id)stubAndReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue {
117 NSDictionary *userInfo = @{StubValueKey: aValue, ChangeStubValueAfterTimesKey: times, StubSecondValueKey: aSecondValue};
118 return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo];
119}
120
121- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue {
122 [self stubMessagePattern:aMessagePattern andReturn:aValue overrideExisting:YES];
123}
124
125- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue overrideExisting:(BOOL)overrideExisting {
126 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
127 [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists",
128 NSStringFromSelector(aMessagePattern.selector)];
129 }
130
131 Class interceptClass = KWSetupObjectInterceptSupport(self);
132 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
133 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern value:aValue];
134 KWAssociateObjectStub(self, stub, overrideExisting);
135}
136
137- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue {
138 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
139 [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists",
140 NSStringFromSelector(aMessagePattern.selector)];
141 }
142
143 Class interceptClass = KWSetupObjectInterceptSupport(self);
144 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
145 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern value:aValue times:times afterThatReturn:aSecondValue];
146 KWAssociateObjectStub(self, stub, YES);
147}
148
149- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block {
150 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
151 [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists",
152 NSStringFromSelector(aMessagePattern.selector)];
153 }
154
155 Class interceptClass = KWSetupObjectInterceptSupport(self);
156 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
157 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern block:block];
158 KWAssociateObjectStub(self, stub, YES);
159}
160
161+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue
162{
163 [self stubMessagePattern:aMessagePattern andReturn:aValue overrideExisting:YES];
164}
165
166+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue overrideExisting:(BOOL)override
167{
168 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
169 [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists",
170 NSStringFromSelector(aMessagePattern.selector)];
171 }
172
173 Class interceptClass = KWSetupObjectInterceptSupport(self);
174 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
175 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern value:aValue];
176 KWAssociateObjectStub(self, stub, override);
177}
178
179+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue {
180 [self stubMessagePattern:aMessagePattern andReturn:aValue times:times afterThatReturn:aSecondValue overrideExisting:YES];
181}
182
183+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue overrideExisting:(BOOL)override {
184 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
185 [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists",
186 NSStringFromSelector(aMessagePattern.selector)];
187 }
188
189 Class interceptClass = KWSetupObjectInterceptSupport(self);
190 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
191 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern value:aValue times:times afterThatReturn:aSecondValue];
192 KWAssociateObjectStub(self, stub, override);
193}
194
195+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block {
196 [self stubMessagePattern:aMessagePattern withBlock:block overrideExisting:YES];
197}
198
199+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block overrideExisting:(BOOL)override {
200 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
201 [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists",
202 NSStringFromSelector(aMessagePattern.selector)];
203 }
204
205 Class interceptClass = KWSetupObjectInterceptSupport(self);
206 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
207 KWStub *stub = [KWStub stubWithMessagePattern:aMessagePattern block:block];
208 KWAssociateObjectStub(self, stub, override);
209}
210
211- (void)clearStubs {
212 KWClearObjectStubs(self);
213}
214
215#pragma mark -
216#pragma mark Spying on Messages
217
218- (void)addMessageSpy:(id<KWMessageSpying>)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern {
219 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
220 [NSException raise:@"KWSpyException" format:@"cannot add spy for -%@ because no such method exists",
221 NSStringFromSelector(aMessagePattern.selector)];
222 }
223
224 Class interceptClass = KWSetupObjectInterceptSupport(self);
225 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
226 KWAssociateMessageSpy(self, aSpy, aMessagePattern);
227}
228
229- (void)removeMessageSpy:(id<KWMessageSpying>)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern {
230 KWClearObjectSpy(self, aSpy, aMessagePattern);
231}
232
233+ (void)addMessageSpy:(id<KWMessageSpying>)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern {
234 if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) {
235 [NSException raise:@"KWSpyException" format:@"cannot add spy for -%@ because no such method exists",
236 NSStringFromSelector(aMessagePattern.selector)];
237 }
238
239 Class interceptClass = KWSetupObjectInterceptSupport(self);
240 KWSetupMethodInterceptSupport(interceptClass, aMessagePattern.selector);
241 KWAssociateMessageSpy(self, aSpy, aMessagePattern);
242}
243
244+ (void)removeMessageSpy:(id<KWMessageSpying>)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern {
245 KWClearObjectSpy(self, aSpy, aMessagePattern);
246}
247
248@end