/*
* Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This file is part of ObjFW. It may be distributed under the terms of the
* Q Public License 1.0, which can be found in the file LICENSE.QPL included in
* the packaging of this file.
*
* Alternatively, it may be distributed under the terms of the GNU General
* Public License, either version 2 or 3, which can be found in the file
* LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
* file.
*/
#include "config.h"
#import "ObjFW.h"
#import "ObjFWTest.h"
@interface OFBlockTests: OTTestCase
@end
#if defined(OF_OBJFW_RUNTIME)
extern struct objc_class _NSConcreteStackBlock;
extern struct objc_class _NSConcreteGlobalBlock;
extern struct objc_class _NSConcreteMallocBlock;
#elif defined(OF_APPLE_RUNTIME)
extern void *_NSConcreteStackBlock;
extern void *_NSConcreteGlobalBlock;
extern void *_NSConcreteMallocBlock;
#endif
/* Clang on Win32 generates broken code that crashes for global blocks. */
#if !defined(OF_WINDOWS) || !defined(__clang__)
static void (^globalBlock)(void) = ^ {};
#endif
static int
(^returnStackBlock(void))(void)
{
__block int i = 42;
return [Block_copy(^ int { return ++i; }) autorelease];
}
static double
forwardTest(void)
{
__block double d;
void (^block)(void) = Block_copy(^ {
d = 5;
});
block();
Block_release(block);
return d;
}
@implementation OFBlockTests
- (void)testClassOfStackBlock
{
__block int x;
void (^stackBlock)(void) = ^ {
x = 0;
(void)x;
};
OTAssertEqual((Class)&_NSConcreteStackBlock,
objc_getClass("OFStackBlock"));
OTAssertTrue([stackBlock isKindOfClass: [OFBlock class]]);
}
#if !defined(OF_WINDOWS) || !defined(__clang__)
- (void)testClassOfGlobalBlock
{
OTAssertEqual((Class)&_NSConcreteGlobalBlock,
objc_getClass("OFGlobalBlock"));
OTAssertTrue([globalBlock isKindOfClass: [OFBlock class]]);
}
#endif
- (void)testClassOfMallocBlock
{
OTAssertEqual((Class)&_NSConcreteMallocBlock,
objc_getClass("OFMallocBlock"));
}
- (void)testCopyStackBlock
{
__block int x;
void (^stackBlock)(void) = ^ {
x = 0;
(void)x;
};
void (^mallocBlock)(void);
mallocBlock = [[stackBlock copy] autorelease];
OTAssertEqual([mallocBlock class], objc_getClass("OFMallocBlock"));
OTAssertTrue([mallocBlock isKindOfClass: [OFBlock class]]);
}
- (void)testCopyStackBlockAndReferenceVariable
{
OTAssertEqual(forwardTest(), 5);
}
- (void)testCopyStackBlockAndReferenceCopiedVariable
{
int (^voidBlock)(void) = returnStackBlock();
OTAssertEqual(voidBlock(), 43);
OTAssertEqual(voidBlock(), 44);
OTAssertEqual(voidBlock(), 45);
}
#if !defined(OF_WINDOWS) || !defined(__clang__)
- (void)testCopyGlobalBlock
{
OTAssertEqual([[globalBlock copy] autorelease], (id)globalBlock);
}
#endif
- (void)testCopyMallocBlock
{
__block int x;
void (^stackBlock)(void) = ^ {
x = 0;
(void)x;
};
void (^mallocBlock)(void);
mallocBlock = [[stackBlock copy] autorelease];
OTAssertEqual([[mallocBlock copy] autorelease], (id)mallocBlock);
OTAssertEqual([mallocBlock retainCount], 2);
}
@end