blob: c8ff165710d63aadd64d9dd1978ff5682ad0f3fd [file] [log] [blame]
/*
* Copyright (c) 2013-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 "NSMethodSignature+OCMAdditions.h"
#if TARGET_OS_IPHONE
#define NSPoint CGPoint
#define NSSize CGSize
#define NSRect CGRect
#endif
@interface NSMethodSignatureOCMAdditionsTests : XCTestCase
@end
@implementation NSMethodSignatureOCMAdditionsTests
#ifndef __arm64__
// Special structure return not really needed on arm64. And we should remove arm and i386 at some point...
- (void)testDeterminesThatSpecialReturnIsNotNeededForNonStruct
{
const char *types = "i";
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:types];
XCTAssertFalse([sig usesSpecialStructureReturn], @"Should have determined no need for special (stret) return.");
}
- (void)testDeterminesThatSpecialReturnIsNeededForLargeStruct
{
// This type should(!) require special returns for all architectures
const char *types = "{CATransform3D=ffffffffffffffff}";
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:types];
XCTAssertTrue([sig usesSpecialStructureReturn], @"Should have determined need for special (stret) return.");
}
- (void)testArchDependentSpecialReturns
{
#define ASSERT_ENC(expected, enctype) do {\
BOOL useSpecial = expected; \
XCTAssertNoThrow(useSpecial = [[NSMethodSignature signatureWithObjCTypes:enctype] usesSpecialStructureReturn], \
@"NSMethodSignature failed for type '%s'", enctype); \
XCTAssertEqual((int)useSpecial, (int)expected,\
@"Special (stret) return incorrect for type '%s'", enctype); \
} while (0)
#define ASSERT_TYPE(expected, type) ASSERT_ENC(expected, @encode(type))
#if __x86_64__
ASSERT_TYPE(YES, NSRect);
ASSERT_TYPE(NO, NSPoint);
ASSERT_TYPE(NO, NSRange);
ASSERT_ENC(NO, "{foo=ffff}");
ASSERT_ENC(YES, "{foo=fffff}");
ASSERT_ENC(YES, "{foo=D}");
ASSERT_ENC(NO, "{foo=t}");
ASSERT_ENC(YES, "{foo=TT}");
ASSERT_TYPE(NO, __int128_t);
ASSERT_TYPE(NO, long double);
ASSERT_ENC(YES, "{nlist_64=(?=I)CCSQ}16@0:8");
#endif
#if __i386__
ASSERT_TYPE(YES, NSRect);
ASSERT_TYPE(NO, NSPoint);
ASSERT_TYPE(NO, NSRange);
ASSERT_TYPE(NO, long double);
ASSERT_ENC(NO, "{foo=ff}");
ASSERT_ENC(YES, "{foo=fff}");
ASSERT_ENC(NO, "{foo=c}");
ASSERT_ENC(NO, "{foo=cc}");
ASSERT_ENC(YES, "{foo=ccc}");
ASSERT_ENC(NO, "{foo=cccc}");
ASSERT_ENC(YES, "{foo=cccccc}");
ASSERT_ENC(NO, "{foo=cccccccc}");
ASSERT_ENC(YES, "{foo=D}");
#endif
#if __arm__
ASSERT_TYPE(YES, NSRect);
ASSERT_TYPE(YES, NSPoint);
ASSERT_TYPE(YES, NSRange);
ASSERT_ENC(NO, "{foo=f}");
ASSERT_ENC(YES, "{foo=ff}");
ASSERT_ENC(NO, "{foo=c}");
ASSERT_ENC(NO, "{foo=cc}");
ASSERT_ENC(NO, "{foo=ccc}");
ASSERT_ENC(NO, "{foo=cccc}");
ASSERT_ENC(YES, "{foo=ccccc}");
#endif
}
#endif
- (void)testNSMethodSignatureDebugDescriptionWorksTheWayWeExpectIt
{
const char *types = "{CATransform3D=ffffffffffffffff}";
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:types];
NSString *debugDescription = [sig debugDescription];
NSRange stretYESRange = [debugDescription rangeOfString:@"is special struct return? YES"];
NSRange stretNORange = [debugDescription rangeOfString:@"is special struct return? NO"];
XCTAssertTrue(stretYESRange.length > 0 || stretNORange.length > 0, @"NSMethodSignature debugDescription has changed; need to change OCPartialMockObject impl");
}
- (void)testCreatesCorrectSignatureForBlockWithNoArgsAndVoidReturn
{
void (^block)(void) = ^() { };
NSMethodSignature *sig = [NSMethodSignature signatureForBlock:block];
XCTAssertNotNil(sig, @"Should have created signature");
NSString *actual = [NSString stringWithCString:[sig methodReturnType] encoding:NSASCIIStringEncoding];
XCTAssertEqualObjects(@"v", actual, @"Should have created signature with correct return type");
// i am not completely sure why this has one argument; the actual type string is "v8@?0"
XCTAssertEqual(1, [sig numberOfArguments], @"Should have created signature with correct number of arguments");
}
- (void)testCreatesCorrectSignatureForBlockWithSomeArgsAndVoidReturn
{
void (^block)(NSString *, BOOL *) = ^(NSString *line, BOOL *stop) { };
NSMethodSignature *sig = [NSMethodSignature signatureForBlock:block];
XCTAssertNotNil(sig, @"Should have created signature");
NSString *actual = [NSString stringWithCString:[sig methodReturnType] encoding:NSASCIIStringEncoding];
XCTAssertEqualObjects(@"v", actual, @"Should have created signature with correct return type");
// see comment in testCreatesCorrectSignatureForBlockWithNoArgsAndVoidReturn for discussion of extra argument
XCTAssertEqual(3, [sig numberOfArguments], @"Should have created signature with correct number of arguments");
actual = [NSString stringWithCString:[sig getArgumentTypeAtIndex:1] encoding:NSASCIIStringEncoding];
// seems to add the name of the class in quotes after the type
XCTAssertEqualObjects(@"@", [actual substringToIndex:1], @"Should have created signature with correct type of second argument");
XCTAssertTrue(strcmp(@encode(BOOL *), [sig getArgumentTypeAtIndex:2]) == 0, @"Should have created signature with correct type of second argument");
}
- (void)testCreatesCorrectSignatureForBlockWithBoolReturn
{
BOOL (^block)(void) = ^() {
return NO;
};
NSMethodSignature *sig = [NSMethodSignature signatureForBlock:block];
XCTAssertNotNil(sig, @"Should have created signature");
XCTAssertTrue(strcmp(@encode(BOOL), [sig methodReturnType]) == 0, @"Should have created signature with correct return type");
}
@end