/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
* 2018, 2019
* Jonathan Schleifer <js@heap.zone>
*
* 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 "TestsAppDelegate.h"
#if (defined(OF_DRAGONFLYBSD) && defined(__LP64__)) || defined(OF_NINTENDO_3DS)
# define TOO_BIG (SIZE_MAX / 3)
#else
# define TOO_BIG (SIZE_MAX - 128)
#endif
static OFString *module = @"OFObject";
@interface MyObj: 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
@implementation MyObj
@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
@implementation TestsAppDelegate (OFObjectTests)
- (void)objectTests
{
void *pool = objc_autoreleasePoolPush();
OFObject *obj = [[[OFObject alloc] init] autorelease];
void *p, *q, *r;
OFObject *o;
MyObj *m;
char *tmp;
TEST(@"Allocating 4096 bytes",
(p = [obj allocMemoryWithSize: 4096]) != NULL)
TEST(@"Freeing memory", R([obj freeMemory: p]))
TEST(@"Allocating and freeing 4096 bytes 3 times",
(p = [obj allocMemoryWithSize: 4096]) != NULL &&
(q = [obj allocMemoryWithSize: 4096]) != NULL &&
(r = [obj allocMemoryWithSize: 4096]) != NULL &&
R([obj freeMemory: p]) && R([obj freeMemory: q]) &&
R([obj freeMemory: r]))
tmp = [self allocMemoryWithSize: 1024];
EXPECT_EXCEPTION(@"Detect freeing of memory not allocated by object",
OFMemoryNotPartOfObjectException, [obj freeMemory: tmp])
EXPECT_EXCEPTION(@"Detect out of memory on alloc",
OFOutOfMemoryException, tmp = [obj allocMemoryWithSize: TOO_BIG])
EXPECT_EXCEPTION(@"Detect out of memory on resize",
OFOutOfMemoryException,
{
p = [obj allocMemoryWithSize: 1];
p = [obj resizeMemory: p
size: TOO_BIG];
})
[obj freeMemory: p];
TEST(@"Allocate when trying to resize NULL",
(p = [obj resizeMemory: NULL
size: 1024]) != NULL)
[obj freeMemory: p];
EXPECT_EXCEPTION(@"Detect resizing of memory not allocated by object",
OFMemoryNotPartOfObjectException, tmp = [obj resizeMemory: tmp
size: 2048])
[self freeMemory: tmp];
TEST(@"+[description]",
[[OFObject description] isEqual: @"OFObject"] &&
[[MyObj description] isEqual: @"MyObj"])
o = [[[OFObject alloc] init] autorelease];
m = [[[MyObj alloc] init] autorelease];
TEST(@"-[description]",
[o.description isEqual: @"<OFObject>"] &&
[m.description isEqual: @"<MyObj>"])
m.objectValue = @"Hello";
m.classValue = [m class];
TEST(@"-[valueForKey:]",
[[m valueForKey: @"objectValue"] isEqual: @"Hello"] &&
[[m valueForKey: @"classValue"] isEqual: m.class] &&
[[m valueForKey: @"class"] isEqual: m.class])
EXPECT_EXCEPTION(@"-[valueForKey:] with undefined key",
OFUndefinedKeyException, [m valueForKey: @"undefined"])
TEST(@"-[setValue:forKey:]",
R([m setValue: @"World"
forKey: @"objectValue"]) &&
R([m setValue: [OFObject class]
forKey: @"classValue"]) &&
[m.objectValue isEqual: @"World"] &&
[m.classValue isEqual: [OFObject class]])
EXPECT_EXCEPTION(@"-[setValue:forKey:] with undefined key",
OFUndefinedKeyException, [m setValue: @"x"
forKey: @"undefined"])
m.boolValue = 1;
m.charValue = 2;
m.shortValue = 3;
m.intValue = 4;
m.longValue = 5;
m.longLongValue = 6;
m.unsignedCharValue = 7;
m.unsignedShortValue = 8;
m.unsignedIntValue = 9;
m.unsignedLongValue = 10;
m.unsignedLongLongValue = 11;
m.floatValue = 12;
m.doubleValue = 13;
TEST(@"Auto-wrapping of -[valueForKey:]",
[[m valueForKey: @"boolValue"] isEqual:
[OFNumber numberWithBool: 1]] &&
[[m valueForKey: @"charValue"] isEqual:
[OFNumber numberWithChar: 2]] &&
[[m valueForKey: @"shortValue"] isEqual:
[OFNumber numberWithShort: 3]] &&
[[m valueForKey: @"intValue"] isEqual:
[OFNumber numberWithInt: 4]] &&
[[m valueForKey: @"longValue"] isEqual:
[OFNumber numberWithLong: 5]] &&
[[m valueForKey: @"longLongValue"] isEqual:
[OFNumber numberWithLongLong: 6]] &&
[[m valueForKey: @"unsignedCharValue"] isEqual:
[OFNumber numberWithUnsignedChar: 7]] &&
[[m valueForKey: @"unsignedShortValue"] isEqual:
[OFNumber numberWithUnsignedShort: 8]] &&
[[m valueForKey: @"unsignedIntValue"] isEqual:
[OFNumber numberWithUnsignedInt: 9]] &&
[[m valueForKey: @"unsignedLongValue"] isEqual:
[OFNumber numberWithUnsignedLong: 10]] &&
[[m valueForKey: @"unsignedLongLongValue"] isEqual:
[OFNumber numberWithUnsignedLongLong: 11]] &&
[[m valueForKey: @"floatValue"] isEqual:
[OFNumber numberWithFloat: 12]] &&
[[m valueForKey: @"doubleValue"] isEqual:
[OFNumber numberWithDouble: 13]])
TEST(@"Auto-wrapping of -[setValue:forKey:]",
R([m setValue: [OFNumber numberWithBool: 0]
forKey: @"boolValue"]) &&
R([m setValue: [OFNumber numberWithChar: 10]
forKey: @"charValue"]) &&
R([m setValue: [OFNumber numberWithShort: 20]
forKey: @"shortValue"]) &&
R([m setValue: [OFNumber numberWithInt: 30]
forKey: @"intValue"]) &&
R([m setValue: [OFNumber numberWithLong: 40]
forKey: @"longValue"]) &&
R([m setValue: [OFNumber numberWithLongLong: 50]
forKey: @"longLongValue"]) &&
R([m setValue: [OFNumber numberWithUnsignedChar: 60]
forKey: @"unsignedCharValue"]) &&
R([m setValue: [OFNumber numberWithUnsignedShort: 70]
forKey: @"unsignedShortValue"]) &&
R([m setValue: [OFNumber numberWithUnsignedInt: 80]
forKey: @"unsignedIntValue"]) &&
R([m setValue: [OFNumber numberWithUnsignedLong: 90]
forKey: @"unsignedLongValue"]) &&
R([m setValue: [OFNumber numberWithUnsignedLongLong: 100]
forKey: @"unsignedLongLongValue"]) &&
R([m setValue: [OFNumber numberWithFloat: 110]
forKey: @"floatValue"]) &&
R([m setValue: [OFNumber numberWithDouble: 120]
forKey: @"doubleValue"]) &&
m.isBoolValue == 0 && m.charValue == 10 && m.shortValue == 20 &&
m.intValue == 30 && m.longValue == 40 && m.longLongValue == 50 &&
m.unsignedCharValue == 60 && m.unsignedShortValue == 70 &&
m.unsignedIntValue == 80 && m.unsignedLongValue == 90 &&
m.unsignedLongLongValue == 100 && m.floatValue == 110 &&
m.doubleValue == 120)
EXPECT_EXCEPTION(@"Catch -[setValue:forKey:] with nil key for scalar",
OFInvalidArgumentException, [m setValue: (id _Nonnull)nil
forKey: @"intValue"])
TEST(@"-[valueForKeyPath:]",
(m = [[[MyObj alloc] init] autorelease]) &&
(m.objectValue = [[[MyObj alloc] init] autorelease]) &&
R([m.objectValue
setObjectValue: [[[MyObj alloc] init] autorelease]]) &&
R([[m.objectValue objectValue] setDoubleValue: 0.5]) &&
[[m valueForKeyPath: @"objectValue.objectValue.doubleValue"]
doubleValue] == 0.5)
TEST(@"[-setValue:forKeyPath:]",
R([m setValue: [OFNumber numberWithDouble: 0.75]
forKeyPath: @"objectValue.objectValue.doubleValue"]) &&
[[m.objectValue objectValue] doubleValue] == 0.75)
objc_autoreleasePoolPop(pool);
}
@end