/*
* 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"
static void *testKey = &testKey;
@interface RuntimeTestClass: OFObject
{
OFString *_foo, *_bar;
}
@property (nonatomic, copy) OFString *foo;
@property (retain) OFString *bar;
- (id)nilSuperTest;
@end
@interface RuntimeTests: OTTestCase
{
RuntimeTestClass *_test;
}
@end
@interface OFObject (SuperTest)
- (id)superTest;
@end
@implementation RuntimeTests
- (void)setUp
{
[super setUp];
_test = [[RuntimeTestClass alloc] init];
}
- (void)dealloc
{
[_test release];
[super dealloc];
}
- (void)testCallNonExistentMethodViaSuper
{
OTAssertThrowsSpecific([_test superTest], OFNotImplementedException);
}
- (void)testCallMethodViaSuperWithNilSelf
{
OTAssertNil([_test nilSuperTest]);
}
- (void)testPropertyCopyNonatomic
{
OFMutableString *string = [OFMutableString stringWithString: @"foo"];
OFString *foo = @"foo";
_test.foo = string;
OTAssertEqualObjects(_test.foo, foo);
OTAssertNotEqual(_test.foo, foo);
OTAssertEqual(_test.foo.retainCount, 1);
}
- (void)testPropertyRetainAtomic
{
OFMutableString *string = [OFMutableString stringWithString: @"foo"];
_test.bar = string;
OTAssertEqual(_test.bar, string);
OTAssertEqual(string.retainCount, 3);
}
#if defined(OF_OBJFW_RUNTIME) || defined(HAVE_OBJC_SETASSOCIATEDOBJECT)
- (void)testAssociatedObjects
{
objc_setAssociatedObject(self, testKey, _test, OBJC_ASSOCIATION_ASSIGN);
OTAssertEqual(_test.retainCount, 1);
objc_setAssociatedObject(self, testKey, _test, OBJC_ASSOCIATION_RETAIN);
OTAssertEqual(_test.retainCount, 2);
OTAssertEqual(objc_getAssociatedObject(self, testKey), _test);
OTAssertEqual(_test.retainCount, 3);
objc_setAssociatedObject(self, testKey, _test, OBJC_ASSOCIATION_ASSIGN);
OTAssertEqual(_test.retainCount, 2);
objc_setAssociatedObject(self, testKey, _test,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
OTAssertEqual(_test.retainCount, 3);
OTAssertEqual(objc_getAssociatedObject(self, testKey), _test);
OTAssertEqual(_test.retainCount, 3);
objc_removeAssociatedObjects(self);
OTAssertEqual(_test.retainCount, 2);
}
#endif
#ifdef OF_OBJFW_RUNTIME
- (void)testTaggedPointers
{
int classID;
uintmax_t value;
id object;
if (sizeof(uintptr_t) == 8)
value = 0xDEADBEEFDEADBEF;
else if (sizeof(uintptr_t) == 4)
value = 0xDEADBEF;
else
OTAssert(sizeof(uintptr_t) == 8 || sizeof(uintptr_t) == 4);
OTAssertNotEqual(objc_registerTaggedPointerClass([OFString class]), -1);
classID = objc_registerTaggedPointerClass([OFNumber class]);
OTAssertNotEqual(classID, -1);
object = objc_createTaggedPointer(classID, (uintptr_t)value);
OTAssertNotNil(object);
OTAssertEqual(object_getClass(object), [OFNumber class]);
OTAssertEqual([object class], [OFNumber class]);
OTAssertEqual(object_getTaggedPointerValue(object), value);
OTAssertNotNil(objc_createTaggedPointer(classID, UINTPTR_MAX >> 4));
OTAssertNil(objc_createTaggedPointer(classID, (UINTPTR_MAX >> 4) + 1));
}
#endif
@end
@implementation RuntimeTestClass
@synthesize foo = _foo;
@synthesize bar = _bar;
- (void)dealloc
{
[_foo release];
[_bar release];
[super dealloc];
}
- (id)superTest
{
return [super superTest];
}
- (id)nilSuperTest
{
self = nil;
return [self superTest];
}
@end