Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / ocmock / OCMock / OCMockRecorder.m
blob5cd63d2b4c84ae3cf84f4cc81f9687a2b680e533
1 //---------------------------------------------------------------------------------------
2 //  $Id$
3 //  Copyright (c) 2004-2011 by Mulle Kybernetik. See License file for details.
4 //---------------------------------------------------------------------------------------
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"
19 @interface NSObject(HCMatcherDummy)
20 - (BOOL)matches:(id)item;
21 @end
23 #pragma mark  -
26 @implementation OCMockRecorder
28 #pragma mark  Initialisers, description, accessors, etc.
30 - (id)initWithSignatureResolver:(id)anObject
32         signatureResolver = anObject;
33         invocationHandlers = [[NSMutableArray alloc] init];
34         return self;
37 - (void)dealloc
39         [recordedInvocation release];
40         [invocationHandlers release];
41         [super dealloc];
44 - (NSString *)description
46         return [recordedInvocation invocationDescription];
49 - (void)releaseInvocation
51         [recordedInvocation release];
52         recordedInvocation = nil;
56 #pragma mark  Recording invocation handlers
58 - (id)andReturn:(id)anObject
60         [invocationHandlers addObject:[[[OCMReturnValueProvider alloc] initWithValue:anObject] autorelease]];
61         return self;
64 - (id)andReturnValue:(NSValue *)aValue
66         [invocationHandlers addObject:[[[OCMBoxedReturnValueProvider alloc] initWithValue:aValue] autorelease]];
67         return self;
70 - (id)andThrow:(NSException *)anException
72         [invocationHandlers addObject:[[[OCMExceptionReturnValueProvider alloc] initWithValue:anException] autorelease]];
73         return self;
76 - (id)andPost:(NSNotification *)aNotification
78         [invocationHandlers addObject:[[[OCMNotificationPoster alloc] initWithNotification:aNotification] autorelease]];
79         return self;
82 - (id)andCall:(SEL)selector onObject:(id)anObject
84         [invocationHandlers addObject:[[[OCMIndirectReturnValueProvider alloc] initWithProvider:anObject andSelector:selector] autorelease]];
85         return self;
88 #if NS_BLOCKS_AVAILABLE
90 - (id)andDo:(void (^)(NSInvocation *))aBlock 
92         [invocationHandlers addObject:[[[OCMBlockCaller alloc] initWithCallBlock:aBlock] autorelease]];
93         return self;
96 #endif
98 - (id)andForwardToRealObject
100         [NSException raise:NSInternalInconsistencyException format:@"Method %@ can only be used with partial mocks.",
101          NSStringFromSelector(_cmd)];
102         return self; // keep compiler happy
106 - (NSArray *)invocationHandlers
108         return invocationHandlers;
112 #pragma mark  Recording the actual invocation
114 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
116         return [signatureResolver methodSignatureForSelector:aSelector];
119 - (void)forwardInvocation:(NSInvocation *)anInvocation
121         if(recordedInvocation != nil)
122                 [NSException raise:NSInternalInconsistencyException format:@"Recorder received two methods to record."];
123         [anInvocation setTarget:nil];
124         [anInvocation retainArguments];
125         recordedInvocation = [anInvocation retain];
130 #pragma mark  Checking the invocation
132 - (BOOL)matchesInvocation:(NSInvocation *)anInvocation
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];
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 handleInvocation
164                         *(id *)[passedArg pointerValue] = [(OCMPassByRefSetter *)recordedArg value];
165                 }
166                 else if([recordedArg conformsToProtocol:objc_getProtocol("HCMatcher")])
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*)passedArg] != NSOrderedSame))
175                                 return NO;
176                         if(([recordedArg isEqual:passedArg] == NO) &&
177                                 !((recordedArg == nil) && (passedArg == nil)))
178                                 return NO;
179                 }
180         }
181         return YES;
187 @end