Skip to content

Commit 908ba9d

Browse files
Add support for multiple protocol mocks
- Remove warnings in `OCMockObjectRuntimeTests.m` - Add tests in `OCMockObjectProtocolMocksTests.m` to test new multiple protocol mock - Add new macros to create multi-Protocol mocks Completes #178.
1 parent afb7bc8 commit 908ba9d

File tree

7 files changed

+123
-12
lines changed

7 files changed

+123
-12
lines changed

Source/OCMock/OCMock.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@
3131

3232
#define OCMProtocolMock(protocol) [OCMockObject niceMockForProtocol:protocol]
3333

34+
#define OCMProtocolsMock(protocol, ...) [OCMockObject niceMockForProtocols:protocol, ## __VA_ARGS__]
35+
3436
#define OCMStrictProtocolMock(protocol) [OCMockObject mockForProtocol:protocol]
3537

38+
#define OCMStrictProtocolsMock(protocol, ...) [OCMockObject mockForProtocol:protocol, ## __VA_ARGS__]
39+
3640
#define OCMPartialMock(obj) [OCMockObject partialMockForObject:obj]
3741

3842
#define OCMObserverMock() [OCMockObject observerMock]

Source/OCMock/OCMockObject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@
3535

3636
+ (id)mockForClass:(Class)aClass;
3737
+ (id)mockForProtocol:(Protocol *)aProtocol;
38+
+ (id)mockForProtocols:(Protocol *)aProtocol, ...;
3839
+ (id)partialMockForObject:(NSObject *)anObject;
3940

4041
+ (id)niceMockForClass:(Class)aClass;
4142
+ (id)niceMockForProtocol:(Protocol *)aProtocol;
43+
+ (id)niceMockForProtocols:(Protocol *)aProtocol, ...;
4244

4345
+ (id)observerMock;
4446

Source/OCMock/OCMockObject.m

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ + (id)mockForProtocol:(Protocol *)aProtocol
5454
return [[[OCProtocolMockObject alloc] initWithProtocol:aProtocol] autorelease];
5555
}
5656

57+
+ (id)mockForProtocols:(Protocol *)aProtocol, ...
58+
{
59+
va_list args;
60+
va_start(args, aProtocol);
61+
id mock = [[[OCProtocolMockObject alloc] initWithProtocols:[self _variadicArgumentsToArray:aProtocol args:args]] autorelease];
62+
va_end(args);
63+
return mock;
64+
}
65+
5766
+ (id)partialMockForObject:(NSObject *)anObject
5867
{
5968
return [[[OCPartialMockObject alloc] initWithObject:anObject] autorelease];
@@ -70,6 +79,15 @@ + (id)niceMockForProtocol:(Protocol *)aProtocol
7079
return [self _makeNice:[self mockForProtocol:aProtocol]];
7180
}
7281

82+
+ (id)niceMockForProtocols:(Protocol *)aProtocol, ...
83+
{
84+
va_list args;
85+
va_start(args, aProtocol);
86+
id mock = [self _makeNice:[[[OCProtocolMockObject alloc] initWithProtocols:[self _variadicArgumentsToArray:aProtocol args:args]] autorelease]];
87+
va_end(args);
88+
return mock;
89+
}
90+
7391

7492
+ (id)_makeNice:(OCMockObject *)mock
7593
{
@@ -433,5 +451,25 @@ - (NSString *)_stubDescriptions:(BOOL)onlyExpectations
433451
return outputString;
434452
}
435453

454+
+ (NSArray *)_variadicArgumentsToArray:(id)firstObject args:(va_list)args
455+
{
456+
NSMutableArray *variadicObjects = nil;
457+
458+
if(firstObject)
459+
{
460+
variadicObjects = [[NSMutableArray alloc] init];
461+
[variadicObjects addObject:firstObject];
462+
463+
if(args != nil)
464+
{
465+
id eachObject;
466+
while ((eachObject = va_arg(args, id)) && eachObject != nil) {
467+
[variadicObjects addObject:eachObject];
468+
}
469+
}
470+
}
471+
472+
return [variadicObjects copy];
473+
}
436474

