blob: 11a397084f4892c14bc5337c3afe87efdded3e1c [file] [log] [blame]
/*
* Copyright (c) 2014-2015 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
@protocol TestProtocolForMacroTesting
- (NSString *)stringValue;
@end
@interface TestClassForMacroTesting : NSObject <TestProtocolForMacroTesting>
@end
@implementation TestClassForMacroTesting
- (NSString *)stringValue
{
return @"FOO";
}
@end
@interface TestClassWithDecimalReturnMethod : NSObject
- (NSDecimalNumber*)method;
@end
@implementation TestClassWithDecimalReturnMethod
- (NSDecimalNumber*)method {
return nil;
}
@end
// implemented in OCMockObjectClassMethodMockingTests
@interface TestClassWithClassMethods : NSObject
+ (NSString *)foo;
+ (NSString *)bar;
- (NSString *)bar;
@end
@interface OCMockObjectMacroTests : XCTestCase
{
BOOL shouldCaptureFailure;
NSString *reportedDescription;
NSString *reportedFile;
NSUInteger reportedLine;
}
@end
@implementation OCMockObjectMacroTests
- (void)recordFailureWithDescription:(NSString *)description inFile:(NSString *)file atLine:(NSUInteger)line expected:(BOOL)expected
{
if(shouldCaptureFailure)
{
reportedDescription = description;
reportedFile = file;
reportedLine = line;
}
else
{
[super recordFailureWithDescription:description inFile:file atLine:line expected:expected];
}
}
- (void)testReportsVerifyFailureWithCorrectLocation
{
id mock = OCMClassMock([NSString class]);
[[mock expect] lowercaseString];
shouldCaptureFailure = YES;
OCMVerifyAll(mock); const char *expectedFile = __FILE__; int expectedLine = __LINE__;
shouldCaptureFailure = NO;
XCTAssertNotNil(reportedDescription, @"Should have recorded a failure with description.");
XCTAssertEqualObjects([NSString stringWithUTF8String:expectedFile], reportedFile, @"Should have reported correct file.");
XCTAssertEqual(expectedLine, (int)reportedLine, @"Should have reported correct line");
}
- (void)testReportsIgnoredExceptionsAtVerifyLocation
{
id mock = OCMClassMock([NSString class]);
[[mock reject] lowercaseString];
@try
{
[mock lowercaseString];
}
@catch (NSException *exception)
{
// ignore; the mock will rethrow this in verify
}
shouldCaptureFailure = YES;
OCMVerifyAll(mock); const char *expectedFile = __FILE__; int expectedLine = __LINE__;
shouldCaptureFailure = NO;
XCTAssertTrue([reportedDescription rangeOfString:@"ignored"].location != NSNotFound, @"Should have reported ignored exceptions.");
XCTAssertEqualObjects([NSString stringWithUTF8String:expectedFile], reportedFile, @"Should have reported correct file.");
XCTAssertEqual(expectedLine, (int)reportedLine, @"Should have reported correct line");
}
- (void)testReportsVerifyWithDelayFailureWithCorrectLocation
{
id mock = OCMClassMock([NSString class]);
[[mock expect] lowercaseString];
shouldCaptureFailure = YES;
OCMVerifyAllWithDelay(mock, 0.05); const char *expectedFile = __FILE__; int expectedLine = __LINE__;
shouldCaptureFailure = NO;
XCTAssertNotNil(reportedDescription, @"Should have recorded a failure with description.");
XCTAssertEqualObjects([NSString stringWithUTF8String:expectedFile], reportedFile, @"Should have reported correct file.");
XCTAssertEqual(expectedLine, (int)reportedLine, @"Should have reported correct line");
}
- (void)testSetsUpStubsForCorrectMethods
{
id mock = OCMStrictClassMock([NSString class]);
OCMStub([mock uppercaseString]).andReturn(@"TEST_STRING");
XCTAssertEqualObjects(@"TEST_STRING", [mock uppercaseString], @"Should have returned stubbed value");
XCTAssertThrows([mock lowercaseString]);
}
- (void)testSetsUpStubsWithNonObjectReturnValues
{
id mock = OCMStrictClassMock([NSString class]);
OCMStub([mock boolValue]).andReturn(YES);
XCTAssertEqual(YES, [mock boolValue], @"Should have returned stubbed value");
}
- (void)testSetsUpStubsWithStructureReturnValues
{
id mock = OCMStrictClassMock([NSString class]);
NSRange expected = NSMakeRange(123, 456);
OCMStub([mock rangeOfString:[OCMArg any]]).andReturn(expected);
NSRange actual = [mock rangeOfString:@"substring"];
XCTAssertEqual((NSUInteger)123, actual.location, @"Should have returned stubbed value");
XCTAssertEqual((NSUInteger)456, actual.length, @"Should have returned stubbed value");
}
- (void)testSetsUpStubReturningNilForIdReturnType
{
id mock = OCMClassMock([NSString class]);
OCMStub([mock lowercaseString]).andReturn(nil);
XCTAssertNil([mock lowercaseString], @"Should have returned stubbed value");
}
- (void)testSetsUpExceptionThrowing
{
id mock = OCMClassMock([NSString class]);
OCMStub([mock uppercaseString]).andThrow([NSException exceptionWithName:@"TestException" reason:@"Testing" userInfo:nil]);
XCTAssertThrowsSpecificNamed([mock uppercaseString], NSException, @"TestException", @"Should have thrown correct exception");
}
- (void)testSetsUpNotificationPostingAndNotificationObserving
{
id mock = OCMProtocolMock(@protocol(TestProtocolForMacroTesting));
NSNotification *n = [NSNotification notificationWithName:@"TestNotification" object:nil];
id observer = OCMObserverMock();
[[NSNotificationCenter defaultCenter] addMockObserver:observer name:[n name] object:nil];
OCMExpect([observer notificationWithName:[n name] object:[OCMArg any]]);
OCMStub([mock stringValue]).andPost(n);
[mock stringValue];
OCMVerifyAll(observer);
}
- (void)testSetsUpSubstituteCall
{
id mock = OCMStrictProtocolMock(@protocol(TestProtocolForMacroTesting));
OCMStub([mock stringValue]).andCall(self, @selector(stringValueForTesting));
XCTAssertEqualObjects([mock stringValue], @"TEST_STRING_FROM_TESTCASE", @"Should have called method from test case");
}
- (NSString *)stringValueForTesting
{
return @"TEST_STRING_FROM_TESTCASE";
}
- (void)testCanChainPropertyBasedActions
{
id mock = OCMPartialMock([[TestClassForMacroTesting alloc] init]);
__block BOOL didCallBlock = NO;
void (^theBlock)(NSInvocation *) = ^(NSInvocation *invocation)
{
didCallBlock = YES;
};
OCMStub([mock stringValue]).andDo(theBlock).andForwardToRealObject();
NSString *actual = [mock stringValue];
XCTAssertTrue(didCallBlock, @"Should have called block");
XCTAssertEqualObjects(@"FOO", actual, @"Should have forwarded invocation");
}
- (void)testCanUseVariablesInInvocationSpec
{
id mock = OCMStrictClassMock([NSString class]);
NSString *expected = @"foo";
OCMStub([mock rangeOfString:expected]).andReturn(NSMakeRange(0, 3));
XCTAssertThrows([mock rangeOfString:@"bar"], @"Should not have accepted invocation with non-matching arg.");
}
- (void)testSetsUpExpectations
{
id mock = OCMClassMock([TestClassForMacroTesting class]);
OCMExpect([mock stringValue]).andReturn(@"TEST_STRING");
XCTAssertThrows([mock verify], @"Should have complained about expected method not being invoked");
XCTAssertEqual([mock stringValue], @"TEST_STRING", @"Should have stubbed method, too");
XCTAssertNoThrow([mock verify], @"Should have accepted invocation as matching expectation");
}
- (void)testShouldNotReportErrorWhenMethodWasInvoked
{
id mock = OCMClassMock([NSString class]);
[mock lowercaseString];
shouldCaptureFailure = YES;
OCMVerify([mock lowercaseString]);
shouldCaptureFailure = NO;
XCTAssertNil(reportedDescription, @"Should not have recorded a failure.");
}
- (void)testShouldReportErrorWhenMethodWasNotInvoked
{
id mock = OCMClassMock([NSString class]);
[mock lowercaseString];
shouldCaptureFailure = YES;
OCMVerify([mock uppercaseString]); const char *expectedFile = __FILE__; int expectedLine = __LINE__;
shouldCaptureFailure = NO;
XCTAssertNotNil(reportedDescription, @"Should have recorded a failure with description.");
XCTAssertEqualObjects([NSString stringWithUTF8String:expectedFile], reportedFile, @"Should have reported correct file.");
XCTAssertEqual(expectedLine, (int)reportedLine, @"Should have reported correct line");
}
- (void)testShouldThrowDescriptiveExceptionWhenTryingToVerifyUnimplementedMethod
{
id mock = OCMClassMock([NSString class]);
// have not found a way to report the error; it seems we must throw an
// exception to get out of the forwarding machinery
XCTAssertThrowsSpecificNamed(OCMVerify([mock arrayByAddingObject:nil]),
NSException,
NSInvalidArgumentException,
@"should throw NSInvalidArgumentException exception");
}
- (void)testCanExplicitlySelectClassMethodForStubs
{
id mock = OCMClassMock([TestClassWithClassMethods class]);
OCMStub(ClassMethod([mock bar])).andReturn(@"mocked-class");
OCMStub([mock bar]).andReturn(@"mocked-instance");
XCTAssertEqualObjects(@"mocked-class", [TestClassWithClassMethods bar], @"Should have stubbed class method.");
XCTAssertEqualObjects(@"mocked-instance", [mock bar], @"Should have stubbed instance method.");
}
- (void)testSelectsInstanceMethodForStubsWhenAmbiguous
{
id mock = OCMClassMock([TestClassWithClassMethods class]);
OCMStub([mock bar]).andReturn(@"mocked-instance");
XCTAssertEqualObjects(@"mocked-instance", [mock bar], @"Should have stubbed instance method.");
}
- (void)testSelectsClassMethodForStubsWhenUnambiguous
{
id mock = OCMClassMock([TestClassWithClassMethods class]);
OCMStub([mock foo]).andReturn(@"mocked-class");
XCTAssertEqualObjects(@"mocked-class", [TestClassWithClassMethods foo], @"Should have stubbed class method.");
}
- (void)testCanExplicitlySelectClassMethodForVerify
{
id mock = OCMClassMock([TestClassWithClassMethods class]);
[TestClassWithClassMethods bar];
OCMVerify(ClassMethod([mock bar]));
}
- (void)testSelectsInstanceMethodForVerifyWhenAmbiguous
{
id mock = OCMClassMock([TestClassWithClassMethods class]);
[mock bar];
OCMVerify([mock bar]);
}
- (void)testSelectsClassMethodForVerifyWhenUnambiguous
{
id mock = OCMClassMock([TestClassWithClassMethods class]);
[TestClassWithClassMethods foo];
OCMVerify([mock foo]);
}
- (void)testCanUseMacroToStubMethodWithDecimalReturnValue
{
id mock = OCMClassMock([TestClassWithDecimalReturnMethod class]);
OCMStub([mock method]).andReturn([NSDecimalNumber decimalNumberWithDecimal:[@0 decimalValue]]);
XCTAssertEqualObjects([mock method], [NSDecimalNumber decimalNumberWithDecimal:[@0 decimalValue]]);
}
@end