Skip to content

Commit a9ac1c9

Browse files
committed
Add location recording to all macros.
For large CI systems it can be costly to generate debug information. Recording location data for all of the stub/expect/reject macros makes it a lot easier to record/find failures.
1 parent 6358799 commit a9ac1c9

File tree

8 files changed

+86
-23
lines changed

8 files changed

+86
-23
lines changed

Source/OCMock/OCMMacroState.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@
2929
BOOL invocationDidThrow;
3030
}
3131

32-
+ (void)beginStubMacro;
32+
+ (void)beginStubMacroAtLocation:(OCMLocation *)aLocation;
3333
+ (OCMStubRecorder *)endStubMacro;
3434

35-
+ (void)beginExpectMacro;
35+
+ (void)beginExpectMacroAtLocation:(OCMLocation *)aLocation;
3636
+ (OCMStubRecorder *)endExpectMacro;
3737

38-
+ (void)beginRejectMacro;
38+
+ (void)beginRejectMacroAtLocation:(OCMLocation *)aLocation;
3939
+ (OCMStubRecorder *)endRejectMacro;
4040

4141
+ (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation;

Source/OCMock/OCMMacroState.m

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ @implementation OCMMacroState
2525

2626
#pragma mark Methods to begin/end macros
2727

28-
+ (void)beginStubMacro
28+
+ (void)beginStubMacroAtLocation:(OCMLocation *)aLocation
2929
{
3030
OCMStubRecorder *recorder = [[[OCMStubRecorder alloc] init] autorelease];
31+
recorder.ocm_location = aLocation;
3132
OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder];
3233
[NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState;
3334
[macroState release];
@@ -40,21 +41,31 @@ + (OCMStubRecorder *)endStubMacro
4041
OCMStubRecorder *recorder = [[(OCMStubRecorder *)[globalState recorder] retain] autorelease];
4142
BOOL didThrow = [globalState invocationDidThrow];
4243
[threadDictionary removeObjectForKey:OCMGlobalStateKey];
43-
if(didThrow == NO && [recorder didRecordInvocation] == NO)
44-
{
45-
[NSException raise:NSInternalInconsistencyException
46-
format:@"Did not record an invocation in OCMStub/OCMExpect/OCMReject.\n"
47-
@"Possible causes are:\n"
48-
@"- The receiver is not a mock object.\n"
49-
@"- The selector conflicts with a selector implemented by OCMStubRecorder/OCMExpectationRecorder."];
50-
}
44+
if(didThrow == NO && [recorder didRecordInvocation] == NO)
45+
{
46+
OCMLocation *location = recorder.ocm_location;
47+
NSString *explanation = @"Did not record an invocation in OCMStub/OCMExpect/OCMReject.\n"
48+
@"Possible causes are:\n"
49+
@"- The receiver is not a mock object.\n"
50+
@"- The selector conflicts with a selector implemented by OCMStubRecorder/OCMExpectationRecorder.";
51+
if(location != nil)
52+
{
53+
[NSException raise:NSInternalInconsistencyException
54+
format:@"%@:%d :%@", [location file], (int)[location line], explanation];
55+
}
56+
else
57+
{
58+
[NSException raise:NSInternalInconsistencyException format:@"%@", explanation];
59+
}
60+
}
5161
return recorder;
5262
}
5363

5464

55-
+ (void)beginExpectMacro
65+
+ (void)beginExpectMacroAtLocation:(OCMLocation *)aLocation
5666
{
5767
OCMExpectationRecorder *recorder = [[[OCMExpectationRecorder alloc] init] autorelease];
68+
recorder.ocm_location = aLocation;
5869
OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder];
5970
[NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState;
6071
[macroState release];
@@ -66,9 +77,10 @@ + (OCMStubRecorder *)endExpectMacro
6677
}
6778

6879

69-
+ (void)beginRejectMacro
80+
+ (void)beginRejectMacroAtLocation:(OCMLocation *)aLocation
7081
{
7182
OCMExpectationRecorder *recorder = [[[OCMExpectationRecorder alloc] init] autorelease];
83+
recorder.ocm_location = aLocation;
7284
OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder];
7385
[NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState;
7486
[macroState release];
@@ -92,7 +104,7 @@ + (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation
92104
+ (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation withQuantifier:(OCMQuantifier *)quantifier
93105
{
94106
OCMVerifier *recorder = [[[OCMVerifier alloc] init] autorelease];
95-
[recorder setLocation:aLocation];
107+
recorder.ocm_location = aLocation;
96108
[recorder setQuantifier:quantifier];
97109
OCMMacroState *macroState = [[OCMMacroState alloc] initWithRecorder:recorder];
98110
[NSThread currentThread].threadDictionary[OCMGlobalStateKey] = macroState;

Source/OCMock/OCMRecorder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#import <Foundation/Foundation.h>
1818

19+
#import "OCMLocation.h"
20+
1921
@class OCMockObject;
2022
@class OCMInvocationMatcher;
2123

@@ -28,6 +30,9 @@
2830
BOOL shouldReturnMockFromInit;
2931
}
3032

33+
// Using `ocm_` prefix to minimize clashes with mocked objects using `location` as a property.
34+
@property(retain) OCMLocation *ocm_location;
35+
3136
- (instancetype)init;
3237
- (instancetype)initWithMockObject:(OCMockObject *)aMockObject;
3338

Source/OCMock/OCMRecorder.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ - (void)setShouldReturnMockFromInit:(BOOL)flag
5151

5252
- (void)dealloc
5353
{
54+
[_ocm_location release];
5455
[invocationMatcher release];
5556
[super dealloc];
5657
}

Source/OCMock/OCMVerifier.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@
1616

1717
#import <OCMock/OCMRecorder.h>
1818

19-
@class OCMLocation;
2019
@class OCMQuantifier;
2120

2221
@interface OCMVerifier : OCMRecorder
2322

24-
@property(strong) OCMLocation *location;
25-
@property(strong) OCMQuantifier *quantifier;
23+
@property(retain) OCMQuantifier *quantifier;
2624

2725
- (id)withQuantifier:(OCMQuantifier *)quantifier;
2826

Source/OCMock/OCMVerifier.m

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,11 @@ - (id)withQuantifier:(OCMQuantifier *)quantifier
4444
- (void)forwardInvocation:(NSInvocation *)anInvocation
4545
{
4646
[super forwardInvocation:anInvocation];
47-
[mockObject verifyInvocation:invocationMatcher withQuantifier:self.quantifier atLocation:self.location];
47+
[mockObject verifyInvocation:invocationMatcher withQuantifier:self.quantifier atLocation:self.ocm_location];
4848
}
4949

5050
- (void)dealloc
5151
{
52-
[_location release];
5352
[_quantifier release];
5453
[super dealloc];
5554
}

Source/OCMock/OCMockMacros.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#define OCMStub(invocation) \
3838
({ \
3939
_OCMSilenceWarnings( \
40-
[OCMMacroState beginStubMacro]; \
40+
[OCMMacroState beginStubMacroAtLocation:OCMMakeLocation(nil, __FILE__, __LINE__)]; \
4141
OCMStubRecorder *recorder = nil; \
4242
@try{ \
4343
invocation; \
@@ -55,7 +55,7 @@
5555
#define OCMExpect(invocation) \
5656
({ \
5757
_OCMSilenceWarnings( \
58-
[OCMMacroState beginExpectMacro]; \
58+
[OCMMacroState beginExpectMacroAtLocation:OCMMakeLocation(nil, __FILE__, __LINE__)]; \
5959
OCMStubRecorder *recorder = nil; \
6060
@try{ \
6161
invocation; \
@@ -73,7 +73,7 @@
7373
#define OCMReject(invocation) \
7474
({ \
7575
_OCMSilenceWarnings( \
76-
[OCMMacroState beginRejectMacro]; \
76+
[OCMMacroState beginRejectMacroAtLocation:OCMMakeLocation(nil, __FILE__, __LINE__)]; \
7777
OCMStubRecorder *recorder = nil; \
7878
@try{ \
7979
invocation; \

Source/OCMockTests/OCMockObjectMacroTests.m

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,54 @@ - (void)testShouldHintAtPossibleReasonWhenVerifyingMethodThatCannotBeMocked
454454
}
455455
}
456456

457+
- (void)testStubExpectAndRejectShouldCaptureFileAndLineNumbers
458+
{
459+
NSString *expectedFile = [NSString stringWithUTF8String:__FILE__];
460+
int expectedLine;
461+
BOOL caughtException = NO;
462+
id realObject = [NSMutableArray array];
463+
464+
@try
465+
{
466+
caughtException = NO;
467+
expectedLine = __LINE__; OCMStub([realObject addObject:@"foo"]);
468+
}
469+
@catch (NSException *e)
470+
{
471+
XCTAssertTrue([[e reason] containsString:expectedFile], @"`%@` should contain `%@`", [e reason], expectedFile);
472+
XCTAssertTrue([[e reason] containsString:[[NSNumber numberWithInt:expectedLine] stringValue]], @"`%@` should contain `%d`", [e reason], expectedLine);
473+
caughtException = YES;
474+
}
475+
XCTAssertTrue(caughtException);
476+
477+
@try
478+
{
479+
caughtException = NO;
480+
expectedLine = __LINE__; OCMExpect([realObject addObject:@"foo"]);
481+
}
482+
@catch (NSException *e)
483+
{
484+
XCTAssertTrue([[e reason] containsString:expectedFile], @"`%@` should contain `%@`", [e reason], expectedFile);
485+
XCTAssertTrue([[e reason] containsString:[[NSNumber numberWithInt:expectedLine] stringValue]], @"`%@` should contain `%d`", [e reason], expectedLine);
486+
caughtException = YES;
487+
}
488+
XCTAssertTrue(caughtException);
489+
490+
@try
491+
{
492+
caughtException = NO;
493+
expectedLine = __LINE__; OCMReject([realObject addObject:@"foo"]);
494+
}
495+
@catch (NSException *e)
496+
{
497+
XCTAssertTrue([[e reason] containsString:expectedFile], @"`%@` should contain `%@`", [e reason], expectedFile);
498+
XCTAssertTrue([[e reason] containsString:[[NSNumber numberWithInt:expectedLine] stringValue]], @"`%@` should contain `%d`", [e reason], expectedLine);
499+
caughtException = YES;
500+
}
501+
XCTAssertTrue(caughtException);
502+
503+
}
504+
457505

458506
- (void)testCanExplicitlySelectClassMethodForStubs
459507
{

0 commit comments

Comments
 (0)