437475
@end

Source/OCMock/OCProtocolMockObject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818

1919
@interface OCProtocolMockObject : OCMockObject
2020
{
21-
Protocol *mockedProtocol;
21+
NSArray<Protocol *> *mockedProtocols;
2222
}
2323

2424
- (id)initWithProtocol:(Protocol *)aProtocol;
25+
- (id)initWithProtocols:(NSArray<Protocol *> *)protocols;
2526

2627
@end
2728

Source/OCMock/OCProtocolMockObject.m

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,55 @@ - (id)initWithProtocol:(Protocol *)aProtocol
2626
{
2727
NSParameterAssert(aProtocol != nil);
2828
[super init];
29-
mockedProtocol = aProtocol;
29+
mockedProtocols = @[aProtocol];
3030
return self;
3131
}
3232

33+
- (id)initWithProtocols:(NSArray<Protocol *> *)protocols
34+
{
35+
NSParameterAssert(protocols != nil);
36+
[super init];
37+
mockedProtocols = protocols;
38+
return self;
39+
}
40+
3341
- (NSString *)description
3442
{
35-
const char* name = protocol_getName(mockedProtocol);
36-
return [NSString stringWithFormat:@"OCMockObject(%s)", name];
43+
char* names = (char*)protocol_getName(mockedProtocols[0]);
44+
for(NSUInteger ix = 1; ix < mockedProtocols.count; ix++)
45+
{
46+
asprintf(&names, "%s, %s", names, protocol_getName(mockedProtocols[ix]));
47+
}
48+
return [NSString stringWithFormat:@"OCMockObject(%s)", names];
3749
}
3850

3951
#pragma mark Proxy API
4052

4153
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
4254
{
4355
struct { BOOL isRequired; BOOL isInstance; } opts[4] = { {YES, YES}, {NO, YES}, {YES, NO}, {NO, NO} };
44-
for(int i = 0; i < 4; i++)
56+
for(Protocol *aProtocol in mockedProtocols)
4557
{
46-
struct objc_method_description methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, opts[i].isRequired, opts[i].isInstance);
47-
if(methodDescription.name != NULL)
48-
return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
58+
for(int i = 0; i < 4; i++)
59+
{
60+
struct objc_method_description methodDescription = protocol_getMethodDescription(aProtocol, aSelector, opts[i].isRequired, opts[i].isInstance);
61+
if(methodDescription.name != NULL)
62+
return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
63+
}
4964
}
5065
return nil;
5166
}
5267

5368
- (BOOL)conformsToProtocol:(Protocol *)aProtocol
5469
{
55-
return protocol_conformsToProtocol(mockedProtocol, aProtocol);
70+
BOOL conformsToProtocol = NO;
71+
for(Protocol *procotol in mockedProtocols)
72+
{
73+
conformsToProtocol = protocol_conformsToProtocol(procotol, aProtocol);
74+
if(conformsToProtocol)
75+
break;
76+
}
77+
return conformsToProtocol;
5678
}
5779

5880
- (BOOL)respondsToSelector:(SEL)selector

Source/OCMockTests/OCMockObjectProtocolMocksTests.m

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,30 @@ - (void)testCanMockFormalProtocol
7070
[mock verify];
7171
}
7272

73+
- (void)testCanMockMultipleFormalProtocols
74+
{
75+
id mock = [OCMockObject mockForProtocols:@protocol(NSLocking), @protocol(NSObject)];
76+
[[mock expect] lock];
77+
[[mock expect] isProxy];
78+
79+
[mock lock];
80+
[mock isProxy];
81+
82+
[mock verify];
83+
}
84+
7385
- (void)testSetsCorrectNameForProtocolMockObjects
7486
{
7587
id mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
7688
XCTAssertEqualObjects(@"OCMockObject(NSLocking)", [mock description], @"Should have returned correct description.");
7789
}
7890

