]> git.wincent.com - WOTest.git/blob - WOProtocolMock.m
Fix object-to-pointer comparisons on Leopard
[WOTest.git] / WOProtocolMock.m
1 //
2 //  WOProtocolMock.m
3 //  WOTest
4 //
5 //  Created by Wincent Colaiuta on 28 January 2007.
6 //
7 //  Copyright 2006-2007 Wincent Colaiuta.
8 //  This program is free software: you can redistribute it and/or modify
9 //  it under the terms of the GNU General Public License as published by
10 //  the Free Software Foundation, either version 3 of the License, or
11 //  (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 //
21
22 #import "WOProtocolMock.h"
23
24 // system headers
25
26 #import <objc/Protocol.h>
27
28 // framework headers
29
30 #import "NSInvocation+WOTest.h"
31 #import "NSMethodSignature+WOTest.h"
32 #import "WOEnumerate.h"
33 #import "WOProtocolStub.h"
34
35 #pragma mark -
36 #pragma mark C function implementations
37
38 NSString *WOStringFromProtocol(Protocol *aProtocol)
39 {
40     if (aProtocol == NULL) return nil;
41         return [NSString stringWithUTF8String:protocol_getName(aProtocol)];
42 }
43
44 @implementation WOProtocolMock
45
46 #pragma mark -
47 #pragma mark Creation
48
49 + (id)mockForProtocol:(Protocol *)aProtocol
50 {
51     NSParameterAssert(aProtocol != NULL);
52     return [[[self alloc] initWithProtocol:aProtocol] autorelease];
53 }
54
55 - (id)initWithProtocol:(Protocol *)aProtocol
56 {
57     NSParameterAssert(aProtocol != NULL);
58
59     // TODO: test for validity of the Protocol by checking with the runtime
60     
61     if ((self = [super init]))
62         [self setMockedProtocol:aProtocol];
63     return self;
64 }
65
66 #pragma mark -
67 #pragma mark Recording
68
69 - (id)accept
70 {
71     WOProtocolStub *stub = [WOProtocolStub stubForProtocol:[self mockedProtocol] withDelegate:self];
72     [accepted addObject:stub];
73     return stub;
74 }
75
76 - (id)acceptOnce
77 {
78     WOProtocolStub *stub = [WOProtocolStub stubForProtocol:[self mockedProtocol] withDelegate:self];
79     [acceptedOnce addObject:stub];
80     return stub;
81 }
82
83 - (id)reject
84 {
85     WOProtocolStub *stub = [WOProtocolStub stubForProtocol:[self mockedProtocol] withDelegate:self];
86     [rejected addObject:stub];
87     return stub;
88 }
89
90 - (id)expect
91 {
92     WOProtocolStub *stub = [WOProtocolStub stubForProtocol:[self mockedProtocol] withDelegate:self];
93     [expected addObject:stub];
94     return stub;
95 }
96
97 - (id)expectOnce
98 {
99     WOProtocolStub *stub = [WOProtocolStub stubForProtocol:[self mockedProtocol] withDelegate:self];
100     [expectedOnce addObject:stub];
101     return stub;
102 }
103
104 - (id)expectInOrder
105 {
106     WOProtocolStub *stub = [WOProtocolStub stubForProtocol:[self mockedProtocol] withDelegate:self];
107     [expectedInOrder addObject:stub];
108     return stub;
109 }
110
111 #pragma mark -
112 #pragma mark Proxy methods 
113
114 - (void)forwardInvocation:(NSInvocation *)anInvocation
115 {
116     NSParameterAssert(anInvocation != nil);
117     
118     // check if in reject list
119     WO_ENUMERATE(rejected, stub)
120         if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
121         {
122             [NSException raise:NSInternalInconsistencyException format:@"Rejected selector %@ for protocol %@",
123                 NSStringFromSelector([anInvocation selector]), WOStringFromProtocol([self mockedProtocol])];
124             return;
125         }
126     
127     // check if expectedInOrder
128     WO_ENUMERATE(expectedInOrder, stub)
129         if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
130         {
131             NSAssert(([expectedInOrder objectAtIndex:0] != stub), @"invocation received out of order");
132             
133             // if in order, remove from head of list
134             [expectedInOrder removeObjectAtIndex:0];
135             
136             // and move to "accepted"
137             [accepted addObject:stub];
138             [self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
139             if ([stub exception]) @throw [stub exception];
140             return;
141         }
142     
143     // check if expected once
144     WO_ENUMERATE(expectedOnce, stub)
145         if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
146         {
147             // move object from "expectedOnce" to "rejected"
148             [rejected addObject:stub];
149             [expectedOnce removeObject:stub];
150             [self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
151             if ([stub exception]) @throw [stub exception];
152             return;
153         }
154     
155     // check if expected
156     WO_ENUMERATE(expected, stub)
157         if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
158         {
159             // move from "expected" to "accepted"
160             [accepted addObject:stub];
161             [expected removeObject:stub];
162             [self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
163             if ([stub exception]) @throw [stub exception];
164             return;
165         }
166     
167     // check if accepted once
168     WO_ENUMERATE(acceptedOnce, stub)
169         if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
170         {
171             // move from "acceptedOnce" to "rejected"
172             [rejected addObject:stub];
173             [acceptedOnce removeObject:stub];
174             [self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
175             if ([stub exception]) @throw [stub exception];
176             return;
177         }
178     
179     // check if accepted
180     WO_ENUMERATE(accepted, stub)
181         if ([anInvocation WOTest_isEqualToInvocation:[stub recordedInvocation]])
182         {
183             [self storeReturnValue:[stub returnValue] forInvocation:anInvocation];
184             if ([stub exception]) @throw [stub exception];
185             return;
186         }
187     
188     
189     if ([self acceptsByDefault]) return;
190     
191     // no matches! (should never get here)
192     [NSException raise:NSInternalInconsistencyException format:@"No matching invocations found (selector %@, protocol %@)",
193         NSStringFromSelector([anInvocation selector]), WOStringFromProtocol([self mockedProtocol])];
194 }
195
196 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
197 {
198     // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the 
199     // selector for this method itself and by not sending any message that might invoke this method.")
200     if (aSelector == _cmd) return nil;
201     
202         BOOL isRequiredMethod = YES;    // no idea what to pass here
203         struct objc_method_description description = protocol_getMethodDescription([self mockedProtocol], aSelector, isRequiredMethod, YES);
204     return [NSMethodSignature WOTest_signatureBasedOnObjCTypes:description.types];
205 }
206
207 #pragma mark -
208 #pragma mark Accessors
209
210 - (Protocol *)mockedProtocol
211 {
212     return mockedProtocol; 
213 }
214
215 - (void)setMockedProtocol:(Protocol *)aMockedProtocol
216 {
217     mockedProtocol = aMockedProtocol;
218 }
219
220 @end