Index: src/test/Makefile ================================================================== --- src/test/Makefile +++ src/test/Makefile @@ -7,14 +7,16 @@ FRAMEWORK = ${OBJFWTEST_FRAMEWORK} LIB_MAJOR = ${OBJFWTEST_LIB_MAJOR} LIB_MINOR = ${OBJFWTEST_LIB_MINOR} LIB_PATCH = ${OBJFWTEST_LIB_PATCH} -SRCS = OTTestCase.m +SRCS = OTAssert.m \ + OTTestCase.m INCLUDES := ${SRCS:.m=.h} \ ObjFWTest.h -SRCS += OTAppDelegate.m +SRCS += OTAppDelegate.m \ + OTAssertionFailedException.m includesubdir = ObjFWTest include ../../buildsys.mk Index: src/test/OTAppDelegate.m ================================================================== --- src/test/OTAppDelegate.m +++ src/test/OTAppDelegate.m @@ -20,10 +20,12 @@ #import "OFSet.h" #import "OFValue.h" #import "OTTestCase.h" +#import "OTAssertionFailedException.h" + OF_APPLICATION_DELEGATE(OTAppDelegate) @implementation OTAppDelegate - (OFSet OF_GENERIC(Class) *)testClasses { @@ -86,16 +88,32 @@ for (OFValue *test in [self testsInClass: class]) { void *pool = objc_autoreleasePoolPush(); OTTestCase *instance = [[[class alloc] init] autorelease]; - [instance setUp]; - [instance performSelector: test.pointerValue]; - [instance tearDown]; + @try { + [instance setUp]; + [instance performSelector: test.pointerValue]; + } @catch (OTAssertionFailedException *e) { + /* + * If an assertion during -[setUp], don't run + * the test. + * If an assertion fails during a test, abort + * the test. + */ + } + @try { + [instance tearDown]; + } @catch (OTAssertionFailedException *e) { + /* + * If an assertion fails during -[tearDown], + * abort the tear down. + */ + } objc_autoreleasePoolPop(pool); } } [OFApplication terminate]; } @end ADDED src/test/OTAssert.h Index: src/test/OTAssert.h ================================================================== --- src/test/OTAssert.h +++ src/test/OTAssert.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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. + */ + +#define OTAssert(cond, ...) \ + OTAssertImpl(self, _cmd, cond, @#cond, @__FILE__, __LINE__, \ + ## __VA_ARGS__, nil) +#define OTAssertTrue(cond, ...) OTAssert(cond == true, ## __VA_ARGS__) +#define OTAssertFalse(cond, ...) OTAssert(cond == false, ## __VA_ARGS__) +#define OTAssertEqual(a, b, ...) OTAssert(a == b, ## __VA_ARGS__) +#define OTAssertNotEqual(a, b, ...) OTAssert(a != b, ## __VA_ARGS__) +#define OTAssertEqualObjects(a, b, ...) OTAssert([a isEqual: b], ## __VA_ARGS__) +#define OTAssertNotEqualObjects(a, b, ...) \ + OTAssert(![a isEqual: b], ## __VA_ARGS__) + +#ifdef __cplusplus +extern "C" { +#endif +extern void OTAssertImpl(id testCase, SEL test, bool condition, OFString *check, + OFString *file, size_t line, ...); +#ifdef __cplusplus +} +#endif ADDED src/test/OTAssert.m Index: src/test/OTAssert.m ================================================================== --- src/test/OTAssert.m +++ src/test/OTAssert.m @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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 "OFColor.h" +#import "OFStdIOStream.h" +#import "OFString.h" + +#import "OTAssertionFailedException.h" + +void +OTAssertImpl(id testCase, SEL test, bool condition, OFString *check, + OFString *file, size_t line, ...) +{ + void *pool; + va_list arguments; + OFConstantString *format; + OFString *message = nil; + + if (condition) + return; + + pool = objc_autoreleasePoolPush(); + + va_start(arguments, line); + format = va_arg(arguments, OFConstantString *); + + if (format != nil) + message = [[[OFString alloc] + initWithFormat: format + arguments: arguments] autorelease]; + + va_end(arguments); + + [OFStdErr setForegroundColor: [OFColor red]]; + [OFStdErr writeFormat: @"-[%@ %s]: Condition failed: %@%@%@\n", + [testCase className], sel_getName(test), + check, (message != nil ? @": " : @""), + (message != nil ? message : @"")]; + [OFStdErr reset]; + + objc_autoreleasePoolPop(pool); + + @throw [OTAssertionFailedException exception]; +} ADDED src/test/OTAssertionFailedException.h Index: src/test/OTAssertionFailedException.h ================================================================== --- src/test/OTAssertionFailedException.h +++ src/test/OTAssertionFailedException.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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. + */ + +#import "OFException.h" + +@interface OTAssertionFailedException: OFException +@end ADDED src/test/OTAssertionFailedException.m Index: src/test/OTAssertionFailedException.m ================================================================== --- src/test/OTAssertionFailedException.m +++ src/test/OTAssertionFailedException.m @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * 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 "OTAssertionFailedException.h" + +@implementation OTAssertionFailedException +@end Index: src/test/OTTestCase.h ================================================================== --- src/test/OTTestCase.h +++ src/test/OTTestCase.h @@ -19,14 +19,11 @@ # import #endif OF_ASSUME_NONNULL_BEGIN -/** - * @class OTTestCase OTTestCase.h ObjFWTest/OTTestCase.h - */ @interface OTTestCase: OFObject - (void)setUp; - (void)tearDown; @end OF_ASSUME_NONNULL_END Index: src/test/ObjFWTest.h ================================================================== --- src/test/ObjFWTest.h +++ src/test/ObjFWTest.h @@ -12,5 +12,6 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OTTestCase.h" +#import "OTAssert.h"