/*
* 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 MyObject: OFObject
{
id _objectValue;
Class _classValue;
bool _boolValue;
char _charValue;
short _shortValue;
int _intValue;
long _longValue;
long long _longLongValue;
unsigned char _unsignedCharValue;
unsigned short _unsignedShortValue;
unsigned int _unsignedIntValue;
unsigned long _unsignedLongValue;
unsigned long long _unsignedLongLongValue;
float _floatValue;
double _doubleValue;
}
@property (nonatomic, retain) id objectValue;
@property (nonatomic) Class classValue;
@property (nonatomic, getter=isBoolValue) bool boolValue;
@property (nonatomic) char charValue;
@property (nonatomic) short shortValue;
@property (nonatomic) int intValue;
@property (nonatomic) long longValue;
@property (nonatomic) long long longLongValue;
@property (nonatomic) unsigned char unsignedCharValue;
@property (nonatomic) unsigned short unsignedShortValue;
@property (nonatomic) unsigned int unsignedIntValue;
@property (nonatomic) unsigned long unsignedLongValue;
@property (nonatomic) unsigned long long unsignedLongLongValue;
@property (nonatomic) float floatValue;
@property (nonatomic) double doubleValue;
@end
@interface OFObjectTests: OTTestCase
{
MyObject *_myObject;
}
@end
@implementation OFObjectTests
- (void)setUp
{
[super setUp];
_myObject = [[MyObject alloc] init];
}
- (void)dealloc
{
[_myObject release];
[super dealloc];
}
- (void)testClassDescription
{
OTAssertEqualObjects([OFObject description], @"OFObject");
OTAssertEqualObjects([MyObject description], @"MyObject");
}
- (void)testInstanceDescription
{
OFObject *object = [[[OFObject alloc] init] autorelease];
OTAssertEqualObjects(object.description, @"<OFObject>");
OTAssertEqualObjects(_myObject.description, @"<MyObject>");
}
- (void)testValueForKey
{
_myObject.objectValue = @"Hello";
_myObject.classValue = _myObject.class;
OTAssertEqualObjects([_myObject valueForKey: @"objectValue"], @"Hello");
OTAssertEqualObjects([_myObject valueForKey: @"classValue"],
_myObject.class);
OTAssertEqualObjects([_myObject valueForKey: @"class"],
_myObject.class);
}
- (void)testValueForKeyWithUndefinedKeyThrows
{
OTAssertThrowsSpecific([_myObject valueForKey: @"undefined"],
OFUndefinedKeyException);
}
- (void)testSetValueForKey
{
[_myObject setValue: @"World" forKey: @"objectValue"];
[_myObject setValue: [OFObject class] forKey: @"classValue"];
OTAssertEqualObjects(_myObject.objectValue, @"World");
OTAssertEqualObjects(_myObject.classValue, [OFObject class]);
}
- (void)testSetValueWithUndefinedKeyThrows
{
OTAssertThrowsSpecific([_myObject setValue: @"x" forKey: @"undefined"],
OFUndefinedKeyException);
}
- (void)testAutoWrappingOfValueForKey
{
_myObject.boolValue = 1;
_myObject.charValue = 2;
_myObject.shortValue = 3;
_myObject.intValue = 4;
_myObject.longValue = 5;
_myObject.longLongValue = 6;
_myObject.unsignedCharValue = 7;
_myObject.unsignedShortValue = 8;
_myObject.unsignedIntValue = 9;
_myObject.unsignedLongValue = 10;
_myObject.unsignedLongLongValue = 11;
_myObject.floatValue = 12;
_myObject.doubleValue = 13;
OTAssertEqualObjects([_myObject valueForKey: @"boolValue"],
[OFNumber numberWithBool: 1]);
OTAssertEqualObjects([_myObject valueForKey: @"charValue"],
[OFNumber numberWithChar: 2]);
OTAssertEqualObjects([_myObject valueForKey: @"shortValue"],
[OFNumber numberWithShort: 3]);
OTAssertEqualObjects([_myObject valueForKey: @"intValue"],
[OFNumber numberWithInt: 4]);
OTAssertEqualObjects([_myObject valueForKey: @"longValue"],
[OFNumber numberWithLong: 5]);
OTAssertEqualObjects([_myObject valueForKey: @"longLongValue"],
[OFNumber numberWithLongLong: 6]);
OTAssertEqualObjects([_myObject valueForKey: @"unsignedCharValue"],
[OFNumber numberWithUnsignedChar: 7]);
OTAssertEqualObjects([_myObject valueForKey: @"unsignedShortValue"],
[OFNumber numberWithUnsignedShort: 8]);
OTAssertEqualObjects([_myObject valueForKey: @"unsignedIntValue"],
[OFNumber numberWithUnsignedInt: 9]);
OTAssertEqualObjects([_myObject valueForKey: @"unsignedLongValue"],
[OFNumber numberWithUnsignedLong: 10]);
OTAssertEqualObjects([_myObject valueForKey: @"unsignedLongLongValue"],
[OFNumber numberWithUnsignedLongLong: 11]);
OTAssertEqualObjects([_myObject valueForKey: @"floatValue"],
[OFNumber numberWithFloat: 12]);
OTAssertEqualObjects([_myObject valueForKey: @"doubleValue"],
[OFNumber numberWithDouble: 13]);
}
- (void)testAutoWrappingOfSetValueForKey
{
[_myObject setValue: [OFNumber numberWithBool: 0]
forKey: @"boolValue"];
[_myObject setValue: [OFNumber numberWithChar: 10]
forKey: @"charValue"];
[_myObject setValue: [OFNumber numberWithShort: 20]
forKey: @"shortValue"];
[_myObject setValue: [OFNumber numberWithInt: 30]
forKey: @"intValue"];
[_myObject setValue: [OFNumber numberWithLong: 40]
forKey: @"longValue"];
[_myObject setValue: [OFNumber numberWithLongLong: 50]
forKey: @"longLongValue"];
[_myObject setValue: [OFNumber numberWithUnsignedChar: 60]
forKey: @"unsignedCharValue"];
[_myObject setValue: [OFNumber numberWithUnsignedShort: 70]
forKey: @"unsignedShortValue"];
[_myObject setValue: [OFNumber numberWithUnsignedInt: 80]
forKey: @"unsignedIntValue"];
[_myObject setValue: [OFNumber numberWithUnsignedLong: 90]
forKey: @"unsignedLongValue"];
[_myObject setValue: [OFNumber numberWithUnsignedLongLong: 100]
forKey: @"unsignedLongLongValue"];
[_myObject setValue: [OFNumber numberWithFloat: 110]
forKey: @"floatValue"];
[_myObject setValue: [OFNumber numberWithDouble: 120]
forKey: @"doubleValue"];
OTAssertEqual(_myObject.isBoolValue, 0);
OTAssertEqual(_myObject.charValue, 10);
OTAssertEqual(_myObject.shortValue, 20);
OTAssertEqual(_myObject.intValue, 30);
OTAssertEqual(_myObject.longValue, 40);
OTAssertEqual(_myObject.longLongValue, 50);
OTAssertEqual(_myObject.unsignedCharValue, 60);
OTAssertEqual(_myObject.unsignedShortValue, 70);
OTAssertEqual(_myObject.unsignedIntValue, 80);
OTAssertEqual(_myObject.unsignedLongValue, 90);
OTAssertEqual(_myObject.unsignedLongLongValue, 100);
OTAssertEqual(_myObject.floatValue, 110);
OTAssertEqual(_myObject.doubleValue, 120);
}
- (void)testSetValueForKeyWithNilThrows
{
OTAssertThrowsSpecific(
[_myObject setValue: (id _Nonnull)nil forKey: @"intValue"],
OFInvalidArgumentException);
}
- (void)testValueForKeyPath
{
_myObject.objectValue = [[[MyObject alloc] init] autorelease];
[_myObject.objectValue setObjectValue:
[[[MyObject alloc] init] autorelease]];
[[_myObject.objectValue objectValue] setDoubleValue: 0.5];
OTAssertEqual([[_myObject valueForKeyPath:
@"objectValue.objectValue.doubleValue"] doubleValue], 0.5);
}
- (void)testSetValueForKeyPath
{
_myObject.objectValue = [[[MyObject alloc] init] autorelease];
[_myObject.objectValue setObjectValue:
[[[MyObject alloc] init] autorelease]];
[_myObject setValue: [OFNumber numberWithDouble: 0.75]
forKeyPath: @"objectValue.objectValue.doubleValue"];
OTAssertEqual([[_myObject.objectValue objectValue] doubleValue], 0.75);
}
@end
@implementation MyObject
@synthesize objectValue = _objectValue, classValue = _classValue;
@synthesize boolValue = _boolValue, charValue = _charValue;
@synthesize shortValue = _shortValue, intValue = _intValue;
@synthesize longValue = _longValue, longLongValue = _longLongValue;
@synthesize unsignedCharValue = _unsignedCharValue;
@synthesize unsignedShortValue = _unsignedShortValue;
@synthesize unsignedIntValue = _unsignedIntValue;
@synthesize unsignedLongValue = _unsignedLongValue;
@synthesize unsignedLongLongValue = _unsignedLongLongValue;
@synthesize floatValue = _floatValue, doubleValue = _doubleValue;
- (void)dealloc
{
[_objectValue release];
[super dealloc];
}
@end