mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 21:36:11 +01:00
Auto registers OC Classes
This commit is contained in:
parent
d52f61cc67
commit
f59ecbcad6
@ -11,14 +11,9 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "TestObj.h"
|
#import "TestObj.h"
|
||||||
|
|
||||||
@interface TestFixture : NSObject
|
@interface TestFixture : NSObject <OcFixture>
|
||||||
{
|
{
|
||||||
TestObj* obj;
|
TestObj* obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CATCH_REGISTER_CLASS( TestFixture )
|
|
||||||
|
|
||||||
|
@ -12,20 +12,14 @@
|
|||||||
@implementation TestFixture
|
@implementation TestFixture
|
||||||
|
|
||||||
|
|
||||||
- (id) init
|
-(void) setUp
|
||||||
{
|
{
|
||||||
self = [super init];
|
obj = [[TestObj alloc] init];
|
||||||
if (self != nil)
|
|
||||||
{
|
|
||||||
obj = [[TestObj alloc] init];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) dealloc
|
-(void) tearDown
|
||||||
{
|
{
|
||||||
[obj release];
|
[obj release];
|
||||||
[super dealloc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OC_TEST_CASE( "OCTest/test1", "This is a test case" )
|
OC_TEST_CASE( "OCTest/test1", "This is a test case" )
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
#import "CatchOCTestCase.h"
|
#import "CatchOCTestCase.h"
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, const char * argv[]) {
|
int main (int argc, const char * argv[]) {
|
||||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
Catch::registerTestMethods();
|
||||||
|
|
||||||
// insert code here...
|
// insert code here...
|
||||||
int result = Catch::Main( argc, (char* const*)argv );
|
int result = Catch::Main( argc, (char* const*)argv );
|
||||||
|
|
||||||
|
@ -17,27 +17,44 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
@protocol OcFixture
|
||||||
|
|
||||||
|
@optional
|
||||||
|
|
||||||
|
-(void) setUp;
|
||||||
|
-(void) tearDown;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
namespace Catch
|
namespace Catch
|
||||||
{
|
{
|
||||||
template<typename T>
|
|
||||||
class OcMethod : public TestCase
|
class OcMethod : public TestCase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OcMethod( SEL sel ) : m_sel( sel )
|
OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invoke() const
|
virtual void invoke() const
|
||||||
{
|
{
|
||||||
T* obj = [[T alloc] init];
|
id obj = class_createInstance( m_cls, 0 );
|
||||||
|
obj = [obj init];
|
||||||
|
|
||||||
|
if( [obj respondsToSelector: @selector(setUp) ] )
|
||||||
|
[obj performSelector: @selector(setUp)];
|
||||||
|
|
||||||
if( [obj respondsToSelector: m_sel] )
|
if( [obj respondsToSelector: m_sel] )
|
||||||
[obj performSelector: m_sel];
|
[obj performSelector: m_sel];
|
||||||
|
|
||||||
|
if( [obj respondsToSelector: @selector(tearDown) ] )
|
||||||
|
[obj performSelector: @selector(tearDown)];
|
||||||
|
|
||||||
[obj release];
|
[obj release];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual TestCase* clone() const
|
virtual TestCase* clone() const
|
||||||
{
|
{
|
||||||
return new OcMethod<T>( m_sel );
|
return new OcMethod( m_cls, m_sel );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator == ( const TestCase& other ) const
|
virtual bool operator == ( const TestCase& other ) const
|
||||||
@ -53,56 +70,65 @@ namespace Catch
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Class m_cls;
|
||||||
SEL m_sel;
|
SEL m_sel;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
namespace Detail
|
||||||
struct OcAutoReg
|
|
||||||
{
|
{
|
||||||
OcAutoReg()
|
|
||||||
{
|
|
||||||
u_int count;
|
|
||||||
Method* methods = class_copyMethodList([T class], &count);
|
|
||||||
|
|
||||||
for( int i = 0; i < count ; i++ )
|
inline bool startsWith( const std::string& str, const std::string& sub )
|
||||||
{
|
|
||||||
SEL selector = method_getName(methods[i]);
|
|
||||||
std::string methodName = sel_getName(selector);
|
|
||||||
if( startsWith( methodName, "Catch_TestCase_" ) )
|
|
||||||
{
|
|
||||||
std::string testCaseName = methodName.substr( 15 );
|
|
||||||
std::string name = getAnnotation( "Name", testCaseName );
|
|
||||||
std::string desc = getAnnotation( "Description", testCaseName );
|
|
||||||
|
|
||||||
TestRegistry::instance().registerTest( TestCaseInfo( new OcMethod<T>( selector ), name, desc ) );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool startsWith( const std::string& str, const std::string& sub )
|
|
||||||
{
|
{
|
||||||
return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
|
return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getAnnotation( const std::string& annotationName, const std::string& testCaseName )
|
inline const char* getAnnotation( Class cls, const std::string& annotationName, const std::string& testCaseName )
|
||||||
{
|
{
|
||||||
NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
|
NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
|
||||||
SEL sel = NSSelectorFromString( selStr );
|
SEL sel = NSSelectorFromString( selStr );
|
||||||
[selStr release];
|
[selStr release];
|
||||||
if( [[T class] respondsToSelector: sel] )
|
if( [cls respondsToSelector: sel] )
|
||||||
return (const char*)[[T class] performSelector: sel];
|
return (const char*)[cls performSelector: sel];
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
inline size_t registerTestMethods()
|
||||||
|
{
|
||||||
|
size_t noTestMethods = 0;
|
||||||
|
int noClasses = objc_getClassList( NULL, 0 );
|
||||||
|
|
||||||
|
std::vector<Class> classes( noClasses );
|
||||||
|
objc_getClassList( &classes[0], noClasses );
|
||||||
|
|
||||||
|
for( int c = 0; c < noClasses; c++ )
|
||||||
|
{
|
||||||
|
Class cls = classes[c];
|
||||||
|
{
|
||||||
|
u_int count;
|
||||||
|
Method* methods = class_copyMethodList( cls, &count );
|
||||||
|
for( int m = 0; m < count ; m++ )
|
||||||
|
{
|
||||||
|
SEL selector = method_getName(methods[m]);
|
||||||
|
std::string methodName = sel_getName(selector);
|
||||||
|
if( Detail::startsWith( methodName, "Catch_TestCase_" ) )
|
||||||
|
{
|
||||||
|
std::string testCaseName = methodName.substr( 15 );
|
||||||
|
std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
|
||||||
|
std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
|
||||||
|
|
||||||
|
TestRegistry::instance().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name, desc ) );
|
||||||
|
noTestMethods++;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(methods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return noTestMethods;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CATCH_REGISTER_CLASS( className ) namespace{ Catch::OcAutoReg<className> reg; }
|
|
||||||
|
|
||||||
#define OC_TEST_CASE( name, desc )\
|
#define OC_TEST_CASE( name, desc )\
|
||||||
+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
|
+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
|
||||||
{\
|
{\
|
||||||
|
Loading…
Reference in New Issue
Block a user