mirror of
https://github.com/gnustep/tools-make.git
synced 2025-04-23 22:33:28 +00:00
Add test framework
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/tools/make/trunk@32010 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
97600a0e82
commit
e2e760b00b
15 changed files with 1637 additions and 1 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
2011-01-07 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* TestFramework/example1.m:
|
||||
* TestFramework/example2.m:
|
||||
* TestFramework/example3.m:
|
||||
* TestFramework/example4.m:
|
||||
* TestFramework/example5.m:
|
||||
* TestFramework/example6.m:
|
||||
* TestFramework/example7.m:
|
||||
* TestFramework/GNUmakefile.in:
|
||||
* TestFramework/gnustep-tests:
|
||||
* TestFramework/ObjectTesting.h:
|
||||
* TestFramework/README:
|
||||
* TestFramework/runtest.sh:
|
||||
* TestFramework/Testing.h:
|
||||
Test framework scripts, headers, template, examples, documentation
|
||||
* GNUmakefile.in:
|
||||
Altered to install/uninstall test framework.
|
||||
|
||||
2010-12-22 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* configure.ac: Tidied up a few messages.
|
||||
|
|
|
@ -139,6 +139,9 @@ INSTANCE_SHARED_MAKE_FILES = bundle.make headers.make java.make \
|
|||
INSTANCE_DOC_MAKE_FILES = autogsdoc.make gsdoc.make install_files.make \
|
||||
javadoc.make latex.make texi.make
|
||||
|
||||
TEST_FRAMEWORK_FILES = \
|
||||
GNUmakefile.in Testing.h ObjectTesting.h
|
||||
|
||||
# Decide which version of the GNUstep.conf file we are going to
|
||||
# install; the standard one, or the strict gnustep-make v2 one ?
|
||||
ifeq ($(GNUSTEP_MAKE_STRICT_V2_MODE),yes)
|
||||
|
@ -172,7 +175,8 @@ install: generated-files
|
|||
"$(makedir)/Master" \
|
||||
"$(makedir)/Instance" \
|
||||
"$(makedir)/Instance/Shared" \
|
||||
"$(makedir)/Instance/Documentation")
|
||||
"$(makedir)/Instance/Documentation" \
|
||||
"$(makedir)/TestFramework")
|
||||
$(EC)(echo "Installing GNUstep configuration file in $(GNUSTEP_CONFIG_FILE)"; \
|
||||
"$(srcdir)/mkinstalldirs" "$(GNUSTEP_CONFIG_FILE_DIR)"; \
|
||||
$(INSTALL_DATA) $(GNUSTEP_DOT_CONF_FILE) "$(GNUSTEP_CONFIG_FILE)")
|
||||
|
@ -219,6 +223,13 @@ install: generated-files
|
|||
$(INSTALL_DATA) config-noarch.make "$(makedir)"; \
|
||||
$(INSTALL_DATA) filesystem.make "$(makedir)"; \
|
||||
$(INSTALL_DATA) config.make "$(makedir)/$(GNUSTEP_TARGET_LDIR)")
|
||||
$(EC)(echo "Installing Test Framework scripts"; \
|
||||
$(INSTALL_PROGRAM) -m 755 TestFramework/runtests.sh "$(tooldir)"; \
|
||||
$(INSTALL_PROGRAM) -m 755 TestFramework/runtest.sh "$(makedir)/TestFramework")
|
||||
$(EC)(echo "Installing Test Framework support files"; \
|
||||
for f in $(TEST_FRAMEWORK_FILES); do \
|
||||
$(INSTALL_DATA) "$(srcdir)/TestFramework/$$f" "$(makedir)/TestFramework"; \
|
||||
done)
|
||||
$(EC)(echo "Installing (and compressing) manpages"; \
|
||||
"$(srcdir)/mkinstalldirs" "$(mandir)/man1" \
|
||||
"$(mandir)/man7"; \
|
||||
|
@ -262,6 +273,8 @@ uninstall:
|
|||
rm -f "$(tooldir)/debugapp"; \
|
||||
rm -f "$(tooldir)/opentool"; \
|
||||
rm -f "$(tooldir)/gnustep-config"; \
|
||||
rm -f "$(tooldir)/runtests.sh"; \
|
||||
rm -f "$(makedir)/TestFramework/runtest.sh"; \
|
||||
for f in $(MAKE_FILES); do \
|
||||
rm -f "$(makedir)/$$f"; \
|
||||
done
|
||||
|
@ -277,6 +290,9 @@ uninstall:
|
|||
for f in $(INSTANCE_DOC_MAKE_FILES); do \
|
||||
rm -f "$(makedir)/Instance/Documentation/$$f"; \
|
||||
done
|
||||
for f in $(TEST_FRAMEWORK_FILES); do \
|
||||
rm -f "$(makedir)/TestFramework/$$f"; \
|
||||
done
|
||||
rm -f "$(makedir)/executable.template"
|
||||
rm -f "$(makedir)/app-wrapper.template"
|
||||
rm -f "$(makedir)/java-executable.template"
|
||||
|
@ -287,6 +303,7 @@ uninstall:
|
|||
rm -f "$(makedir)/$(GNUSTEP_TARGET_LDIR)/config.make"
|
||||
rm -f "$(GNUSTEP_CONFIG_FILE)"
|
||||
-rmdir "$(GNUSTEP_CONFIG_FILE_DIR)"
|
||||
-rmdir "$(makedir)/TestFramework"
|
||||
-rmdir "$(makedir)/Instance/Documentation"
|
||||
-rmdir "$(makedir)/Instance/Shared"
|
||||
-rmdir "$(makedir)/Instance"
|
||||
|
|
24
TestFramework/GNUmakefile.in
Normal file
24
TestFramework/GNUmakefile.in
Normal file
|
@ -0,0 +1,24 @@
|
|||
# __GENERATED__ makefile marker
|
||||
#
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
-include ../GNUmakefile.super
|
||||
|
||||
TEST_TOOL_NAME = @TESTNAME@
|
||||
|
||||
ADDITIONAL_OBJCFLAGS += -I@INCLUDEDIR@ -Wall
|
||||
|
||||
ifeq ($(gcov),yes)
|
||||
ADDITIONAL_OBJCFLAGS += -ftest-coverage -fprofile-arcs
|
||||
ADDITIONAL_LDFLAGS += -ftest-coverage -fprofile-arcs
|
||||
ADDITIONAL_TOOL_LIBS+=-lgcov
|
||||
endif
|
||||
|
||||
@TESTNAME@_OBJC_FILES = @FILENAME@
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/test-tool.make
|
||||
-include GNUmakefile.postamble
|
||||
|
||||
test:
|
||||
./$(GNUSTEP_OBJ_DIR_NAME)/@TESTNAME@
|
426
TestFramework/ObjectTesting.h
Normal file
426
TestFramework/ObjectTesting.h
Normal file
|
@ -0,0 +1,426 @@
|
|||
/* 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 UNSUPPORTED 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);
|
||||
}
|
||||
}
|
||||
|
150
TestFramework/README
Normal file
150
TestFramework/README
Normal file
|
@ -0,0 +1,150 @@
|
|||
|
||||
TestFramework
|
||||
=============
|
||||
|
||||
This testsuite is a general framework for testing the core GNUstep
|
||||
libraries. Since, in part, we are testing the very basic level of
|
||||
an Objective-C runtime, we can't use more complete unit tests, such
|
||||
as OCUnit <http://www.sente.ch/software/ocunit/>.
|
||||
The aim of this framework is to provide a simple, yet reasonaply
|
||||
comprehensive regression test mechanism for Objective-C development.
|
||||
|
||||
Please run the GNUstep testsuite (using this framework) often, when
|
||||
adding new features, fixing bugs and running on new platforms.
|
||||
|
||||
Where working on features common to both Apple's Cocoa/iOS APIs and
|
||||
to GNUstep, please try creating and running test cases in the Apple
|
||||
environment before implementing/changing GNUstep code, so that you
|
||||
are sure the behavior is the same in bioth cases.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
The testing framework and many of the test cases in the testsuite are
|
||||
copyright by the FSF and distributed under the GPL. However, some tests
|
||||
may not be copyright by the FSF, but retain the copyright of the original
|
||||
owner (e.g tests submited as bug reports). You should feel free to add tests
|
||||
that are not copyright by the FSF. The copyright of these tests should
|
||||
be clearly stated, however, and they should still be distributed under the
|
||||
GPL version 3 or later.
|
||||
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
To run a testsuite, use the gnustep-tests script along with the name of
|
||||
the project testsuite (directory) you with to test:
|
||||
|
||||
gnustep-tests base
|
||||
|
||||
or where a group of tests within a project is to be run:
|
||||
|
||||
gnustep-tests base/NSArray
|
||||
|
||||
You may run individual test files by using the runtest.sh script with the
|
||||
name(s) of the Objective-C test source file(s):
|
||||
|
||||
gnustep-tests base/NSDate/general.m
|
||||
gnustep-tests ./mytest.m base/NSDate/general.m
|
||||
|
||||
Alternatively, you may run tests from within a project/directory. eg.
|
||||
|
||||
cd base
|
||||
gnustep-tests
|
||||
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
|
||||
A minimal test should be a file importing the header "Testing.h"
|
||||
(which defines global variables, functions, and standard test macros)
|
||||
and containing a main() function implementation which executes the
|
||||
actual test code.
|
||||
Groups of tests should be placed between calls to the START_SET() and
|
||||
END_SET() macros.
|
||||
|
||||
You should look at the example test files in the same directory as
|
||||
this README for how to write test cases, and you should examine Testing.h
|
||||
to see full documentation of the range of macros provided.
|
||||
|
||||
The main workhorse of the test framewrk is the pass() function, which has
|
||||
two arguments ... first an integer expression, and second a string
|
||||
describing what is being tested.
|
||||
The function uses the global variable 'testHopeful' to decide whether a
|
||||
test which did not pass is a 'FAIL' (when testHopeful==NO) or a 'DASHED'
|
||||
hope (when testHopeful==YES).
|
||||
The function sets the global variable 'testPassed' to a BOOL reflecting
|
||||
the result of the test (YES if the test passed, NO otherwise).
|
||||
The only other functions are for occasional use to report sections of
|
||||
the testsuite as not having run for some reason.
|
||||
|
||||
There are just four test macros.
|
||||
All have uppercase names beginning with 'PASS'.
|
||||
All wrap test code and a call to the pass() function in exception handlers.
|
||||
All are code blocks and do not need a semicolon terminator.
|
||||
|
||||
PASS passes if an expression resulting in an integer value is
|
||||
non-zero
|
||||
PASS_EQUAL passes if an expression resulting in an object is identical
|
||||
to or -isEqual: to another object.
|
||||
PASS_EXCEPTION passes if a code fragment raises an exception
|
||||
PASS_RUNS passes if a code fragment runs without raising an exception
|
||||
|
||||
Tests are grouped together, along with any associated non-test code, between
|
||||
paired calls to the START_SET and END_SET macros.
|
||||
|
||||
You can skip an entire set by supplying NO as the argument to the START_SET
|
||||
macro, in which case the entire set will be reported as UNSUPPORTED.
|
||||
|
||||
Any uncaught exception (ie one which occurs outside a one of the four test
|
||||
macros and is not caught by an exception handler you write yourself) will
|
||||
cause the remaining tests in a set to be skipped. In this case the set
|
||||
will be reported as UNRESOLVED.
|
||||
|
||||
You may also arrange to jump to the end of the set if a test fails by wrapping
|
||||
the test in a NEED macro. Doing this also causes the set to be reported as
|
||||
UNRESOLVED.
|
||||
|
||||
|
||||
Advanced building
|
||||
-----------------
|
||||
|
||||
In most cases, all you need to do is write an objective-c file as described
|
||||
above, and the test framework will build it and run it for you automatically,
|
||||
but occasionally you may need to use your own build process.
|
||||
|
||||
Where tests must make use of external resources or ensure that other tests
|
||||
have already been run before they are run, you can make use of the gnustep
|
||||
make package facilities to control dependencies etc.
|
||||
|
||||
Normally each test is built and run by generating a makefile in the directory
|
||||
containing the test. This makefile uses the standard conventions of including
|
||||
GNUmakefile.preamble before test-tool.make and including GNUmakefile.postamble
|
||||
after test-tool.make, which gives you a high degree of control over how the
|
||||
tests in the directory are built.
|
||||
|
||||
In addition to the preamble/postamble mechanism, the file ../GNUmakefile.super
|
||||
is included at the start of the generated makefile (if it exists). This allows
|
||||
all the tests in a suite to use a common makefile fragment which can (for
|
||||
instance) build common resources before any tests are run.
|
||||
|
||||
For total control, the runtest.sh script checks to see if a 'Custom.mk' file
|
||||
exists in the directory, and if it does it uses that file to build the tests
|
||||
rather than generating its own make file.
|
||||
|
||||
You may also specify a GNUmakefile.tests in a project level directory (ie one
|
||||
containing subdirectories of tests), and that makefile will be executed when
|
||||
you run tests on the project.
|
||||
|
||||
Ignoring directories
|
||||
--------------------
|
||||
|
||||
If, when given the name of a test to be run, the runtest.sh script finds a
|
||||
file named 'IGNORE' in the same directory as the named file, it skips
|
||||
running of the test. The effect of this is that the presence of an IGNORE
|
||||
file causes a directory to be ignored. This is useful in conjunction
|
||||
with ../GNUmakefile.super so that projects to build resources for other tests
|
||||
can be ignored by the scripts running the tests, and just built as required
|
||||
by ../GNUmakefile.super
|
||||
|
379
TestFramework/Testing.h
Normal file
379
TestFramework/Testing.h
Normal file
|
@ -0,0 +1,379 @@
|
|||
/* Testing - Include basic tests macros for the GNUstep Testsuite
|
||||
|
||||
Copyright (C) 2005-2011 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
Updated by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
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 3 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef Testing_h
|
||||
#define Testing_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSGarbageCollector.h>
|
||||
#import <Foundation/NSObjCRuntime.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
/* A flag indicating that the testsuite is currently processing tests
|
||||
* which are actually not expected to pass, but where we hope someone
|
||||
* might have committed a bugfix.
|
||||
* The state of this flag is preserved by sets ... on exit from a set
|
||||
* it is restored to the state it had on entry.
|
||||
*/
|
||||
static BOOL testHopeful __attribute__((unused)) = NO;
|
||||
|
||||
/* A flag indicating whether the most recently executed test passed.
|
||||
* This is set by the pass() function (and therefore by any test macro).
|
||||
*/
|
||||
static BOOL testPassed __attribute__((unused)) = NO;
|
||||
|
||||
/* A variable set whenever a test macro is executed. This contains
|
||||
* the exception which terminated the test macro, or nil if no exception
|
||||
* was raised.
|
||||
*/
|
||||
static NSException *testRaised __attribute__((unused)) = nil;
|
||||
|
||||
/* The pass() function is the low-level core of the testsuit.
|
||||
*
|
||||
* You call this with two arguments ... an integer expression indicating the
|
||||
* success or failure of the testcase (0 is a failure) and a string which
|
||||
* describes the testcase.
|
||||
*
|
||||
* The global variable 'testHopeful' can be set to a non-zero value before
|
||||
* calling this function in order to specify that if the condition is
|
||||
* not true it should be treated as a dashed hope rather than a failure.
|
||||
*
|
||||
* If there is a better higher-level test macro available, please use
|
||||
* that instead. In particular, please use the PASS_EQUAL() macro wherever
|
||||
* you wish to test the equality of a pair of objective-c objects.
|
||||
*
|
||||
* This function is the most efficient option for general use, but
|
||||
* please don't use it if there is any change that the evaluation of
|
||||
* the expression used as its first argument might cause an exception
|
||||
* in any context where that might be a problem.
|
||||
*/
|
||||
static void pass(int testPassed, const char *format, ...) __attribute__((unused)) __attribute__ ((format(printf, 2, 3)));
|
||||
static void pass(int testPassed, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (testPassed)
|
||||
{
|
||||
fprintf(stderr, "PASS: ");
|
||||
testPassed = YES;
|
||||
}
|
||||
else if (YES == testHopeful)
|
||||
{
|
||||
fprintf(stderr, "DASHED: ");
|
||||
testPassed = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "FAIL: ");
|
||||
testPassed = NO;
|
||||
}
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* The unresolved() function is called with a single string argument to
|
||||
* notify the testsuite that a test failed to complete for some reason.
|
||||
* eg. You might call this if an earlier testcase failed and it makes no
|
||||
* sense to run subsequent tests.
|
||||
* This is called if a set is terminated before all the tests in it have
|
||||
* been run.
|
||||
*/
|
||||
static void unresolved(const char *format, ...) __attribute__((unused)) __attribute__ ((format(printf, 1, 2), unused));
|
||||
static void unresolved(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fprintf(stderr, "UNRESOLVED: ");
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* The unsupported() function is called with a single string argument to
|
||||
* notify the testsuite that a test could not be run because the capability
|
||||
* it is testing does not exist on the current platform.
|
||||
*/
|
||||
static void unsupported(const char *format, ...) __attribute__((unused)) __attribute__ ((format(printf, 1, 2), unused));
|
||||
static void unsupported(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fprintf(stderr, "UNSUPPORTED: ");
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Tests a code expression which evaluates to an integer value.
|
||||
* If the expression evaluates to zero the test does not pass.
|
||||
* If the expression causes an exception to be raised, the exception
|
||||
* is caught and logged but the test does not pass.
|
||||
* Otherwise, the test passes.
|
||||
* Basically equivalent to pass() but with exception handling.
|
||||
*/
|
||||
#define PASS(expression, args...) \
|
||||
NS_DURING \
|
||||
{ \
|
||||
int _cond; \
|
||||
id _tmp = testRaised; testRaised = nil; [_tmp release]; \
|
||||
[[NSGarbageCollector defaultCollector] collectExhaustively]; \
|
||||
_cond = (int) expression; \
|
||||
[[NSGarbageCollector defaultCollector] collectExhaustively]; \
|
||||
pass(_cond, ## args); \
|
||||
} \
|
||||
NS_HANDLER \
|
||||
testRaised = [localException retain]; \
|
||||
pass(0, ## args); \
|
||||
printf("%s: %s", [[testRaised name] UTF8String], \
|
||||
[[testRaised description] UTF8String]); \
|
||||
NS_ENDHANDLER
|
||||
|
||||
/* Tests a code expression which evaluates to an object value.
|
||||
*
|
||||
* Where the expression evaluates to an object which is identical to
|
||||
* the expect value, or where [object isEqual: expect] returns YES,
|
||||
* the test has passed.
|
||||
*
|
||||
* The particularly useful thing about this macro is that, if the
|
||||
* results of the expression and the expected object are not equal,
|
||||
* the string representation of both values is logged so that you
|
||||
* can get a better idea of what went wrong.
|
||||
*/
|
||||
#define PASS_EQUAL(expression, expect, args...) \
|
||||
NS_DURING \
|
||||
{ \
|
||||
int _cond; \
|
||||
id _obj; \
|
||||
id _tmp = testRaised; testRaised = nil; [_tmp release]; \
|
||||
[[NSGarbageCollector defaultCollector] collectExhaustively]; \
|
||||
_obj = ( expression );\
|
||||
_cond = _obj == expect || [_obj isEqual: expect]; \
|
||||
[[NSGarbageCollector defaultCollector] collectExhaustively]; \
|
||||
pass(_cond, ## args); \
|
||||
if (0 == _cond) \
|
||||
{ \
|
||||
NSString *s = [_obj description]; \
|
||||
if ([s length] == 1) \
|
||||
{ \
|
||||
fprintf(stderr, \
|
||||
"Expected '%s' and got '%s' (unicode codepoint %d)\n", \
|
||||
[[expect description] UTF8String], [s UTF8String], \
|
||||
[s characterAtIndex: 0]); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fprintf(stderr, "Expected '%s' and got '%s'\n", \
|
||||
[[expect description] UTF8String], [s UTF8String]); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
NS_HANDLER \
|
||||
testRaised = [localException retain]; \
|
||||
pass(0, ## args); \
|
||||
printf("%s: %s", [[testRaised name] UTF8String], \
|
||||
[[testRaised description] UTF8String]); \
|
||||
NS_ENDHANDLER
|
||||
|
||||
/* Please use the PASS_EXCEPTION() macro to handle any code where you
|
||||
* want an exception to be thrown. The macro checks that the supplied
|
||||
* code throws the specified exception. If the code fails to throw,
|
||||
* or throws the wrong exception, then the code does not pass.
|
||||
* You can supply nil for expectedExceptionName if you don't care about the
|
||||
* type of exception.
|
||||
*/
|
||||
#define PASS_EXCEPTION(code, expectedExceptionName, args...) \
|
||||
NS_DURING \
|
||||
id _tmp = testRaised; testRaised = nil; [_tmp release]; \
|
||||
{ code; } \
|
||||
pass(0, ## args); \
|
||||
NS_HANDLER \
|
||||
testRaised = [localException retain]; \
|
||||
pass((expectedExceptionName == nil \
|
||||
|| [[testRaised name] isEqual: expectedExceptionName]), ## args); \
|
||||
if (NO == [expectedExceptionName isEqual: [testRaised name]]) \
|
||||
fprintf(stderr, "Expected '%s' and got '%s'\n", \
|
||||
[expectedExceptionName UTF8String], \
|
||||
[[testRaised name] UTF8String]); \
|
||||
NS_ENDHANDLER
|
||||
|
||||
/* Please use the PASS_RUNS() macro to handle any code where you want the
|
||||
* code to run to completion without an exception being thrown, but you don't
|
||||
* have a particular expression to be checked.
|
||||
*/
|
||||
#define PASS_RUNS(code, args...) \
|
||||
NS_DURING \
|
||||
id _tmp = testRaised; testRaised = nil; [_tmp release]; \
|
||||
{ code; } \
|
||||
pass(1, ## args); \
|
||||
NS_HANDLER \
|
||||
testRaised = [localException retain]; \
|
||||
pass(0, ## args); \
|
||||
printf("%s: %s", [[testRaised name] UTF8String], \
|
||||
[[testRaised description] UTF8String]); \
|
||||
NS_ENDHANDLER
|
||||
|
||||
|
||||
/* SETs are used to group multiple testcases or code which is outside of
|
||||
* the scope of the current test but could raise exceptions that should
|
||||
* be caught to allow further tests to run.
|
||||
*
|
||||
* You must pass a 'supported' flag to say whether the code should be run
|
||||
* or not, if not then the set is reported as unsupported.
|
||||
*
|
||||
* The state of the 'testHopeful' flag is saved at the start of the set and
|
||||
* restored at the end of the set, so you can start your code by setting
|
||||
* 'testHopeful=YES;' to mark any tests within the set as being part of a group
|
||||
* of tests we don't expect to pass.
|
||||
*
|
||||
* The tests within the set are enclosed in an autorelease pool, and any
|
||||
* temporary objects are cleaned up at the end of the set.
|
||||
*/
|
||||
|
||||
/* The START_SET() macro starts a set of grouped tests or, if the argument
|
||||
* is false, skips the set and reports the set as unsupported.
|
||||
*/
|
||||
#define START_SET(supported) \
|
||||
if ((supported)) \
|
||||
{ \
|
||||
BOOL save_hopeful = testHopeful; \
|
||||
NS_DURING \
|
||||
NSAutoreleasePool *_setPool = [NSAutoreleasePool new]; \
|
||||
{
|
||||
|
||||
|
||||
/* The END_SET() macro terminates a set of grouped tests. It's argument is
|
||||
* a printf style format string and variable arguments to print a message
|
||||
* describing the set.
|
||||
*/
|
||||
#define END_SET(desc, args...) \
|
||||
} \
|
||||
[_setPool release]; \
|
||||
NS_HANDLER \
|
||||
if (NO == [[localException name] isEqualToString: @"CheckSet"]) \
|
||||
{ \
|
||||
fprintf(stderr, "EXCEPTION: %s %s %s\n", \
|
||||
[[localException name] UTF8String], \
|
||||
[[localException reason] UTF8String], \
|
||||
[[[localException userInfo] description] UTF8String]); \
|
||||
} \
|
||||
unresolved(desc, ## args); \
|
||||
NS_ENDHANDLER \
|
||||
testHopeful = save_hopeful; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
unsupported(desc, ## args); \
|
||||
}
|
||||
|
||||
/* The NEED macro takes a test macro as an arugment and breaks out of a set
|
||||
* and reports it as unresolved if test does not pass.
|
||||
*/
|
||||
#define NEED(testToTry) \
|
||||
testToTry \
|
||||
if (NO == testPassed) \
|
||||
{ \
|
||||
if (nil != testRaised) \
|
||||
{ \
|
||||
[testRaised raise]; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
[NSException raise: @"CheckSet" format: @"Test did not pass"]; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* some good macros to compare floating point numbers */
|
||||
#import <math.h>
|
||||
#import <float.h>
|
||||
#define EQ(x, y) (fabs((x) - (y)) <= fabs((x) + (y)) * (FLT_EPSILON * 100))
|
||||
#define LE(x, y) ((x)<(y) || EQ(x, y))
|
||||
#define GE(x, y) ((y)<(x) || EQ(x, y))
|
||||
#define LT(x, y) (!GE(x, y))
|
||||
#define GT(x, y) (!LE(x, y))
|
||||
|
||||
/* A convenience macro to pass an object as a string to a print function.
|
||||
*/
|
||||
#define POBJECT(obj) [[(obj) description] UTF8String]
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef CREATE_AUTORELEASE_POOL
|
||||
#define RETAIN(object) [object retain]
|
||||
#define RELEASE(object) [object release]
|
||||
#define AUTORELEASE(object) [object autorelease]
|
||||
#define TEST_RETAIN(object) ({\
|
||||
id __object = (id)(object); (__object != nil) ? [__object retain] : nil; })
|
||||
#define TEST_RELEASE(object) ({\
|
||||
id __object = (id)(object); if (__object != nil) [__object release]; })
|
||||
#define TEST_AUTORELEASE(object) ({\
|
||||
id __object = (id)(object); (__object != nil) ? [__object autorelease] : nil; })
|
||||
#define ASSIGN(object,value) ({\
|
||||
id __value = (id)(value); \
|
||||
id __object = (id)(object); \
|
||||
if (__value != __object) \
|
||||
{ \
|
||||
if (__value != nil) \
|
||||
{ \
|
||||
[__value retain]; \
|
||||
} \
|
||||
object = __value; \
|
||||
if (__object != nil) \
|
||||
{ \
|
||||
[__object release]; \
|
||||
} \
|
||||
} \
|
||||
})
|
||||
#define ASSIGNCOPY(object,value) ({\
|
||||
id __value = (id)(value); \
|
||||
id __object = (id)(object); \
|
||||
if (__value != __object) \
|
||||
{ \
|
||||
if (__value != nil) \
|
||||
{ \
|
||||
__value = [__value copy]; \
|
||||
} \
|
||||
object = __value; \
|
||||
if (__object != nil) \
|
||||
{ \
|
||||
[__object release]; \
|
||||
} \
|
||||
} \
|
||||
})
|
||||
#define DESTROY(object) ({ \
|
||||
if (object) \
|
||||
{ \
|
||||
id __o = object; \
|
||||
object = nil; \
|
||||
[__o release]; \
|
||||
} \
|
||||
})
|
||||
#define CREATE_AUTORELEASE_POOL(X) \
|
||||
NSAutoreleasePool *(X) = [NSAutoreleasePool new]
|
||||
#define RECREATE_AUTORELEASE_POOL(X) \
|
||||
if (X == nil) \
|
||||
(X) = [NSAutoreleasePool new]
|
||||
#endif
|
||||
|
16
TestFramework/example1.m
Normal file
16
TestFramework/example1.m
Normal file
|
@ -0,0 +1,16 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* This is the absolute minimal test program ...
|
||||
* a single test case involving plain C and no Objective-C code.
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example1.m' it should
|
||||
* report a single test file completed and a single test pass
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* This is too simple to really be useful, but it's a start.
|
||||
*/
|
||||
pass(1 == 1, "integer equality works");
|
||||
return 0;
|
||||
}
|
22
TestFramework/example2.m
Normal file
22
TestFramework/example2.m
Normal file
|
@ -0,0 +1,22 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* A second test ... your first go at testing with ObjectiveC
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example2.m' it should
|
||||
* report a single test file completed and two test passes.
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* We start a set here ...
|
||||
* Having a set means we do not need to bother creating an autorelease pool.
|
||||
*/
|
||||
START_SET(YES)
|
||||
|
||||
pass(1 == 1, "integer equality works");
|
||||
pass([[NSObject new] autorelease] != nil, "+new creates an object");
|
||||
|
||||
END_SET("example set")
|
||||
|
||||
return 0;
|
||||
}
|
41
TestFramework/example3.m
Normal file
41
TestFramework/example3.m
Normal file
|
@ -0,0 +1,41 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* A third test ... using test macros.
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example3.m' it should
|
||||
* report a single test file completed, two test passes, and a test fail.
|
||||
*/
|
||||
|
||||
/* Import a header because we want to use a method from it.
|
||||
*/
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* We start a set here ...
|
||||
* Having a set means we do not need to bother creating an autorelease pool.
|
||||
*/
|
||||
START_SET(YES)
|
||||
|
||||
/* We use a macro here so that any exception in the expression we use
|
||||
* will not break out of the set, and the two remaining tests will be
|
||||
* run.
|
||||
*/
|
||||
PASS([(NSDictionary*)@"abc" objectForKey: @"xxx"],
|
||||
"sending a bad message")
|
||||
|
||||
pass(1 == 1, "integer equality works");
|
||||
|
||||
/* And let's use a macro here too ... the expression is not going to
|
||||
* raise an exception unless NSObject is somehow broken, and even if
|
||||
* it did, this is the last test in the set, so it wouldn't matter,
|
||||
* but it's good practice to code safely in case we move the code
|
||||
* around in a later version of the program.
|
||||
*/
|
||||
PASS([[NSObject new] autorelease] != nil, "+new creates an object")
|
||||
|
||||
END_SET("example set")
|
||||
|
||||
return 0;
|
||||
}
|
30
TestFramework/example4.m
Normal file
30
TestFramework/example4.m
Normal file
|
@ -0,0 +1,30 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* A fourth test ... testing for an exception.
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example4.m' it should
|
||||
* report a single test file completed, three test passes.
|
||||
*/
|
||||
|
||||
/* Import a header because we want to use a method from it.
|
||||
*/
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
START_SET(YES)
|
||||
|
||||
/* We test for the code fragment raising an exception. We don't care
|
||||
* about the particular exception, so we pass nil as the expected exception
|
||||
* name.
|
||||
*/
|
||||
PASS_EXCEPTION([(NSDictionary*)@"abc" objectForKey: @"xxx"], nil,
|
||||
"sending a bad message causes an exception")
|
||||
pass(1 == 1, "integer equality works");
|
||||
PASS([[NSObject new] autorelease] != nil, "+new creates an object")
|
||||
|
||||
END_SET("example set")
|
||||
|
||||
return 0;
|
||||
}
|
35
TestFramework/example5.m
Normal file
35
TestFramework/example5.m
Normal file
|
@ -0,0 +1,35 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* A fifth test ... hope.
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example5.m' it should
|
||||
* report a single test file completed, one hope dashed, two test passes,
|
||||
* and one set unresolved.
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
START_SET(YES)
|
||||
|
||||
/* First set a flag to say that we are not expecting tests to
|
||||
* actually pass.
|
||||
*/
|
||||
testHopeful = YES;
|
||||
|
||||
/* Here the test should result in a dashed hope rather than a fail.
|
||||
*/
|
||||
PASS(1 == 0, "silly test which we don't expect to pass")
|
||||
|
||||
/* This test should simply pass of course.
|
||||
*/
|
||||
PASS(1 == 1, "integer equality works")
|
||||
|
||||
END_SET("example set")
|
||||
|
||||
/* And here we demonstrate that on exit from the set, the global
|
||||
* variable is restored to its state on entry.
|
||||
*/
|
||||
pass(NO == testHopeful, "the flag state is restored outside the set");
|
||||
|
||||
return 0;
|
||||
}
|
40
TestFramework/example6.m
Normal file
40
TestFramework/example6.m
Normal file
|
@ -0,0 +1,40 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* A sixth test ... need.
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example6.m' it should
|
||||
* report a single test file completed, one hope dashed, one test pass,
|
||||
* and one set unresolved.
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
START_SET(YES)
|
||||
|
||||
/* First set a flag to say that we are not expecting tests to
|
||||
* actually pass.
|
||||
*/
|
||||
testHopeful = YES;
|
||||
|
||||
/* Here we demonstate the NEED macro. This says that a need must be met
|
||||
* in order to continue with the set ... if the test does not pass
|
||||
* we can't complete the set and we skip to the end.
|
||||
*/
|
||||
NEED(PASS(1 == 0, "silly test which we don't expect to pass"))
|
||||
|
||||
/* This test should never be reached because the previous test needs to
|
||||
* pass, but will not do so.
|
||||
*/
|
||||
PASS(1 == 1, "integer equality works")
|
||||
|
||||
/* The set should be unresolved, because the earlier need was not met.
|
||||
*/
|
||||
END_SET("example set")
|
||||
|
||||
/* And here we demonstrate that on exit from the set, the global
|
||||
* variable is restored to its state on entry.
|
||||
*/
|
||||
pass(NO == testHopeful, "the flag state is restored outside the set");
|
||||
|
||||
return 0;
|
||||
}
|
44
TestFramework/example7.m
Normal file
44
TestFramework/example7.m
Normal file
|
@ -0,0 +1,44 @@
|
|||
#import <ObjectTesting.h>
|
||||
|
||||
/* A seventh test ... nesting sets.
|
||||
*
|
||||
* If you run the test with 'gnustep-tests example7.m' it should
|
||||
* report a single test file completed, one test fail, two test passes,
|
||||
* and one set unresolved.
|
||||
*/
|
||||
int
|
||||
main()
|
||||
{
|
||||
/* Start a set.
|
||||
*/
|
||||
START_SET(YES)
|
||||
|
||||
/* Our first test in this set will pass.
|
||||
*/
|
||||
PASS(1 == 1, "integer equality works")
|
||||
|
||||
/* Now we start a set nested inside the first one.
|
||||
*/
|
||||
START_SET(YES)
|
||||
|
||||
/* And we say we need a test to pass, but it's actually a faulty one
|
||||
* which will fail, causing the set to be terminated.
|
||||
*/
|
||||
NEED(PASS_EQUAL(@"hello", @"there", "faulty string equality test"))
|
||||
|
||||
/* Heres a correct string equality test, but it's never reached because
|
||||
* the earlier test was needed.
|
||||
*/
|
||||
PASS_EQUAL(@"there", @"there", "NSString equality works")
|
||||
|
||||
END_SET("inner set")
|
||||
|
||||
/* And here's another correct test which *is* reached because it's
|
||||
* in a different set.
|
||||
*/
|
||||
PASS_EQUAL(@"there", @"there", "NSString equality works")
|
||||
|
||||
END_SET("outer set")
|
||||
|
||||
return 0;
|
||||
}
|
208
TestFramework/gnustep-tests
Executable file
208
TestFramework/gnustep-tests
Executable file
|
@ -0,0 +1,208 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Runs tests for the GNUstep Testsuite
|
||||
#
|
||||
# Copyright (C) 2005-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
# Updates by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
#
|
||||
# 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 3 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.
|
||||
#
|
||||
#
|
||||
# Usage: gnustep-tests [directory | test1.m [test2.m ...]]
|
||||
#
|
||||
# Runs the tests in the specified directory (or those in the individual files)
|
||||
# or all the tests in subdirectories of the current directory if no arguments
|
||||
# are given.
|
||||
# A summary is written to tests.sum, a log to tests.log, and a brief
|
||||
# summary to stdout.
|
||||
# The log and summary from the previous testrun are renamed to
|
||||
# oldtests.log and oldtests.sum, available for comparison.
|
||||
|
||||
if test -z "$GNUSTEP_MAKEFILES"; then
|
||||
GNUSTEP_MAKEFILES=`gnustep-config --variable=GNUSTEP_MAKEFILES 2>/dev/null`
|
||||
if test -z "$GNUSTEP_MAKEFILES"; then
|
||||
echo "You need to have GNUstep-make installed and set up."
|
||||
echo "Did you remember to source GNUstep.sh?"
|
||||
else
|
||||
export GNUSTEP_MAKEFILES
|
||||
. $GNUSTEP_MAKEFILES/GNUstep.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
# Argument checking
|
||||
while test $# != 0
|
||||
do
|
||||
gs_option=
|
||||
case $1 in
|
||||
--help | -h)
|
||||
echo
|
||||
echo "$0: Script to run the GNUstep testsuite"
|
||||
echo "Usage: gnustep-tests [directory | test1.m [test2.m ...]]"
|
||||
echo "Runs the specified tests, or any in subdirectoried of the"
|
||||
echo "current directory if no arguments are given."
|
||||
echo
|
||||
echo "Interpreting the output"
|
||||
echo "-----------------------"
|
||||
echo "The summary output lists all test failures ... there should not"
|
||||
echo "be any. If a test fails then either there is a problem in the"
|
||||
echo "software being tested, or a problem in the test itsself. Either"
|
||||
echo "way, you should try to fix the problem and provide a patch, or"
|
||||
echo "at least report it at: https://savannah.gnu.org/bugs/?group=gnustep"
|
||||
echo
|
||||
echo "After the listing of any failures is a summary of counts of events:"
|
||||
echo "COMPLETED: The number of separate test files which were run."
|
||||
echo "COMPILEFAIL: The number of separate test files which failed to run."
|
||||
echo "DASHED: The number of hopes dashed ... tests which did not"
|
||||
echo " pass, but which were not expected to pass (known"
|
||||
echo " bugs etc)."
|
||||
echo "FAIL: The number of individual tests failed"
|
||||
echo "PASS: The number of individual tests passed"
|
||||
echo "UNRESOLVED: The number of unresolved tests ... tests which have"
|
||||
echo " been omitted because of an earlier failure etc."
|
||||
echo "UNSUPPORTED: The number of unsupported tests ... those for features"
|
||||
echo " which work on some platforms, but not on yours."
|
||||
echo
|
||||
exit 0
|
||||
;;
|
||||
--debug | -d) # ignore for backward compatibility.
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ ! "$MAKE_CMD" ]
|
||||
then
|
||||
gmake --version > /dev/null 2>&1
|
||||
if [ $? = 0 ]
|
||||
then
|
||||
MAKE_CMD=gmake
|
||||
else
|
||||
MAKE_CMD=make
|
||||
fi
|
||||
fi
|
||||
export MAKE_CMD
|
||||
TEMP=`echo *`
|
||||
TESTDIRS=
|
||||
for file in $TEMP
|
||||
do
|
||||
if [ -d $file -a $file != CVS -a $file != obj ]
|
||||
then
|
||||
TESTDIRS="$TESTDIRS $file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ x$1 != x ]
|
||||
then
|
||||
if [ -d $1 ]
|
||||
then
|
||||
# Only find in the directories specified.
|
||||
TESTDIRS=$*
|
||||
else
|
||||
TESTDIRS=
|
||||
TESTS=$*
|
||||
fi
|
||||
fi
|
||||
|
||||
CWD=`pwd`
|
||||
TOP=$GNUSTEP_MAKEFILES/TestFramework
|
||||
export TOP
|
||||
RUNCMD=$TOP/runtest.sh
|
||||
cd $CWD
|
||||
|
||||
run_test_file ()
|
||||
{
|
||||
echo >> $CWD/tests.log
|
||||
echo Testing $TESTFILE... >> $CWD/tests.log
|
||||
echo >> $CWD/tests.sum
|
||||
|
||||
# Run the test. Log everything to a temporary file.
|
||||
$RUNCMD $run_args $TESTFILE > $CWD/tests.tmp 2>&1
|
||||
|
||||
# Add the information to the detailed log.
|
||||
cat $CWD/tests.tmp >> $CWD/tests.log
|
||||
|
||||
# Extract the summary information and add it to the summary file.
|
||||
grep "^\(PASS\|FAIL\|COMPILEFAIL\|COMPLETED\|DASHED\|UNRESOLVED\|UNSUPPORTED\)" $CWD/tests.tmp > $CWD/tests.sum.tmp
|
||||
cat $CWD/tests.sum.tmp >> $CWD/tests.sum
|
||||
|
||||
# If there were failures or unresolved tests then report them...
|
||||
if grep -L "^\(COMPILEFAIL\|FAIL\|UNRESOLVED\)" $CWD/tests.sum.tmp > /dev/null; then
|
||||
echo
|
||||
echo $TESTFILE:
|
||||
grep "^\(COMPILEFAIL\|FAIL\|UNRESOLVED\)" $CWD/tests.sum.tmp
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Delete the old files.
|
||||
if [ -f tests.log ]
|
||||
then
|
||||
mv tests.log oldtests.log
|
||||
fi
|
||||
if [ -f tests.sum ]
|
||||
then
|
||||
mv tests.sum oldtests.sum
|
||||
fi
|
||||
|
||||
if [ x"$TESTDIRS" = x ]
|
||||
then
|
||||
# I think we should depreciate this part, but for now...
|
||||
for TESTFILE in $TESTS
|
||||
do
|
||||
run_test_file
|
||||
done
|
||||
else
|
||||
for dir in $TESTDIRS
|
||||
do
|
||||
echo "--- Running tests in $dir ---"
|
||||
TESTS=`find $dir -name \*.m | sort | sed -e 's/\(^\| \)X[^ ]*//g'`
|
||||
# If there is a GNUmakefile.tests in the directory, run it first.
|
||||
# Unless ... we are at the top level, in which case that file is
|
||||
# our template.
|
||||
cd $dir
|
||||
if [ $TOP != `pwd` ]
|
||||
then
|
||||
if [ -f GNUmakefile.tests ]
|
||||
then
|
||||
$MAKE_CMD -f GNUmakefile.tests $MAKEFLAGS debug=yes 2>&1
|
||||
fi
|
||||
fi
|
||||
cd $CWD
|
||||
for TESTFILE in $TESTS
|
||||
do
|
||||
run_test_file
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
# Make some stats.
|
||||
if [ -r tests.sum ]
|
||||
then
|
||||
grep "^[A-Z]*:" tests.sum | cut -d: -f1 | sort | uniq -c > tests.tmp
|
||||
else
|
||||
echo "No tests found." > tests.tmp
|
||||
fi
|
||||
|
||||
echo >> tests.sum
|
||||
cat tests.tmp >> tests.sum
|
||||
|
||||
echo
|
||||
cat tests.tmp
|
||||
|
||||
|
||||
# Delete the temporary file.
|
||||
rm -f tests.tmp tests.sum.tmp
|
||||
|
185
TestFramework/runtest.sh
Executable file
185
TestFramework/runtest.sh
Executable file
|
@ -0,0 +1,185 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# run tests script for the GNUstep Testsuite
|
||||
#
|
||||
# Copyright (C) 2005-2011 Free Software Foundation, Inc.
|
||||
#
|
||||
# Written by: Alexander Malmberg <alexander@malmberg.org>
|
||||
# Updated by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||
#
|
||||
# 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 3 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.
|
||||
#
|
||||
#
|
||||
# Usage: ./runtest.sh test_name.m
|
||||
#
|
||||
# Compiles and runs the test test_name. Detailed logging should go to stdout;
|
||||
# only summary information should go to stderr.
|
||||
|
||||
USEDEBUG=YES
|
||||
# Argument checking
|
||||
while test $# != 0
|
||||
do
|
||||
gs_option=
|
||||
case $1 in
|
||||
--help | -h)
|
||||
echo "$0: Script to run a test a GNUstep testsuite program"
|
||||
echo "Usage: ./runtest.sh test_name.m"
|
||||
echo "Options:"
|
||||
echo " --help - Print help"
|
||||
echo
|
||||
exit 0
|
||||
;;
|
||||
--debug | -d) # ignore for backward compatibility
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ x$1 = x ]
|
||||
then
|
||||
echo "ERROR: $0: No test given"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# != 1 ]
|
||||
then
|
||||
echo "ERROR: $0: Too many arguments (single test file name expected)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -e $1 ]
|
||||
then
|
||||
|
||||
if [ ! -f $1 ]
|
||||
then
|
||||
echo "ERROR: $0: Argument ($1) is not the name of a regular file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -r $1 ]
|
||||
then
|
||||
echo "ERROR: $0: Test file ($1) is not readable by you"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
else
|
||||
echo "ERROR: $0: Test file ($1) does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$GNUSTEP_MAKEFILES"; then
|
||||
GNUSTEP_MAKEFILES=`gnustep-config --variable=GNUSTEP_MAKEFILES 2>/dev/null`
|
||||
if test -z "$GNUSTEP_MAKEFILES"; then
|
||||
echo "You need to have GNUstep-make installed and set up."
|
||||
echo "Did you remember to source GNUstep.sh?"
|
||||
else
|
||||
. $GNUSTEP_MAKEFILES/GNUstep.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
# Move to the test's directory.
|
||||
DIR=`dirname $1`
|
||||
if [ ! -d $DIR ]; then
|
||||
echo "Unable to proceed ... $DIR is not a directory"
|
||||
exit 1
|
||||
fi
|
||||
cd $DIR
|
||||
DIR=`pwd`
|
||||
# Check that we are not in the top level ... where creating a GNUmakefile
|
||||
# would trash an existing makefile.
|
||||
if [ -f GNUmakefile ]; then
|
||||
echo "Unable to proceed ... a GNUmakefile already exsts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! "$MAKE_CMD" ]
|
||||
then
|
||||
MAKE_CMD=gmake
|
||||
$MAKE_CMD --version > /dev/null 2>&1
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
MAKE_CMD=make
|
||||
fi
|
||||
fi
|
||||
|
||||
NAME=`basename $1`
|
||||
|
||||
if [ ! -f IGNORE ]
|
||||
then
|
||||
# Remove the extension, if there is one. If there is no extension, add
|
||||
# .obj .
|
||||
TESTNAME=`echo $NAME | sed -e"s/^\([^.]*\)$/\1.obj./;s/\.[^.]*//g"`
|
||||
|
||||
# Check for a custom makefile, if it exists use it.
|
||||
if [ -r Custom.mk ]
|
||||
then
|
||||
if [ $NAME = "Custom.mk" ]
|
||||
then
|
||||
echo "include Custom.mk" >>GNUmakefile
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
# Create the GNUmakefile by filling in the name of the test.
|
||||
sed -e "s/@TESTNAME@/$TESTNAME/;s/@FILENAME@/$NAME/;s^@INCLUDEDIR@^$TOP^" < $TOP/GNUmakefile.in > GNUmakefile
|
||||
fi
|
||||
|
||||
# Clean up to avoid contamination by previous tests. (Optimistically) assume
|
||||
# that this will never fail in any interesting way.
|
||||
$MAKE_CMD clean >/dev/null 2>&1
|
||||
|
||||
# Compile it. Redirect errors to stdout so it shows up in the log, but not
|
||||
# in the summary.
|
||||
$MAKE_CMD $MAKEFLAGS messages=yes debug=yes 2>&1
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo COMPILEFAIL: $1 >&2
|
||||
else
|
||||
# We want aggressive memory checking.
|
||||
|
||||
# Tell glibc to check for malloc errors, and to crash if it detects
|
||||
# any.
|
||||
MALLOC_CHECK_=2
|
||||
export MALLOC_CHECK
|
||||
|
||||
# Tell GNUstep-base to check for messages sent to deallocated objects
|
||||
# and crash if it happens.
|
||||
NSZombieEnabled=YES
|
||||
CRASH_ON_ZOMBIE=YES
|
||||
export NSZombieEnabled CRASH_ON_ZOMBIE
|
||||
|
||||
echo Running $1...
|
||||
# Run it. If it terminates abnormally, mark it as a crash (unless we have
|
||||
# a special file to mark it as being expected to abort).
|
||||
$MAKE_CMD -s test
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
if [ -r $NAME.abort ]
|
||||
then
|
||||
echo COMPLETED: $1 >&2
|
||||
else
|
||||
echo FAIL: $1 >&2
|
||||
fi
|
||||
else
|
||||
echo COMPLETED: $1 >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f GNUmakefile
|
||||
|
||||
# Clean up to avoid contaminating later tests. (Optimistically) assume that
|
||||
# this will never fail in any interesting way.
|
||||
rm -f core
|
||||
#$MAKE_CMD clean >/dev/null 2>&1
|
||||
fi
|
Loading…
Reference in a new issue