Skip to content

Commit 9f173d0

Browse files
committed
Allow injection of macro state class into OCM macros
We have a need to inject a replacement for `OCMMacroState` for when we are doing cross process testing using a library like https://github.com/google/EarlGrey/tree/earlgrey2. This simple expansion to the basic macros will give us the flexibility we need to allow us to use OCMock v3 syntax instead of falling back to OCMock v2 syntax when working with EarlGrey tests. The modification to andReturn macro allows us to move objects across the process boundary instead of "hiding" an object instead of an NSValue. The "hack" of using NSArray as a tuple could be replaced by a real object, or an NSDictionary, but I went with the simple stupid approach to start.
1 parent 6358799 commit 9f173d0

File tree

3 files changed

+49
-44
lines changed

3 files changed

+49
-44
lines changed

Source/OCMock/OCMStubRecorder.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,14 @@
4242

4343
@interface OCMStubRecorder (Properties)
4444

45-
#define andReturn(aValue) _andReturn(({ \
46-
__typeof__(aValue) _val = (aValue); \
47-
NSValue *_nsval = [NSValue value:&_val withObjCType:@encode(__typeof__(_val))]; \
48-
if (OCMIsObjectType(@encode(__typeof(_val)))) { \
49-
objc_setAssociatedObject(_nsval, "OCMAssociatedBoxedValue", *(__unsafe_unretained id *) (void *) &_val, OBJC_ASSOCIATION_RETAIN); \
50-
} \
51-
_nsval; \
45+
#define andReturn(aValue) _andReturn(({ \
46+
__typeof__(aValue) _val = (aValue); \
47+
const char *_encoding = @encode(__typeof(_val)); \
48+
BOOL _boxed = !OCMIsObjectType(_encoding); \
49+
id _retVal = _boxed ? [NSValue value:&_val withObjCType:_encoding] : *(const id*)(void *)(&_val); \
50+
@[_retVal, @(_boxed)]; \
5251
}))
53-
@property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSValue *);
52+
@property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSArray<id> *);
5453

5554
#define andThrow(anException) _andThrow(anException)
5655
@property (nonatomic, readonly) OCMStubRecorder *(^ _andThrow)(NSException *);

Source/OCMock/OCMStubRecorder.m

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,14 @@ @implementation OCMStubRecorder (Properties)
126126

127127
@dynamic _andReturn;
128128