91+
- (void)testSetsCorrectNameForMultiProtocolMockObjects
92+
{
93+
id mock = [OCMockObject mockForProtocols:@protocol(NSLocking), @protocol(NSObject)];
94+
XCTAssertEqualObjects(@"OCMockObject(NSLocking, NSObject)", [mock description], @"Should have returned correct description.");
95+
}
96+
7997
- (void)testRaisesWhenUnknownMethodIsCalledOnProtocol
8098
{
8199
id mock = [OCMockObject mockForProtocol:@protocol(NSLocking)];
@@ -88,6 +106,13 @@ - (void)testConformsToMockedProtocol
88106
XCTAssertTrue([mock conformsToProtocol:@protocol(NSLocking)]);
89107
}
90108

109+
- (void)testConformsToMockedMultiProtocols
110+
{
111+
id mock = [OCMockObject mockForProtocols:@protocol(NSLocking), @protocol(NSObject)];
112+
XCTAssertTrue([mock conformsToProtocol:@protocol(NSLocking)]);
113+
XCTAssertTrue([mock conformsToProtocol:@protocol(NSObject)]);
114+
}
115+
91116
- (void)testRespondsToValidProtocolRequiredSelector
92117
{
93118
id mock = [OCMockObject mockForProtocol:@protocol(TestProtocol)];
@@ -106,19 +131,22 @@ - (void)testDoesNotRespondToInvalidProtocolSelector
106131
XCTAssertFalse([mock respondsToSelector:@selector(testDoesNotRespondToInvalidProtocolSelector)]);
107132
}
108133

109-
- (void)testWithTypedefReturnType {
134+
- (void)testWithTypedefReturnType
135+
{
110136
id mock = [OCMockObject mockForProtocol:@protocol(ProtocolWithTypedefs)];
111137
XCTAssertNoThrow([[[mock stub] andReturn:[TypedefInterface new]] typedefReturnValue1], @"Should accept a typedefed return-type");
112138
XCTAssertNoThrow([mock typedefReturnValue1]);
113139
}
114140

115-
- (void)testWithTypedefPointerReturnType {
141+
- (void)testWithTypedefPointerReturnType
142+
{
116143
id mock = [OCMockObject mockForProtocol:@protocol(ProtocolWithTypedefs)];
117144
XCTAssertNoThrow([[[mock stub] andReturn:[TypedefInterface new]] typedefReturnValue2], @"Should accept a typedefed return-type");
118145
XCTAssertNoThrow([mock typedefReturnValue2]);
119146
}
120147

121-
- (void)testWithTypedefParameter {
148+
- (void)testWithTypedefParameter
149+
{
122150
id mock = [OCMockObject mockForProtocol:@protocol(ProtocolWithTypedefs)];
123151
XCTAssertNoThrow([[mock stub] typedefParameter:nil], @"Should accept a typedefed parameter-type");
124152
XCTAssertNoThrow([mock typedefParameter:nil]);
@@ -147,9 +175,22 @@ - (void)testProtocolClassMethod
147175
XCTAssertEqual(@"stubbed", result, @"Should have stubbed the class method.");
148176
}
149177

178+
- (void)testMultipleProtocolClassMethod
179+
{
180+
id mock = OCMProtocolsMock(@protocol(TestProtocol), @protocol(NSLocking));
181+
OCMStub([mock stringValueClassMethod]).andReturn(@"stubbed");
182+
id result = [mock stringValueClassMethod];
183+
XCTAssertEqual(@"stubbed", result, @"Should have stubbed the class method.");
184+
}
185+
150186
- (void)testRefusesToCreateProtocolMockForNilProtocol
151187
{
152188
XCTAssertThrows(OCMProtocolMock(nil));
153189
}
154190

191+
- (void)testRefusesToCreateMultipleProtocolMockForNilProtocol
192+
{
193+
XCTAssertThrows(OCMProtocolsMock(nil));
194+
}
195+
155196
@end

Source/OCMockTests/OCMockObjectRuntimeTests.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ - (void)testCanMockNSMutableArray
122122
{
123123
id mock = [OCMockObject niceMockForClass:[NSMutableArray class]];
124124
id anArray = [[NSMutableArray alloc] init];
125+
126+
XCTAssertNotNil(mock);
127+
XCTAssertNotNil(anArray);
125128
}
126129

127130

0 commit comments

Comments
 (0)