blob: 4aa67dd285b01d152dcff4fd72eb3c72adc4a028 [file] [log] [blame]
/*
* Copyright (c) 2019-2021 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.h"
#pragma mark Helper classes
@interface TestClassForInternalTests : NSObject
@property(nonatomic, copy) NSString *title;
- (void)doStuffWithClass:(Class)aClass;
@end
@implementation TestClassForInternalTests
@synthesize title;
- (void)doStuffWithClass:(Class)aClass
{
// stubbed out anyway
}
@end
@interface OCMockObjectInternalTests : XCTestCase
@end
@implementation OCMockObjectInternalTests
#pragma mark Tests
- (void)testReRaisesFailFastExceptionsOnVerify
{
id mock = [OCMockObject mockForClass:[NSString class]];
@try
{
[mock lowercaseString];
}
@catch(NSException *exception)
{
// expected
}
XCTAssertThrows([mock verify], @"Should have reraised the exception.");
}
- (void)testDoesNotReRaiseStubbedExceptions
{
id mock = [OCMockObject mockForClass:[NSString class]];
[[[mock expect] andThrow:[NSException exceptionWithName:@"ExceptionForTest" reason:@"test" userInfo:nil]] lowercaseString];
@try
{
[mock lowercaseString];
}
@catch(NSException *exception)
{
// expected
}
XCTAssertNoThrow([mock verify], @"Should not have reraised stubbed exception.");
}
- (void)testAndThrowDoesntLeak
{
__weak NSException *exception = nil;
@autoreleasepool
{
id mock = [OCMockObject partialMockForObject:[NSProcessInfo processInfo]];
exception = [NSException exceptionWithName:NSGenericException
reason:nil
userInfo:nil];
[[[mock expect] andThrow:exception] arguments];
BOOL threw = NO;
@try
{
[[NSProcessInfo processInfo] arguments];
}
@catch(NSException *ex)
{
threw = YES;
}
XCTAssertTrue(threw);
[mock verify];
[mock stopMocking];
mock = nil;
}
XCTAssertNil(exception, @"The exception should have been released by now");
}
- (void)testReRaisesRejectExceptionsOnVerify
{
id mock = [OCMockObject niceMockForClass:[NSString class]];
[[mock reject] uppercaseString];
@try
{
[mock uppercaseString];
}
@catch(NSException *exception)
{
// expected
}
XCTAssertThrows([mock verify], @"Should have reraised the exception.");
}
- (void)testCanCreateExpectationsAfterInvocations
{
id mock = [OCMockObject mockForClass:[NSString class]];
[[mock expect] lowercaseString];
[mock lowercaseString];
[mock expect];
}
- (void)testArgumentConstraintsAreOnlyCalledAsOftenAsTheMethodIsCalled
{
__block int count = 0;
id mock = [OCMockObject mockForClass:[NSString class]];
[[mock stub] hasSuffix:[OCMArg checkWithBlock:^(id value) {
count++;
return YES;
}]];
[mock hasSuffix:@"foo"];
[mock hasSuffix:@"bar"];
XCTAssertEqual(2, count, @"Should have evaluated constraint only twice");
}
- (void)testVerifyWithDelayDoesNotWaitForRejects
{
id mock = [OCMockObject niceMockForClass:[NSString class]];
[[mock reject] hasSuffix:OCMOCK_ANY];
[[mock expect] hasPrefix:OCMOCK_ANY];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[mock hasPrefix:@"foo"];
});
NSDate *start = [NSDate date];
[mock verifyWithDelay:4];
NSDate *end = [NSDate date];
XCTAssertTrue([end timeIntervalSinceDate:start] < 3, @"Should have returned before delay was up");
}
- (void)testDoesNotReinitialiseMockWhenInitIsCalledMoreThanOnce
{
id mock = OCMClassMock([TestClassForInternalTests class]);
OCMStub([mock alloc]).andReturn(mock);
OCMStub([mock title]).andReturn(@"foo");
TestClassForInternalTests *object = [[TestClassForInternalTests alloc] init];
XCTAssertEqualObjects(@"foo", object.title);
}
- (void)testClassArgsAreRetained
{
id mockWithClassMethod = OCMClassMock([TestClassForInternalTests class]);
@autoreleasepool
{
[[mockWithClassMethod stub] doStuffWithClass:[OCMArg any]];
}
XCTAssertNoThrow([mockWithClassMethod doStuffWithClass:[NSString class]]);
}
- (void)testArgumentsGetReleasedAfterStopMocking
{
__weak id weakArgument;
id mock = OCMClassMock([TestClassForInternalTests class]);
@autoreleasepool
{
NSMutableString *title = [NSMutableString new];
weakArgument = title;
[mock setTitle:title];
[mock stopMocking];
}
XCTAssertNil(weakArgument);
}
- (void)testRaisesWhenAttemptingToVerifyInvocationsAfterStopMocking
{
id mock = OCMClassMock([TestClassForInternalTests class]);
[mock title];
[mock stopMocking];
@try
{
[[mock verify] title];
XCTFail(@"Should have thrown an NSInternalInconsistencyException when attempting to verify after stopMocking.");
}
@catch(NSException *ex)
{
XCTAssertEqualObjects(ex.name, NSInternalInconsistencyException);
XCTAssertTrue([ex.reason containsString:[mock description]]);
}
}
- (void)testRaisesWhenAttemptingToUseAfterStopMocking
{
id mock = OCMClassMock([TestClassForInternalTests class]);
[mock stopMocking];
@try
{
[mock title];
XCTFail(@"Should have thrown an NSInternalInconsistencyException when attempting to use after stopMocking.");
}
@catch(NSException *ex)
{
XCTAssertEqualObjects(ex.name, NSInternalInconsistencyException);
XCTAssertTrue([ex.reason containsString:[mock description]]);
}
}
@end