Add basic NSKeyValueCoding tests

This commit is contained in:
hmelder 2024-09-07 10:35:30 +02:00
parent 3ebcf8aa48
commit ae02ddd3dc
3 changed files with 593 additions and 0 deletions

View file

@ -0,0 +1,66 @@
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSValue.h>
#import <objc/runtime.h>
#import "Testing.h"
// Caching is only available for libobjc2
#if defined(__OBJC2__)
@interface TestClass : NSObject
- (float)floatVal;
@end
@implementation TestClass
- (float)floatVal
{
return 1.0f;
}
@end
static float
getFloatValIMP(id receiver, SEL cmd)
{
return 2.0f;
}
void
testInstallingNewMethodAfterCaching(void)
{
TestClass *obj = [TestClass new];
START_SET("Installing Methods after initial Cache")
// Initial lookups
PASS_EQUAL([obj valueForKey:@"floatVal"], [NSNumber numberWithFloat:1.0f],
"Initial lookup has the correct value");
// Slots are now cached
// Register getFloatVal which should be used if available according to search
// pattern
SEL sel = sel_registerName("getFloatVal");
class_addMethod([TestClass class], sel, (IMP) getFloatValIMP, "f@:");
PASS_EQUAL([obj valueForKey:@"floatVal"], [NSNumber numberWithFloat:2.0f],
"Slot was correctly invalidated");
END_SET("Installing Methods after initial Cache")
[obj release];
}
int
main(int argc, char *argv[])
{
testInstallingNewMethodAfterCaching();
return 0;
}
#else
int
main(int argc, char *argv[])
{
return 0;
}
#endif // defined(__OBJC2__)

View file

@ -0,0 +1,191 @@
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSValue.h>
#import "Testing.h"
// For ivars: _<key>, _is<Key>, <key>, or is<Key>, in that order.
// For methods: get<Key>, <key>, is<Key>, or _<key> in that order.
@interface SearchOrder : NSObject
{
long long _longLong;
long long _isLongLong;
long long longLong;
long long isLongLong;
unsigned char _isUnsignedChar;
unsigned char unsignedChar;
unsigned char isUnsignedChar;
unsigned int unsignedInt;
unsigned int isUnsignedInt;
unsigned long isUnsignedLong;
}
- (instancetype)init;
- (signed char)getChar;
- (signed char)char;
- (signed char)isChar;
- (signed char)_char;
- (int)int;
- (int)isInt;
- (int)_int;
- (short)isShort;
- (short)_short;
- (long)_long;
@end
@implementation SearchOrder
- (instancetype)init
{
self = [super init];
if (self)
{
_longLong = LLONG_MAX;
_isLongLong = LLONG_MAX - 1;
longLong = LLONG_MAX - 2;
isLongLong = LLONG_MAX - 3;
_isUnsignedChar = UCHAR_MAX;
unsignedChar = UCHAR_MAX - 1;
isUnsignedChar = UCHAR_MAX - 2;
unsignedInt = UINT_MAX;
isUnsignedInt = UINT_MAX - 1;
isUnsignedLong = ULONG_MAX;
}
return self;
}
- (signed char)getChar
{
return SCHAR_MAX;
}
- (signed char)char
{
return SCHAR_MAX - 1;
}
- (signed char)isChar
{
return SCHAR_MAX - 2;
}
- (signed char)_char
{
return SCHAR_MAX - 3;
}
- (int)int
{
return INT_MAX;
}
- (int)isInt
{
return INT_MAX - 1;
}
- (int)_int
{
return INT_MAX - 2;
}
- (short)isShort
{
return SHRT_MAX;
}
- (short)_short
{
return SHRT_MAX - 1;
}
- (long)_long
{
return LONG_MAX;
}
@end
@interface SearchOrderNoIvarAccess : NSObject
{
bool _boolVal;
bool _isBoolVal;
bool boolVal;
bool isBoolVal;
}
@end
@implementation SearchOrderNoIvarAccess
+ (BOOL)accessInstanceVariablesDirectly
{
return NO;
}
@end
static void
testSearchOrder(void)
{
SearchOrder *so = [SearchOrder new];
START_SET("Search Order");
PASS_EQUAL([so valueForKey:@"char"], [NSNumber numberWithChar:SCHAR_MAX],
"get<Key> is used when available");
PASS_EQUAL([so valueForKey:@"int"], [NSNumber numberWithInt:INT_MAX],
"<key> is used when get<Key> is not available");
PASS_EQUAL([so valueForKey:@"short"], [NSNumber numberWithShort:SHRT_MAX],
"is<Key> is used when get<Key> and <key> is not available");
PASS_EQUAL(
[so valueForKey:@"long"], [NSNumber numberWithLong:LONG_MAX],
"_<key> is used when get<Key>, <key>, and is<Key> is not available");
PASS_EQUAL(
[so valueForKey:@"longLong"], [NSNumber numberWithLongLong:LLONG_MAX],
"_<key> ivar is used when get<Key>, <key>, and is<Key> is not available");
PASS_EQUAL(
[so valueForKey:@"unsignedChar"],
[NSNumber numberWithUnsignedChar:UCHAR_MAX],
"_is<Key> ivar is used when get<Key>, <key>, and is<Key> is not available");
PASS_EQUAL(
[so valueForKey:@"unsignedInt"], [NSNumber numberWithUnsignedInt:UINT_MAX],
"<key> ivar is used when get<Key>, <key>, and is<Key> is not available");
PASS_EQUAL(
[so valueForKey:@"unsignedLong"],
[NSNumber numberWithUnsignedLong:ULONG_MAX],
"is<Key> ivar is used when get<Key>, <key>, and is<Key> is not available");
END_SET("Search Order");
[so release];
}
static void
testIvarAccess(void)
{
SearchOrderNoIvarAccess *so = [SearchOrderNoIvarAccess new];
START_SET("Search Order Ivar Access");
PASS_EXCEPTION([so valueForKey:@"boolVal"], NSUndefinedKeyException,
"Does not return protected ivar");
END_SET("Search Order Ivar Access");
[so release];
}
int
main(int argc, char *argv[])
{
testSearchOrder();
testIvarAccess();
return 0;
}

336
Tests/base/KVC/types.m Normal file
View file

@ -0,0 +1,336 @@
#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSGeometry.h>
#import <Foundation/NSArray.h>
#include "Testing.h"
/*
* Testing key-value coding on accessors and instance variable
* with all supported types.
*
* Please note that 'Class', `SEL`, unions, and pointer types are
* not coding-compliant on macOS.
*/
typedef struct
{
int x;
float y;
} MyStruct;
@interface ReturnTypes : NSObject
{
signed char _iChar;
int _iInt;
short _iShort;
long _iLong;
long long _iLongLong;
unsigned char _iUnsignedChar;
unsigned int _iUnsignedInt;
unsigned short _iUnsignedShort;
unsigned long _iUnsignedLong;
unsigned long long _iUnsignedLongLong;
float _iFloat;
double _iDouble;
bool _iBool;
// Not coding-compliant on macOS
// const char *_iCharPtr;
// int *_iIntPtr;
// Class _iCls;
// void *_iUnknownType; // Type encoding: ?
// MyUnion _iMyUnion;
id _iId;
NSPoint _iNSPoint;
NSRange _iNSRange;
NSRect _iNSRect;
NSSize _iNSSize;
MyStruct _iMyStruct;
}
- (instancetype)init;
- (signed char)mChar; // Type encoding: c
- (int)mInt; // Type encoding: i
- (short)mShort; // Type encoding: s
- (long)mLong; // Type encoding: l
- (long long)mLongLong; // Type encoding: q
- (unsigned char)mUnsignedChar; // Type encoding: C
- (unsigned int)mUnsignedInt; // Type encoding: I
- (unsigned short)mUnsignedShort; // Type encoding: S
- (unsigned long)mUnsignedLong; // Type encoding: L
- (unsigned long long)mUnsignedLongLong; // Type encoding: Q
- (float)mFloat; // Type encoding: f
- (double)mDouble; // Type encoding: d
- (bool)mBool; // Type encoding: B
- (id)mId; // Type encoding: @
- (NSPoint)mNSPoint;
- (NSRange)mNSRange;
- (NSRect)mNSRect;
- (NSSize)mNSSize;
- (MyStruct)mMyStruct;
@end
@implementation ReturnTypes
- (instancetype)init
{
self = [super init];
if (self)
{
MyStruct my = {.x = 42, .y = 3.14f};
_iChar = SCHAR_MIN;
_iShort = SHRT_MIN;
_iInt = INT_MIN;
_iLong = LONG_MIN;
_iUnsignedChar = 0;
_iUnsignedInt = 0;
_iUnsignedShort = 0;
_iUnsignedLong = 0;
_iUnsignedLongLong = 0;
_iFloat = 123.4f;
_iDouble = 123.45678;
_iBool = true;
_iId = @"id";
_iNSPoint = NSMakePoint(1.0, 2.0);
_iNSRange = NSMakeRange(1, 2);
_iNSRect = NSMakeRect(1.0, 2.0, 3.0, 4.0);
_iNSSize = NSMakeSize(1.0, 2.0);
_iMyStruct = my;
}
return self;
}
- (void)mVoid
{}
- (signed char)mChar
{
return SCHAR_MAX;
}
- (short)mShort
{
return SHRT_MAX;
}
- (int)mInt
{
return INT_MAX;
}
- (long)mLong
{
return LONG_MAX;
}
- (long long)mLongLong
{
return LLONG_MAX;
}
- (unsigned char)mUnsignedChar
{
return UCHAR_MAX;
}
- (unsigned int)mUnsignedInt
{
return UINT_MAX;
}
- (unsigned short)mUnsignedShort
{
return USHRT_MAX;
}
- (unsigned long)mUnsignedLong
{
return ULONG_MAX;
}
- (unsigned long long)mUnsignedLongLong
{
return ULLONG_MAX;
}
- (float)mFloat
{
return 123.45f;
}
- (double)mDouble
{
return 123.456789;
}
- (bool)mBool
{
return true;
}
- (id)mId
{
return @"id";
}
- (NSPoint)mNSPoint
{
return NSMakePoint(1.0, 2.0);
}
- (NSRange)mNSRange
{
return NSMakeRange(1, 2);
}
- (NSRect)mNSRect
{
return NSMakeRect(1.0, 2.0, 3.0, 4.0);
}
- (NSSize)mNSSize
{
return NSMakeSize(1.0, 2.0);
}
- (MyStruct)mMyStruct
{
MyStruct s = {.x = 1, .y = 2.0};
return s;
}
@end
static void
testAccessors(void)
{
ReturnTypes *rt = [ReturnTypes new];
NSPoint p = NSMakePoint(1.0, 2.0);
NSRange r = NSMakeRange(1, 2);
NSRect re = NSMakeRect(1.0, 2.0, 3.0, 4.0);
NSSize s = NSMakeSize(1.0, 2.0);
MyStruct ms = {.x = 1, .y = 2.0};
START_SET("Accessors");
PASS_EQUAL([rt valueForKey:@"mChar"], [NSNumber numberWithChar:SCHAR_MAX],
"Accessor returns char");
PASS_EQUAL([rt valueForKey:@"mInt"], [NSNumber numberWithInt:INT_MAX],
"Accessor returns int");
PASS_EQUAL([rt valueForKey:@"mShort"], [NSNumber numberWithShort:SHRT_MAX],
"Accessor returns short");
PASS_EQUAL([rt valueForKey:@"mLong"], [NSNumber numberWithLong:LONG_MAX],
"Accessor returns long");
PASS_EQUAL([rt valueForKey:@"mLongLong"],
[NSNumber numberWithLongLong:LLONG_MAX],
"Accessor returns long long");
PASS_EQUAL([rt valueForKey:@"mUnsignedChar"],
[NSNumber numberWithUnsignedChar:UCHAR_MAX],
"Accessor returns unsigned char");
PASS_EQUAL([rt valueForKey:@"mUnsignedInt"],
[NSNumber numberWithUnsignedInt:UINT_MAX],
"Accessor returns unsigned int");
PASS_EQUAL([rt valueForKey:@"mUnsignedShort"],
[NSNumber numberWithUnsignedShort:USHRT_MAX],
"Accessor returns unsigned short");
PASS_EQUAL([rt valueForKey:@"mUnsignedLong"],
[NSNumber numberWithUnsignedLong:ULONG_MAX],
"Accessor returns unsigned long");
PASS_EQUAL([rt valueForKey:@"mUnsignedLongLong"],
[NSNumber numberWithUnsignedLongLong:ULLONG_MAX],
"Accessor returns unsigned long long");
PASS_EQUAL([rt valueForKey:@"mFloat"], [NSNumber numberWithFloat:123.45f],
"Accessor returns float");
PASS_EQUAL([rt valueForKey:@"mDouble"],
[NSNumber numberWithDouble:123.456789], "Accessor returns double");
PASS_EQUAL([rt valueForKey:@"mBool"], [NSNumber numberWithBool:true],
"Accessor returns bool");
PASS_EQUAL([rt valueForKey:@"mId"], @"id", "Accessor returns id");
PASS_EQUAL([rt valueForKey:@"mNSPoint"], [NSValue valueWithPoint:p],
"Accessor returns NSPoint");
PASS_EQUAL([rt valueForKey:@"mNSRange"], [NSValue valueWithRange:r],
"Accessor returns NSRange");
PASS_EQUAL([rt valueForKey:@"mNSRect"], [NSValue valueWithRect:re],
"Accessor returns NSRect");
PASS_EQUAL([rt valueForKey:@"mNSSize"], [NSValue valueWithSize:s],
"Accessor returns NSSize");
PASS_EQUAL([rt valueForKey:@"mMyStruct"],
[NSValue valueWithBytes:&ms objCType:@encode(MyStruct)],
"Accessor returns MyStruct");
END_SET("Accessors");
[rt release];
}
static void
testIvars(void)
{
ReturnTypes *rt = [ReturnTypes new];
NSPoint p = NSMakePoint(1.0, 2.0);
NSRange r = NSMakeRange(1, 2);
NSRect re = NSMakeRect(1.0, 2.0, 3.0, 4.0);
NSSize s = NSMakeSize(1.0, 2.0);
MyStruct ms = {.x = 42, .y = 3.14f};
START_SET("Ivars");
PASS_EQUAL([rt valueForKey:@"iChar"], [NSNumber numberWithChar:SCHAR_MIN],
"Ivar returns char");
PASS_EQUAL([rt valueForKey:@"iInt"], [NSNumber numberWithInt:INT_MIN],
"Ivar returns int");
PASS_EQUAL([rt valueForKey:@"iShort"], [NSNumber numberWithShort:SHRT_MIN],
"Ivar returns short");
PASS_EQUAL([rt valueForKey:@"iLong"], [NSNumber numberWithLong:LONG_MIN],
"Ivar returns long");
PASS_EQUAL([rt valueForKey:@"iUnsignedChar"],
[NSNumber numberWithUnsignedChar:0], "Ivar returns unsigned char");
PASS_EQUAL([rt valueForKey:@"iUnsignedInt"],
[NSNumber numberWithUnsignedInt:0], "Ivar returns unsigned int");
PASS_EQUAL([rt valueForKey:@"iUnsignedShort"],
[NSNumber numberWithUnsignedShort:0],
"Ivar returns unsigned short");
PASS_EQUAL([rt valueForKey:@"iUnsignedLong"],
[NSNumber numberWithUnsignedLong:0], "Ivar returns unsigned long");
PASS_EQUAL([rt valueForKey:@"iUnsignedLongLong"],
[NSNumber numberWithUnsignedLongLong:0],
"Ivar returns unsigned long long");
PASS_EQUAL([rt valueForKey:@"iFloat"], [NSNumber numberWithFloat:123.4f],
"Ivar returns float");
PASS_EQUAL([rt valueForKey:@"iDouble"], [NSNumber numberWithDouble:123.45678],
"Ivar returns double");
PASS_EQUAL([rt valueForKey:@"iBool"], [NSNumber numberWithBool:true],
"Ivar returns bool");
PASS_EQUAL([rt valueForKey:@"iId"], @"id", "Ivar returns id");
PASS_EQUAL([rt valueForKey:@"iNSPoint"], [NSValue valueWithPoint:p],
"Ivar returns NSPoint");
PASS_EQUAL([rt valueForKey:@"iNSRange"], [NSValue valueWithRange:r],
"Ivar returns NSRange");
PASS_EQUAL([rt valueForKey:@"iNSRect"], [NSValue valueWithRect:re],
"Ivar returns NSRect");
PASS_EQUAL([rt valueForKey:@"iNSSize"], [NSValue valueWithSize:s],
"Ivar returns NSSize");
PASS_EQUAL([rt valueForKey:@"iMyStruct"],
[NSValue valueWithBytes:&ms objCType:@encode(MyStruct)],
"Ivar returns MyStruct");
END_SET("Ivars");
[rt release];
}
int
main(int argc, char *argv[])
{
testAccessors();
testIvars();
return 0;
}