OLD | NEW |
| (Empty) |
1 //------------------------------------------------------------------------------
--------- | |
2 // $Id$ | |
3 // Copyright (c) 2004-2011 by Mulle Kybernetik. See License file for details. | |
4 //------------------------------------------------------------------------------
--------- | |
5 | |
6 #import <objc/runtime.h> | |
7 #import <OCMock/OCMockRecorder.h> | |
8 #import <OCMock/OCMArg.h> | |
9 #import <OCMock/OCMConstraint.h> | |
10 #import "OCMPassByRefSetter.h" | |
11 #import "OCMReturnValueProvider.h" | |
12 #import "OCMBoxedReturnValueProvider.h" | |
13 #import "OCMExceptionReturnValueProvider.h" | |
14 #import "OCMIndirectReturnValueProvider.h" | |
15 #import "OCMNotificationPoster.h" | |
16 #import "OCMBlockCaller.h" | |
17 #import "NSInvocation+OCMAdditions.h" | |
18 | |
19 @interface NSObject(HCMatcherDummy) | |
20 - (BOOL)matches:(id)item; | |
21 @end | |
22 | |
23 #pragma mark - | |
24 | |
25 | |
26 @implementation OCMockRecorder | |
27 | |
28 #pragma mark Initialisers, description, accessors, etc. | |
29 | |
30 - (id)initWithSignatureResolver:(id)anObject | |
31 { | |
32 signatureResolver = anObject; | |
33 invocationHandlers = [[NSMutableArray alloc] init]; | |
34 return self; | |
35 } | |
36 | |
37 - (void)dealloc | |
38 { | |
39 [recordedInvocation release]; | |
40 [invocationHandlers release]; | |
41 [super dealloc]; | |
42 } | |
43 | |
44 - (NSString *)description | |
45 { | |
46 return [recordedInvocation invocationDescription]; | |
47 } | |
48 | |
49 - (void)releaseInvocation | |
50 { | |
51 [recordedInvocation release]; | |
52 recordedInvocation = nil; | |
53 } | |
54 | |
55 | |
56 #pragma mark Recording invocation handlers | |
57 | |
58 - (id)andReturn:(id)anObject | |
59 { | |
60 [invocationHandlers addObject:[[[OCMReturnValueProvider alloc] initWithV
alue:anObject] autorelease]]; | |
61 return self; | |
62 } | |
63 | |
64 - (id)andReturnValue:(NSValue *)aValue | |
65 { | |
66 [invocationHandlers addObject:[[[OCMBoxedReturnValueProvider alloc] init
WithValue:aValue] autorelease]]; | |
67 return self; | |
68 } | |
69 | |
70 - (id)andThrow:(NSException *)anException | |
71 { | |
72 [invocationHandlers addObject:[[[OCMExceptionReturnValueProvider alloc]
initWithValue:anException] autorelease]]; | |
73 return self; | |
74 } | |
75 | |
76 - (id)andPost:(NSNotification *)aNotification | |
77 { | |
78 [invocationHandlers addObject:[[[OCMNotificationPoster alloc] initWithNo
tification:aNotification] autorelease]]; | |
79 return self; | |
80 } | |
81 | |
82 - (id)andCall:(SEL)selector onObject:(id)anObject | |
83 { | |
84 [invocationHandlers addObject:[[[OCMIndirectReturnValueProvider alloc] i
nitWithProvider:anObject andSelector:selector] autorelease]]; | |
85 return self; | |
86 } | |
87 | |
88 #if NS_BLOCKS_AVAILABLE | |
89 | |
90 - (id)andDo:(void (^)(NSInvocation *))aBlock | |
91 { | |
92 [invocationHandlers addObject:[[[OCMBlockCaller alloc] initWithCallBlock
:aBlock] autorelease]]; | |
93 return self; | |
94 } | |
95 | |
96 #endif | |
97 | |
98 - (id)andForwardToRealObject | |
99 { | |
100 [NSException raise:NSInternalInconsistencyException format:@"Method %@ c
an only be used with partial mocks.", | |
101 NSStringFromSelector(_cmd)]; | |
102 return self; // keep compiler happy | |
103 } | |
104 | |
105 | |
106 - (NSArray *)invocationHandlers | |
107 { | |
108 return invocationHandlers; | |
109 } | |
110 | |
111 | |
112 #pragma mark Recording the actual invocation | |
113 | |
114 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector | |
115 { | |
116 return [signatureResolver methodSignatureForSelector:aSelector]; | |
117 } | |
118 | |
119 - (void)forwardInvocation:(NSInvocation *)anInvocation | |
120 { | |
121 if(recordedInvocation != nil) | |
122 [NSException raise:NSInternalInconsistencyException format:@"Rec
order received two methods to record."]; | |
123 [anInvocation setTarget:nil]; | |
124 [anInvocation retainArguments]; | |
125 recordedInvocation = [anInvocation retain]; | |
126 } | |
127 | |
128 | |
129 | |
130 #pragma mark Checking the invocation | |
131 | |
132 - (BOOL)matchesInvocation:(NSInvocation *)anInvocation | |
133 { | |
134 id recordedArg, passedArg; | |
135 int i, n; | |
136 | |
137 if([anInvocation selector] != [recordedInvocation selector]) | |
138 return NO; | |
139 | |
140 n = (int)[[recordedInvocation methodSignature] numberOfArguments]; | |
141 for(i = 2; i < n; i++) | |
142 { | |
143 recordedArg = [recordedInvocation getArgumentAtIndexAsObject:i]; | |
144 passedArg = [anInvocation getArgumentAtIndexAsObject:i]; | |
145 | |
146 if([recordedArg isProxy]) | |
147 { | |
148 if(![recordedArg isEqual:passedArg]) | |
149 return NO; | |
150 continue; | |
151 } | |
152 | |
153 if([recordedArg isKindOfClass:[NSValue class]]) | |
154 recordedArg = [OCMArg resolveSpecialValues:recordedArg]; | |
155 | |
156 if([recordedArg isKindOfClass:[OCMConstraint class]]) | |
157 { | |
158 if([recordedArg evaluate:passedArg] == NO) | |
159 return NO; | |
160 } | |
161 else if([recordedArg isKindOfClass:[OCMPassByRefSetter class]]) | |
162 { | |
163 // side effect but easier to do here than in handleInvoc
ation | |
164 *(id *)[passedArg pointerValue] = [(OCMPassByRefSetter *
)recordedArg value]; | |
165 } | |
166 else if([recordedArg conformsToProtocol:objc_getProtocol("HCMatc
her")]) | |
167 { | |
168 if([recordedArg matches:passedArg] == NO) | |
169 return NO; | |
170 } | |
171 else | |
172 { | |
173 if(([recordedArg class] == [NSNumber class]) && | |
174 ([(NSNumber*)recordedArg compare:(NSNumber*)pass
edArg] != NSOrderedSame)) | |
175 return NO; | |
176 if(([recordedArg isEqual:passedArg] == NO) && | |
177 !((recordedArg == nil) && (passedArg == nil))) | |
178 return NO; | |
179 } | |
180 } | |
181 return YES; | |
182 } | |
183 | |
184 | |
185 | |
186 | |
187 @end | |
OLD | NEW |