From f59ecbcad6f33210af9d2a8f1de20bc94eba89a0 Mon Sep 17 00:00:00 2001 From: Phil Nash Date: Tue, 16 Nov 2010 07:00:08 +0000 Subject: [PATCH] Auto registers OC Classes --- Test/Xcode/OCTest/CatchOCTestCase.h | 9 +-- Test/Xcode/OCTest/CatchOCTestCase.mm | 12 +--- Test/Xcode/OCTest/Main.mm | 3 + catch_objc.hpp | 100 +++++++++++++++++---------- 4 files changed, 71 insertions(+), 53 deletions(-) diff --git a/Test/Xcode/OCTest/CatchOCTestCase.h b/Test/Xcode/OCTest/CatchOCTestCase.h index 4eda8c28..da6048f3 100644 --- a/Test/Xcode/OCTest/CatchOCTestCase.h +++ b/Test/Xcode/OCTest/CatchOCTestCase.h @@ -11,14 +11,9 @@ #import #import "TestObj.h" -@interface TestFixture : NSObject +@interface TestFixture : NSObject { TestObj* obj; } -@end - - - -CATCH_REGISTER_CLASS( TestFixture ) - +@end \ No newline at end of file diff --git a/Test/Xcode/OCTest/CatchOCTestCase.mm b/Test/Xcode/OCTest/CatchOCTestCase.mm index da4be833..8398d1ad 100644 --- a/Test/Xcode/OCTest/CatchOCTestCase.mm +++ b/Test/Xcode/OCTest/CatchOCTestCase.mm @@ -12,20 +12,14 @@ @implementation TestFixture -- (id) init +-(void) setUp { - self = [super init]; - if (self != nil) - { - obj = [[TestObj alloc] init]; - } - return self; + obj = [[TestObj alloc] init]; } -- (void) dealloc +-(void) tearDown { [obj release]; - [super dealloc]; } OC_TEST_CASE( "OCTest/test1", "This is a test case" ) diff --git a/Test/Xcode/OCTest/Main.mm b/Test/Xcode/OCTest/Main.mm index 47a37e3e..d0d77407 100644 --- a/Test/Xcode/OCTest/Main.mm +++ b/Test/Xcode/OCTest/Main.mm @@ -3,9 +3,12 @@ #import "CatchOCTestCase.h" + int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + Catch::registerTestMethods(); + // insert code here... int result = Catch::Main( argc, (char* const*)argv ); diff --git a/catch_objc.hpp b/catch_objc.hpp index 5c2d7d01..9a92c31d 100644 --- a/catch_objc.hpp +++ b/catch_objc.hpp @@ -17,27 +17,44 @@ #include #include "catch.hpp" +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + namespace Catch { - template class OcMethod : public TestCase { public: - OcMethod( SEL sel ) : m_sel( sel ) + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) { } 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] ) [obj performSelector: m_sel]; + + if( [obj respondsToSelector: @selector(tearDown) ] ) + [obj performSelector: @selector(tearDown)]; + [obj release]; } virtual TestCase* clone() const { - return new OcMethod( m_sel ); + return new OcMethod( m_cls, m_sel ); } virtual bool operator == ( const TestCase& other ) const @@ -53,56 +70,65 @@ namespace Catch } private: - + Class m_cls; SEL m_sel; }; - template - struct OcAutoReg + namespace Detail { - OcAutoReg() - { - u_int count; - Method* methods = class_copyMethodList([T class], &count); - - for( int i = 0; i < count ; i++ ) - { - 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( selector ), name, desc ) ); - - } - } - free(methods); - } - - private: - bool startsWith( const std::string& str, const std::string& sub ) + + inline bool startsWith( const std::string& str, const std::string& 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()]; SEL sel = NSSelectorFromString( selStr ); [selStr release]; - if( [[T class] respondsToSelector: sel] ) - return (const char*)[[T class] performSelector: sel]; + if( [cls respondsToSelector: sel] ) + return (const char*)[cls performSelector: sel]; return ""; } + } + + inline size_t registerTestMethods() + { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( NULL, 0 ); - }; + std::vector 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 reg; } - #define OC_TEST_CASE( name, desc )\ +(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ {\