mirror of
https://github.com/gnustep/tools-make.git
synced 2025-04-26 15:40:58 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/tools/make/trunk@32268 72102866-910b-0410-8b05-ffd578937521
426 lines
15 KiB
Objective-C
426 lines
15 KiB
Objective-C
/* ObjectTesting - Include basic object tests for the GNUstep Testsuite
|
|
|
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
|
|
|
Written by: Matt Rice?
|
|
|
|
This package is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
General Public License for more details.
|
|
|
|
*/
|
|
#import <Testing.h>
|
|
#import <Foundation/NSArray.h>
|
|
#import <Foundation/NSDictionary.h>
|
|
#import <Foundation/NSData.h>
|
|
#import <Foundation/NSArchiver.h>
|
|
#import <Foundation/NSKeyedArchiver.h>
|
|
|
|
/* WARNING ...
|
|
*
|
|
* You should look in Testing.h for the standard Test Framework API
|
|
* and its documentation (along with the README file).
|
|
*
|
|
* You should look in the example tests in the TestFramework subdirectory
|
|
* of the gnustep-make package to see how to use the API.
|
|
*
|
|
* This file contains old code from the earlier days of the testsuite
|
|
* and while a lot of it is useful stuff, it's not an example of how
|
|
* best to use the current API.
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Quick test to check that we have the class we expect.
|
|
*/
|
|
#define TEST_FOR_CLASS(aClassName, aClass, TestDescription) \
|
|
pass([aClass isKindOfClass: NSClassFromString(aClassName)], TestDescription)
|
|
|
|
/* Quick test to check for a non-empty string in the case where we don't
|
|
* actually know what value we should be expecting.
|
|
*/
|
|
#define TEST_STRING(code, description) \
|
|
{ \
|
|
NSString *_testString = code; \
|
|
pass(_testString != nil \
|
|
&& [_testString isKindOfClass: [NSString class]] \
|
|
&& [_testString length], description); \
|
|
}
|
|
|
|
/* DEPRECATED
|
|
* This is for backward compatibility, the original havng been replaced
|
|
* by two clearer/simpler macros.
|
|
* Please use PASS_EXCEPTION() for a test which is supposed to raise,
|
|
* or PASS_RUNS() to test that code runs without raising an exception.
|
|
*/
|
|
#define TEST_EXCEPTION(code, exceptionName, shouldRaise, description) \
|
|
if (shouldRaise) { PASS_EXCEPTION(code, exceptionName, description) } \
|
|
else { PASS_RUNS(code, description) }
|
|
|
|
/* DEPRECATED
|
|
START_TEST/END_TEST can be used if the code being tested could raise
|
|
and the exception should be considered a test failure. The exception
|
|
is not reraised to allow subsequent tests to execute. The START_TEST
|
|
macro takes an argument which will skip the test as Skipped if it
|
|
evaluates to 0, allowing runtime control of whether the code block
|
|
should be executed. */
|
|
#define START_TEST(supported) if ((supported)) { NS_DURING
|
|
#define END_TEST(result, desc, args...) \
|
|
pass(result, desc, ## args); \
|
|
NS_HANDLER \
|
|
fprintf(stderr, "EXCEPTION: %s %s %s\n", \
|
|
[[localException name] UTF8String], \
|
|
[[localException reason] UTF8String], \
|
|
[[[localException userInfo] description] UTF8String]); \
|
|
pass (NO, desc, ## args); NS_ENDHANDLER } \
|
|
else unsupported (desc, ## args)
|
|
|
|
/* Functions to test basic capabilities expected of most classes.
|
|
*/
|
|
static void test_NSMutableCopying(NSString *iClassName,
|
|
NSString *mClassName,
|
|
NSArray *objects) __attribute__ ((unused));
|
|
static void test_alloc(NSString *className) __attribute__ ((unused));
|
|
static void test_alloc_only(NSString *className) __attribute__ ((unused));
|
|
static void test_NSObject(NSString *className,
|
|
NSArray *objects) __attribute__ ((unused));
|
|
static void test_NSCopying(NSString *iClassName,
|
|
NSString *mClassName,
|
|
NSArray *objects,
|
|
BOOL mustRetain,
|
|
BOOL mustCopy) __attribute__ ((unused));
|
|
static void test_NSCoding(NSArray *objects) __attribute__ ((unused));
|
|
static void test_keyed_NSCoding(NSArray *objects) __attribute__ ((unused));
|
|
|
|
/* perform basic allocation tests */
|
|
static void test_alloc(NSString *className)
|
|
{
|
|
Class theClass = NSClassFromString(className);
|
|
id obj0 = nil;
|
|
id obj1 = nil;
|
|
const char *prefix = [[NSString stringWithFormat: @"Class '%@'", className]
|
|
UTF8String];
|
|
NSZone *testZone = NSCreateZone(1024, 1024, 1);
|
|
pass(theClass != Nil, "%s exists", prefix);
|
|
|
|
obj0 = [theClass alloc];
|
|
pass(obj0 != nil, "%s has working alloc", prefix);
|
|
pass([obj0 isKindOfClass: theClass],
|
|
"%s alloc gives the correct class", prefix);
|
|
obj0 = [[theClass alloc] init];
|
|
pass([obj0 isKindOfClass: theClass], "%s has working init", prefix);
|
|
|
|
obj0 = [theClass new];
|
|
pass([obj0 isKindOfClass: theClass], "%s has working new", prefix);
|
|
|
|
obj1 = [theClass allocWithZone: testZone];
|
|
pass([obj1 isKindOfClass: theClass],"%s has working allocWithZone",prefix);
|
|
}
|
|
/* perform basic allocation tests without initialisation*/
|
|
static void test_alloc_only(NSString *className)
|
|
{
|
|
Class theClass = NSClassFromString(className);
|
|
id obj0 = nil;
|
|
id obj1 = nil;
|
|
const char *prefix = [[NSString stringWithFormat: @"Class '%@'", className]
|
|
UTF8String];
|
|
NSZone *testZone = NSCreateZone(1024, 1024, 1);
|
|
pass(theClass != Nil, "%s exists", prefix);
|
|
|
|
obj0 = [theClass alloc];
|
|
pass(obj0 != nil, "%s has working alloc", prefix);
|
|
pass([obj0 isKindOfClass: theClass],
|
|
"%s alloc gives the correct class", prefix);
|
|
PASS_EXCEPTION([obj0 description], NSInvalidArgumentException, "raises NSInvalidArgumentException in description")
|
|
|
|
PASS_EXCEPTION(if([obj0 init]==nil)[NSException raise: NSInvalidArgumentException format: @""],
|
|
NSInvalidArgumentException, "returns nil or raises NSInvalidArgumentException in init")
|
|
|
|
PASS_EXCEPTION(if([theClass new]==nil)[NSException raise: NSInvalidArgumentException format: @""],
|
|
NSInvalidArgumentException, "returns nil or raises NSInvalidArgumentException in new")
|
|
|
|
obj1 = [theClass allocWithZone: testZone];
|
|
pass([obj1 isKindOfClass: theClass],"%s has working allocWithZone",prefix);
|
|
}
|
|
/* test for the NSObject protocol */
|
|
/* TODO move to ProtocolTesting.h? */
|
|
static void test_NSObject(NSString *className, NSArray *objects)
|
|
{
|
|
int i;
|
|
Class theClass = Nil;
|
|
theClass = NSClassFromString(className);
|
|
pass(theClass != Nil, "%s is a known className", [className UTF8String]);
|
|
|
|
for (i = 0; i < [objects count]; i++)
|
|
{
|
|
id theObj = [objects objectAtIndex: i];
|
|
id mySelf = nil;
|
|
Class myClass = Nil;
|
|
int count0;
|
|
int count1;
|
|
int count2;
|
|
Class sup = Nil;
|
|
const char *prefix;
|
|
id r;
|
|
|
|
prefix = [[NSString stringWithFormat: @"Object %i of class '%@'",
|
|
i, className] UTF8String];
|
|
pass([theObj conformsToProtocol: @protocol(NSObject)],
|
|
"%s conforms to NSObject", prefix);
|
|
mySelf = [theObj self];
|
|
pass(mySelf == theObj, "%s can return self", prefix);
|
|
myClass = [theObj class];
|
|
pass(myClass != Nil, "%s can return own class", prefix);
|
|
pass([theObj isKindOfClass: theClass],
|
|
"%s object %.160s is of correct class", prefix,
|
|
[[theObj description] UTF8String]);
|
|
pass(mySelf == myClass ? ![theObj isMemberOfClass: myClass]
|
|
: [theObj isMemberOfClass: myClass], "%s isMemberOfClass works", prefix);
|
|
sup = [theObj superclass];
|
|
pass(theClass == NSClassFromString(@"NSObject") ? sup == nil
|
|
: (sup != nil && sup != myClass), "%s can return superclass", prefix);
|
|
pass([theObj respondsToSelector: @selector(hash)],
|
|
"%s responds to hash", prefix);
|
|
pass([theObj isEqual: theObj], "%s isEqual: to self", prefix);
|
|
pass([theObj respondsToSelector: @selector(self)],
|
|
"%s respondsToSelector: ", prefix);
|
|
[theObj isProxy];
|
|
r = [theObj retain];
|
|
pass(theObj == r, "%s handles retain", prefix);
|
|
[theObj release];
|
|
[theObj retain];
|
|
[theObj autorelease];
|
|
|
|
count0 = [theObj retainCount];
|
|
[theObj retain];
|
|
count1 = [theObj retainCount];
|
|
[theObj release];
|
|
count2 = [theObj retainCount];
|
|
pass((count0 == count2), "%s has working retainCount", prefix);
|
|
pass([[theObj description] isKindOfClass: [NSString class]],
|
|
"%s has NSString description", prefix);
|
|
pass([theObj performSelector: @selector(self)] == theObj,
|
|
"%s handles performSelector", prefix);
|
|
}
|
|
}
|
|
static void test_NSCoding(NSArray *objects)
|
|
{
|
|
int i;
|
|
for (i = 0; i < [objects count]; i++)
|
|
{
|
|
id obj = [objects objectAtIndex: i];
|
|
const char *prefix;
|
|
NSMutableData *data;
|
|
NSArchiver *archiver;
|
|
id decoded;
|
|
|
|
START_SET(YES);
|
|
pass([[[obj class] description] length],
|
|
"I can extract a class name for object");
|
|
|
|
prefix = [[NSString stringWithFormat: @"Object %i of class '%s'", i,
|
|
[NSStringFromClass([obj class]) UTF8String]] UTF8String];
|
|
pass([obj conformsToProtocol: @protocol(NSCoding)],
|
|
"conforms to NSCoding protocol");
|
|
data = (NSMutableData *)[NSMutableData data];
|
|
archiver = [[NSArchiver alloc] initForWritingWithMutableData: data];
|
|
pass(archiver != nil, "I am able to set up an archiver");
|
|
data = nil;
|
|
[archiver encodeRootObject: obj];
|
|
data = [archiver archiverData];
|
|
pass(data && [data length] > 0, "%s can be encoded", prefix);
|
|
decoded = [NSUnarchiver unarchiveObjectWithData: data];
|
|
pass(decoded != nil, "can be decoded");
|
|
pass([decoded isEqual: obj], "decoded object equals the original");
|
|
END_SET("test_NSCoding object %u", i);
|
|
}
|
|
}
|
|
|
|
static void test_keyed_NSCoding(NSArray *objects)
|
|
{
|
|
int i;
|
|
for (i = 0; i < [objects count]; i++)
|
|
{
|
|
id obj = [objects objectAtIndex: i];
|
|
const char *prefix;
|
|
NSData *data;
|
|
id decoded;
|
|
|
|
START_SET(YES);
|
|
pass([[[obj class] description] length],
|
|
"I can extract a class name for object");
|
|
|
|
prefix = [[NSString stringWithFormat: @"Object %i of class '%s'", i,
|
|
[NSStringFromClass([obj class]) UTF8String]] UTF8String];
|
|
pass([obj conformsToProtocol: @protocol(NSCoding)],
|
|
"conforms to NSCoding protocol");
|
|
data = [NSKeyedArchiver archivedDataWithRootObject: obj];
|
|
pass([data length] > 0, "%s can be encoded", prefix);
|
|
decoded = [NSKeyedUnarchiver unarchiveObjectWithData: data];
|
|
pass (decoded != nil, "can be decoded");
|
|
PASS_EQUAL(decoded, obj, "decoded object equals the original");
|
|
END_SET("test_keyed_NSCoding object %u", i);
|
|
}
|
|
}
|
|
|
|
static void test_NSCopying(NSString *iClassName,
|
|
NSString *mClassName,
|
|
NSArray *objects,
|
|
BOOL mustRetain,
|
|
BOOL mustCopy)
|
|
{
|
|
Class iClass = NSClassFromString(iClassName);
|
|
Class mClass = NSClassFromString(mClassName);
|
|
int i;
|
|
NSZone *testZone = NSCreateZone(1024, 1024, 1);
|
|
|
|
pass(iClass != Nil, "%s is a known class", [iClassName UTF8String]);
|
|
pass(mClass != Nil, "%s is a known class", [mClassName UTF8String]);
|
|
|
|
for (i = 0; i < [objects count]; i++)
|
|
{
|
|
BOOL immutable;
|
|
NSString *theName;
|
|
const char *prefix;
|
|
id theCopy = nil;
|
|
Class theClass = Nil;
|
|
id theObj = [objects objectAtIndex: i];
|
|
|
|
START_SET(YES);
|
|
if (iClass != mClass && [theObj isKindOfClass: mClass])
|
|
{
|
|
immutable = NO;
|
|
theName = iClassName;
|
|
theClass = iClass;
|
|
}
|
|
else
|
|
{
|
|
immutable = YES;
|
|
theName = mClassName;
|
|
theClass = mClass;
|
|
}
|
|
|
|
prefix = [[NSString stringWithFormat: @"Object %i of class '%s'",
|
|
i, [theName UTF8String]] UTF8String];
|
|
pass([theObj conformsToProtocol: @protocol(NSCopying)],
|
|
"conforms to NSCopying");
|
|
theCopy = [theObj copy];
|
|
pass(theCopy != nil, "%s understands -copy", prefix);
|
|
pass([theCopy isKindOfClass: iClass],
|
|
"%s copy is of correct type", prefix);
|
|
pass([theObj isEqual: theCopy], "%s original and copy are equal", prefix);
|
|
if (immutable)
|
|
{
|
|
if (YES == mustRetain)
|
|
{
|
|
pass(theCopy == theObj,
|
|
"%s is retained by copy with same zone", prefix);
|
|
}
|
|
else if (YES == mustCopy)
|
|
{
|
|
pass(theCopy != theObj,
|
|
"%s is not retained by copy with same zone", prefix);
|
|
}
|
|
}
|
|
if (theClass != iClass)
|
|
{
|
|
pass(![theCopy isKindOfClass: theClass],
|
|
"%s result of copy is not immutable", prefix);
|
|
}
|
|
|
|
theCopy = [theObj copyWithZone: testZone];
|
|
pass(theCopy != nil, "%s understands -copyWithZone", prefix);
|
|
pass([theCopy isKindOfClass: iClass],
|
|
"%s zCopy has correct type", prefix);
|
|
pass([theObj isEqual: theCopy],
|
|
"%s copy and original are equal", prefix);
|
|
if (immutable)
|
|
{
|
|
if (YES == mustRetain)
|
|
{
|
|
pass(theCopy == theObj,
|
|
"%s is retained by copy with other zone", prefix);
|
|
}
|
|
else if (YES == mustCopy)
|
|
{
|
|
pass(theCopy != theObj,
|
|
"%s is not retained by copy with other zone", prefix);
|
|
}
|
|
}
|
|
if (theClass != iClass)
|
|
pass(![theCopy isKindOfClass: theClass],
|
|
"%s result of copyWithZone: is not immutable", prefix);
|
|
END_SET("test_NSCopying object %u", i);
|
|
}
|
|
}
|
|
|
|
|
|
static void test_NSMutableCopying(NSString *iClassName,
|
|
NSString *mClassName,
|
|
NSArray *objects)
|
|
{
|
|
int i;
|
|
Class iClass = Nil;
|
|
Class mClass = Nil;
|
|
NSZone *testZone = NSCreateZone(1024, 1024, 1);
|
|
iClass = NSClassFromString(iClassName);
|
|
pass(iClass != Nil, "%s is a known class", [iClassName UTF8String]);
|
|
|
|
mClass = NSClassFromString(mClassName);
|
|
pass(mClass != Nil, "%s is a known class", [mClassName UTF8String]);
|
|
|
|
for (i = 0; i < [objects count]; i++)
|
|
{
|
|
id theObj = [objects objectAtIndex: i];
|
|
NSString *theName = nil;
|
|
const char *prefix;
|
|
BOOL immutable;
|
|
id theCopy = nil;
|
|
Class theClass = Nil;
|
|
|
|
START_SET(YES);
|
|
if (iClass == mClass && [theObj isKindOfClass: mClass])
|
|
immutable = NO;
|
|
else
|
|
immutable = YES;
|
|
|
|
if (immutable)
|
|
{
|
|
theName = iClassName;
|
|
theClass = iClass;
|
|
}
|
|
else
|
|
{
|
|
theName = mClassName;
|
|
theClass = mClass;
|
|
}
|
|
|
|
prefix = [[NSString stringWithFormat:
|
|
@"Object %i of class '%s'", i, [theName UTF8String]] UTF8String];
|
|
pass([theObj conformsToProtocol: @protocol(NSMutableCopying)],
|
|
"%s conforms to NSMutableCopying protocol", prefix);
|
|
theCopy = [theObj mutableCopy];
|
|
pass(theCopy != nil, "%s understands -mutableCopy", prefix);
|
|
pass([theCopy isKindOfClass: mClass],
|
|
"%s mutable copy is of correct type", prefix);
|
|
pass([theCopy isEqual: theObj], "%s copy equals original", prefix);
|
|
pass(theCopy != theObj,
|
|
"%s not retained by mutable copy in the same zone",
|
|
[mClassName UTF8String]);
|
|
|
|
theCopy = [theObj mutableCopyWithZone: testZone];
|
|
pass(theCopy != nil,
|
|
"%s understands mutableCopyWithZone", [mClassName UTF8String]);
|
|
pass(theCopy != theObj, "%s not retained by mutable copy in other zone",
|
|
[mClassName UTF8String]);
|
|
END_SET("test_NSMutableCopying object %u", i);
|
|
}
|
|
}
|
|
|