diff --git a/Source/OCMock/OCMStubRecorder.h b/Source/OCMock/OCMStubRecorder.h index 383d9b45..ca8d4e2f 100644 --- a/Source/OCMock/OCMStubRecorder.h +++ b/Source/OCMock/OCMStubRecorder.h @@ -42,15 +42,14 @@ @interface OCMStubRecorder (Properties) -#define andReturn(aValue) _andReturn(({ \ - __typeof__(aValue) _val = (aValue); \ - NSValue *_nsval = [NSValue value:&_val withObjCType:@encode(__typeof__(_val))]; \ - if (OCMIsObjectType(@encode(__typeof(_val)))) { \ - objc_setAssociatedObject(_nsval, "OCMAssociatedBoxedValue", *(__unsafe_unretained id *) (void *) &_val, OBJC_ASSOCIATION_RETAIN); \ - } \ - _nsval; \ +#define andReturn(aValue) _andReturn(({ \ + __typeof__(aValue) _val = (aValue); \ + const char *_encoding = @encode(__typeof(_val)); \ + BOOL _boxed = !OCMIsObjectType(_encoding); \ + id _retVal = _boxed ? [NSValue value:&_val withObjCType:_encoding] : *(const id*)(void *)(&_val); \ + @[_retVal, @(_boxed)]; \ })) -@property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSValue *); +@property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSArray *); #define andThrow(anException) _andThrow(anException) @property (nonatomic, readonly) OCMStubRecorder *(^ _andThrow)(NSException *); diff --git a/Source/OCMock/OCMStubRecorder.m b/Source/OCMock/OCMStubRecorder.m index 2c2448b1..75fa42cd 100644 --- a/Source/OCMock/OCMStubRecorder.m +++ b/Source/OCMock/OCMStubRecorder.m @@ -126,21 +126,14 @@ @implementation OCMStubRecorder (Properties) @dynamic _andReturn; -- (OCMStubRecorder * (^)(NSValue *))_andReturn -{ - id (^theBlock)(id) = ^(NSValue *aValue) { - if(OCMIsObjectType([aValue objCType])) - { - id objValue = nil; - [aValue getValue:&objValue]; // TODO: deprecated but replacement available in 10.13 only - return [self andReturn:objValue]; - } - else - { - return [self andReturnValue:aValue]; - } +- (OCMStubRecorder *(^)(NSArray *))_andReturn +{ + id (^theBlock)(NSArray *) = ^ (NSArray *aTuple) + { + id value = aTuple[0]; + return [aTuple[1] boolValue] ? [self andReturnValue:value] : [self andReturn:value]; }; - return (id)[[theBlock copy] autorelease]; + return [[theBlock copy] autorelease]; } diff --git a/Source/OCMock/OCMockMacros.h b/Source/OCMock/OCMockMacros.h index 22535572..f0155849 100644 --- a/Source/OCMock/OCMockMacros.h +++ b/Source/OCMock/OCMockMacros.h @@ -34,68 +34,76 @@ #define OCMObserverMock() [OCMockObject observerMock] -#define OCMStub(invocation) \ +#define OCMStubWithStateClass(MacroStateClass, invocation) \ ({ \ _OCMSilenceWarnings( \ - [OCMMacroState beginStubMacro]; \ + [MacroStateClass beginStubMacro]; \ OCMStubRecorder *recorder = nil; \ @try{ \ invocation; \ }@catch(...){ \ - [[OCMMacroState globalState] setInvocationDidThrow:YES]; \ + [[MacroStateClass globalState] setInvocationDidThrow:YES]; \ /* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \ @throw; \ }@finally{ \ - recorder = [OCMMacroState endStubMacro]; \ + recorder = [MacroStateClass endStubMacro]; \ } \ recorder; \ ); \ }) -#define OCMExpect(invocation) \ +#define OCMStub(invocation) OCMStubWithStateClass(OCMMacroState, invocation) + +#define OCMExpectWithStateClass(MacroStateClass, invocation) \ ({ \ _OCMSilenceWarnings( \ - [OCMMacroState beginExpectMacro]; \ + [MacroStateClass beginExpectMacro]; \ OCMStubRecorder *recorder = nil; \ @try{ \ invocation; \ }@catch(...){ \ - [[OCMMacroState globalState] setInvocationDidThrow:YES]; \ + [[MacroStateClass globalState] setInvocationDidThrow:YES]; \ /* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \ @throw; \ }@finally{ \ - recorder = [OCMMacroState endExpectMacro]; \ + recorder = [MacroStateClass endExpectMacro]; \ } \ recorder; \ ); \ }) -#define OCMReject(invocation) \ +#define OCMExpect(invocation) OCMExpectWithStateClass(OCMMacroState, invocation) + +#define OCMRejectWithStateClass(MacroStateClass, invocation) \ ({ \ _OCMSilenceWarnings( \ - [OCMMacroState beginRejectMacro]; \ + [MacroStateClass beginRejectMacro]; \ OCMStubRecorder *recorder = nil; \ @try{ \ invocation; \ }@catch(...){ \ - [[OCMMacroState globalState] setInvocationDidThrow:YES]; \ + [[MacroStateClass globalState] setInvocationDidThrow:YES]; \ /* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \ @throw; \ }@finally{ \ - recorder = [OCMMacroState endRejectMacro]; \ + recorder = [MacroStateClass endRejectMacro]; \ } \ recorder; \ ); \ }) +#define OCMReject(invocation) OCMRejectWithStateClass(OCMMacroState, invocation) -#define OCMClassMethod(invocation) \ + +#define OCMClassMethodWithStateClass(MacroStateClass, invocation) \ _OCMSilenceWarnings( \ - [[OCMMacroState globalState] switchToClassMethod]; \ + [[MacroStateClass globalState] switchToClassMethod]; \ invocation; \ ); +#define OCMClassMethod(invocation) OCMClassMethodWithStateClass(OCMMacroState, invocation) + #ifndef OCM_DISABLE_SHORT_SYNTAX #define ClassMethod(invocation) OCMClassMethod(invocation) @@ -106,38 +114,43 @@ #define OCMVerifyAllWithDelay(mock, delay) [(OCMockObject *)mock verifyWithDelay:delay atLocation:OCMMakeLocation(self, __FILE__, __LINE__)] -#define _OCMVerify(invocation) \ +#define _OCMVerifyWithStateClass(MacroStateClass, invocation) \ ({ \ _OCMSilenceWarnings( \ - [OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \ + [MacroStateClass beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \ @try{ \ invocation; \ }@catch(...){ \ - [[OCMMacroState globalState] setInvocationDidThrow:YES]; \ + [[MacroStateClass globalState] setInvocationDidThrow:YES]; \ /* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \ @throw; \ }@finally{ \ - [OCMMacroState endVerifyMacro]; \ + [MacroStateClass endVerifyMacro]; \ } \ ); \ }) -#define _OCMVerifyWithQuantifier(quantifier, invocation) \ +#define _OCMVerify(invocation) _OCMVerifyWithStateClass(OCMMacroState, invocation) + + +#define _OCMVerifyWithQuantifierAndStateClass(MacroStateClass, quantifier, invocation) \ ({ \ _OCMSilenceWarnings( \ - [OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__) withQuantifier:quantifier]; \ + [MacroStateClass beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__) withQuantifier:quantifier]; \ @try{ \ invocation; \ }@catch(...){ \ - [[OCMMacroState globalState] setInvocationDidThrow:YES]; \ + [[MacroStateClass globalState] setInvocationDidThrow:YES]; \ /* NOLINTNEXTLINE(google-objc-avoid-throwing-exception) */ \ @throw; \ }@finally{ \ - [OCMMacroState endVerifyMacro]; \ + [MacroStateClass endVerifyMacro]; \ } \ ); \ }) +#define _OCMVerifyWithQuantifier(quantifier, invocation) _OCMVerifyWithQuantifierAndStateClass(OCMMacroState, quantifier, invocation) + // explanation for macros below here: https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros #define _OCMVerify_1(A) _OCMVerify(A)