Skip to content

Commit c834547

Browse files
committed
Make OCMInvocationConstraint retain invocation
1 parent a09c4b9 commit c834547

File tree

3 files changed

+104
-17
lines changed

3 files changed

+104
-17
lines changed

Source/OCMock/OCMConstraint.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@
5353

5454
@interface OCMInvocationConstraint : OCMConstraint
5555
{
56-
@public
57-
NSInvocation *invocation;
56+
NSInvocation *invocation;
5857
}
5958

59+
- (instancetype)initWithInvocation:(NSInvocation *)invocation NS_DESIGNATED_INITIALIZER;
60+
- (instancetype)init NS_UNAVAILABLE;
61+
6062
@end
6163

6264
@interface OCMBlockConstraint : OCMConstraint

Source/OCMock/OCMConstraint.m

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
#import <OCMock/OCMConstraint.h>
18-
18+
#import "OCMFunctions.h"
1919

2020
@implementation OCMConstraint
2121

@@ -34,26 +34,30 @@ - (id)copyWithZone:(struct _NSZone *)zone
3434
return [self retain];
3535
}
3636

37+
+ (NSInvocation *)invocationWithSelector:(SEL)aSelector onObject:(id)anObject
38+
{
39+
NSMethodSignature *signature = [anObject methodSignatureForSelector:aSelector];
40+
if(signature == nil)
41+
[NSException raise:NSInvalidArgumentException format:@"Unknown selector %@ used in constraint.", NSStringFromSelector(aSelector)];
42+
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
43+
[invocation setTarget:anObject];
44+
[invocation setSelector:aSelector];
45+
return invocation;
46+
}
47+
3748
+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject
3849
{
39-
OCMInvocationConstraint *constraint = [OCMInvocationConstraint constraint];
40-
NSMethodSignature *signature = [anObject methodSignatureForSelector:aSelector];
41-
if(signature == nil)
42-
[NSException raise:NSInvalidArgumentException format:@"Unkown selector %@ used in constraint.", NSStringFromSelector(aSelector)];
43-
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
44-
[invocation setTarget:anObject];
45-
[invocation setSelector:aSelector];
46-
constraint->invocation = invocation;
47-
return constraint;
50+
NSInvocation *invocation = [self invocationWithSelector:aSelector onObject:anObject];
51+
return [[[OCMInvocationConstraint alloc] initWithInvocation:invocation] autorelease];
4852
}
4953

5054
+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue
5155
{
52-
OCMInvocationConstraint *constraint = (OCMInvocationConstraint *)[self constraintWithSelector:aSelector onObject:anObject];
53-
if([[constraint->invocation methodSignature] numberOfArguments] < 4)
54-
[NSException raise:NSInvalidArgumentException format:@"Constraint with value requires selector with two arguments."];
55-
[constraint->invocation setArgument:&aValue atIndex:3];
56-
return constraint;
56+
NSInvocation *invocation = [self invocationWithSelector:aSelector onObject:anObject];
57+
if([[invocation methodSignature] numberOfArguments] < 4)
58+
[NSException raise:NSInvalidArgumentException format:@"Constraint with value requires selector with two arguments."];
59+
[invocation setArgument:&aValue atIndex:3];
60+
return [[[OCMInvocationConstraint alloc] initWithInvocation:invocation] autorelease];
5761
}
5862

5963

@@ -125,6 +129,33 @@ - (BOOL)evaluate:(id)value
125129

126130
@implementation OCMInvocationConstraint
127131

132+
- (instancetype)initWithInvocation:(NSInvocation *)anInvocation {
133+
if((self = [super init]))
134+
{
135+
NSMethodSignature *signature = [anInvocation methodSignature];
136+
if([signature numberOfArguments] < 3)
137+
{
138+
[NSException raise:NSInvalidArgumentException format:@"invocation must take at least one argument (other than _cmd and self)"];
139+
}
140+
if(!(OCMIsObjectType([signature getArgumentTypeAtIndex:2])))
141+
{
142+
[NSException raise:NSInvalidArgumentException format:@"invocation's second argument must be an object type"];
143+
}
144+
if(strcmp([signature methodReturnType], @encode(BOOL)))
145+
{
146+
[NSException raise:NSInvalidArgumentException format:@"invocation must return BOOL"];
147+
}
148+
invocation = [anInvocation retain];
149+
}
150+
return self;
151+
}
152+
153+
- (void)dealloc
154+
{
155+
[invocation release];
156+
[super dealloc];
157+
}
158+
128159
- (BOOL)evaluate:(id)value
129160
{
130161
[invocation setArgument:&value atIndex:2]; // should test if constraint takes arg

Source/OCMockTests/OCMConstraintTests.m

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,58 @@ - (void)testEvaluateNilBlockReturnsNo
142142
XCTAssertFalse([constraint evaluate:@"foo"]);
143143
}
144144

145+
- (void)testEvaluateInvocationRetainsInvocation
146+
{
147+
OCMInvocationConstraint *constraint;
148+
@autoreleasepool {
149+
SEL selector = @selector(checkArg:);
150+
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
151+
[anInvocation setTarget:self];
152+
[anInvocation setSelector:selector];
153+
constraint = [[OCMInvocationConstraint alloc] initWithInvocation:anInvocation];
154+
}
155+
XCTAssertTrue([constraint evaluate:@"foo"]);
156+
}
157+
158+
- (BOOL)methodWithNoArgs
159+
{
160+
return YES;
161+
}
162+
163+
- (void)testEvaluateInvocationThrowsForInvocationForMethodWithoutArgument
164+
{
165+
SEL selector = @selector(methodWithNoArgs);
166+
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
167+
[anInvocation setTarget:self];
168+
[anInvocation setSelector:selector];
169+
XCTAssertThrowsSpecificNamed([[OCMInvocationConstraint alloc] initWithInvocation:anInvocation], NSException, NSInvalidArgumentException);
170+
}
171+
172+
- (BOOL)aMethodWithInt:(int)anInt
173+
{
174+
return YES;
175+
}
176+
177+
- (void)testEvaluateInvocationThrowsForInvocationForMethodWithoutObjectArgument
178+
{
179+
SEL selector = @selector(aMethodWithInt:);
180+
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
181+
[anInvocation setTarget:self];
182+
[anInvocation setSelector:selector];
183+
XCTAssertThrowsSpecificNamed([[OCMInvocationConstraint alloc] initWithInvocation:anInvocation], NSException, NSInvalidArgumentException);
184+
}
185+
186+
- (void)aMethodThatDoesNotReturnBool:(id)anArg
187+
{
188+
}
189+
190+
- (void)testEvaluateInvocationThrowsForInvocationThatDoesNotReturnBool
191+
{
192+
SEL selector = @selector(aMethodThatDoesNotReturnBool:);
193+
NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
194+
[anInvocation setTarget:self];
195+
[anInvocation setSelector:selector];
196+
XCTAssertThrowsSpecificNamed([[OCMInvocationConstraint alloc] initWithInvocation:anInvocation], NSException, NSInvalidArgumentException);
197+
}
198+
145199
@end

0 commit comments

Comments
 (0)