129-
- (OCMStubRecorder * (^)(NSValue *))_andReturn
130-
{
131-
id (^theBlock)(id) = ^(NSValue *aValue) {
132-
if(OCMIsObjectType([aValue objCType]))
133-
{
134-
id objValue = nil;
135-
[aValue getValue:&objValue]; // TODO: deprecated but replacement available in 10.13 only
136-
return [self andReturn:objValue];
137-
}
138-
else
139-
{
140-
return [self andReturnValue:aValue];
141-
}
129+
- (OCMStubRecorder *(^)(NSArray<id> *))_andReturn
130+
{
131+
id (^theBlock)(NSArray<id> *) = ^ (NSArray<id> *aTuple)
132+
{
133+
id value = aTuple[0];
134+
return [aTuple[1] boolValue] ? [self andReturnValue:value] : [self andReturn:value];
142135
};
143-
return (id)[[theBlock copy] autorelease];
136+
return [[theBlock copy] autorelease];
144137
}
145138

146139

Source/OCMock/OCMockMacros.h

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,68 +34,76 @@
3434
#define OCMObserverMock() [OCMockObject observerMock]
3535

3636

37-
#define OCMStub(invocation) \
37+
#define OCMStubWithStateClass(MacroStateClass, invocation) \
3838
({ \
3939
_OCMSilenceWarnings( \
40-
[OCMMacroState beginStubMacro]; \
40+
[MacroStateClass beginStubMacro]; \
4141
OCMStubRecorder *recorder = nil; \
4242
@try{ \
4343
invocation; \
4444
}@catch(...){ \
45-
[[OCMMacroState globalState] setInvocationDidThrow:YES]; \
45+
[[MacroStateClass globalState] setInvocationDidThrow:YES]; \
4646
/* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \
4747
@throw; \
4848
}@finally{ \
49-
recorder = [OCMMacroState endStubMacro]; \
49+
recorder = [MacroStateClass endStubMacro]; \
5050
} \
5151
recorder; \
5252
); \
5353
})
5454

55-
#define OCMExpect(invocation) \
55+
#define OCMStub(invocation) OCMStubWithStateClass(OCMMacroState, invocation)
56+
57+
#define OCMExpectWithStateClass(MacroStateClass, invocation) \
5658
({ \
5759
_OCMSilenceWarnings( \
58-
[OCMMacroState beginExpectMacro]; \
60+
[MacroStateClass beginExpectMacro]; \
5961
OCMStubRecorder *recorder = nil; \
6062
@try{ \
6163
invocation; \
6264
}@catch(...){ \
63-
[[OCMMacroState globalState] setInvocationDidThrow:YES]; \
65+
[[MacroStateClass globalState] setInvocationDidThrow:YES]; \
6466
/* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \
6567
@throw; \
6668
}@finally{ \
67-
recorder = [OCMMacroState endExpectMacro]; \
69+
recorder = [MacroStateClass endExpectMacro]; \
6870
} \
6971
recorder; \
7072
); \
7173
})
7274

73-
#define OCMReject(invocation) \
75+
#define OCMExpect(invocation) OCMExpectWithStateClass(OCMMacroState, invocation)
76+
77+
#define OCMRejectWithStateClass(MacroStateClass, invocation) \
7478
({ \
7579
_OCMSilenceWarnings( \
76-
[OCMMacroState beginRejectMacro]; \
80+
[MacroStateClass beginRejectMacro]; \
7781
OCMStubRecorder *recorder = nil; \
7882
@try{ \
7983
invocation; \
8084
}@catch(...){ \
81-
[[OCMMacroState globalState] setInvocationDidThrow:YES]; \
85+
[[MacroStateClass globalState] setInvocationDidThrow:YES]; \
8286
/* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \
8387
@throw; \
8488
}@finally{ \
85-
recorder = [OCMMacroState endRejectMacro]; \
89+
recorder = [MacroStateClass endRejectMacro]; \
8690
} \
8791
recorder; \
8892
); \
8993
})
9094

95+
#define OCMReject(invocation) OCMRejectWithStateClass(OCMMacroState, invocation)
9196

9297

93-
#define OCMClassMethod(invocation) \
98+
99+
#define OCMClassMethodWithStateClass(MacroStateClass, invocation) \
94100
_OCMSilenceWarnings( \
95-
[[OCMMacroState globalState] switchToClassMethod]; \
101+
[[MacroStateClass globalState] switchToClassMethod]; \
96102
invocation; \
97103
);
98104

105+
#define OCMClassMethod(invocation) OCMClassMethodWithStateClass(OCMMacroState, invocation)
106+
99107

100108
#ifndef OCM_DISABLE_SHORT_SYNTAX
101109
#define ClassMethod(invocation) OCMClassMethod(invocation)
@@ -106,38 +114,43 @@
106114

107115
#define OCMVerifyAllWithDelay(mock, delay) [(OCMockObject *)mock verifyWithDelay:delay atLocation:OCMMakeLocation(self, __FILE__, __LINE__)]
108116

109-
#define _OCMVerify(invocation) \
117+
#define _OCMVerifyWithStateClass(MacroStateClass, invocation) \
110118
({ \
111119
_OCMSilenceWarnings( \
112-
[OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \
120+
[MacroStateClass beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \
113121
@try{ \
114122
invocation; \
115123
}@catch(...){ \
116-
[[OCMMacroState globalState] setInvocationDidThrow:YES]; \
124+
[[MacroStateClass globalState] setInvocationDidThrow:YES]; \
117125
/* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \
118126
@throw; \
119127
}@finally{ \
120-
[OCMMacroState endVerifyMacro]; \
128+
[MacroStateClass endVerifyMacro]; \
121129
} \
122130
); \
123131
})
124132

125-
#define _OCMVerifyWithQuantifier(quantifier, invocation) \
133+
#define _OCMVerify(invocation) _OCMVerifyWithStateClass(OCMMacroState, invocation)
134+
135+
136+
#define _OCMVerifyWithQuantifierAndStateClass(MacroStateClass, quantifier, invocation) \
126137
({ \
127138
_OCMSilenceWarnings( \
128-
[OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__) withQuantifier:quantifier]; \
139+
[MacroStateClass beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__) withQuantifier:quantifier]; \
129140
@try{ \
130141
invocation; \
131142
}@catch(...){ \
132-
[[OCMMacroState globalState] setInvocationDidThrow:YES]; \
143+
[[MacroStateClass globalState] setInvocationDidThrow:YES]; \
133144
/* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \
134145
@throw; \
135146
}@finally{ \
136-
[OCMMacroState endVerifyMacro]; \
147+
[MacroStateClass endVerifyMacro]; \
137148
} \
138149
); \
139150
})
140151

152+
#define _OCMVerifyWithQuantifier(quantifier, invocation) _OCMVerifyWithQuantifierAndStateClass(OCMMacroState, quantifier, invocation)
153+
141154
// explanation for macros below here: https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros
142155

143156
#define _OCMVerify_1(A) _OCMVerify(A)

0 commit comments

Comments
 (0)