/*
* Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3.0 only,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3.0 along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
#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