catch2/include/internal/catch_objc.hpp

189 lines
5.6 KiB
C++
Raw Normal View History

2010-11-14 23:47:30 +01:00
/*
* catch_objc.hpp
2011-02-08 09:42:05 +01:00
* Catch
2010-11-14 23:47:30 +01:00
*
* Created by Phil on 14/11/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
2012-02-10 09:28:37 +01:00
#import <Foundation/Foundation.h>
2010-11-14 23:47:30 +01:00
#import <objc/runtime.h>
2012-02-10 09:28:37 +01:00
2010-11-14 23:47:30 +01:00
#include <string>
2011-04-26 09:32:40 +02:00
// NB. Any general catch headers included here must be included
// in catch.hpp first to make sure they are included by the single
// header for non obj-usage
#include "internal/catch_test_case_info.hpp"
2010-11-14 23:47:30 +01:00
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////////////
// This protocol is really only here for (self) documenting purposes, since
// all its methods are optional.
2010-11-16 08:00:08 +01:00
@protocol OcFixture
@optional
-(void) setUp;
-(void) tearDown;
@end
2010-11-14 23:47:30 +01:00
namespace Catch
{
class OcMethod : public ITestCase
2010-11-14 23:47:30 +01:00
{
public:
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
OcMethod
(
Class cls,
SEL sel
)
: m_cls( cls ),
m_sel( sel )
2010-11-14 23:47:30 +01:00
{
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
virtual void invoke
()
const
2010-11-14 23:47:30 +01:00
{
2010-11-16 08:00:08 +01:00
id obj = class_createInstance( m_cls, 0 );
obj = [obj init];
if( [obj respondsToSelector: @selector(setUp) ] )
[obj performSelector: @selector(setUp)];
2010-11-14 23:47:30 +01:00
if( [obj respondsToSelector: m_sel] )
[obj performSelector: m_sel];
2010-11-16 08:00:08 +01:00
if( [obj respondsToSelector: @selector(tearDown) ] )
[obj performSelector: @selector(tearDown)];
2010-11-14 23:47:30 +01:00
[obj release];
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
virtual ITestCase* clone
()
const
2010-11-14 23:47:30 +01:00
{
2010-11-16 08:00:08 +01:00
return new OcMethod( m_cls, m_sel );
2010-11-14 23:47:30 +01:00
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
virtual bool operator ==
(
const ITestCase& other
)
const
2010-11-14 23:47:30 +01:00
{
const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
return ocmOther && ocmOther->m_sel == m_sel;
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
virtual bool operator <
(
const ITestCase& other
)
const
2010-11-14 23:47:30 +01:00
{
const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
return ocmOther && ocmOther->m_sel < m_sel;
}
private:
2010-11-16 08:00:08 +01:00
Class m_cls;
2010-11-14 23:47:30 +01:00
SEL m_sel;
};
2010-11-16 08:00:08 +01:00
namespace Detail
2010-11-14 23:47:30 +01:00
{
2010-11-16 08:00:08 +01:00
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
inline bool startsWith
(
const std::string& str,
const std::string& sub
)
2010-11-14 23:47:30 +01:00
{
return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////
inline const char* getAnnotation
(
Class cls,
const std::string& annotationName,
const std::string& testCaseName
)
2010-11-14 23:47:30 +01:00
{
NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
SEL sel = NSSelectorFromString( selStr );
[selStr release];
2010-11-16 08:00:08 +01:00
if( [cls respondsToSelector: sel] )
return (const char*)[cls performSelector: sel];
2010-11-14 23:47:30 +01:00
return "";
}
2010-11-16 08:00:08 +01:00
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////////
inline size_t registerTestMethods
()
2010-11-16 08:00:08 +01:00
{
size_t noTestMethods = 0;
int noClasses = objc_getClassList( NULL, 0 );
std::vector<Class> classes( noClasses );
objc_getClassList( &classes[0], noClasses );
2010-11-14 23:47:30 +01:00
2010-11-16 08:00:08 +01:00
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 );
const char* name = Detail::getAnnotation( cls, "Name", testCaseName );
const char* desc = Detail::getAnnotation( cls, "Description", testCaseName );
2010-11-16 08:00:08 +01:00
2011-04-26 09:32:40 +02:00
Hub::getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name, desc, "", 0 ) );
2010-11-16 08:00:08 +01:00
noTestMethods++;
}
}
free(methods);
}
}
return noTestMethods;
}
2010-11-14 23:47:30 +01:00
}
2011-02-08 09:42:05 +01:00
///////////////////////////////////////////////////////////////////////////////
2010-11-14 23:47:30 +01:00
#define OC_TEST_CASE( name, desc )\
+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
{\
return name; \
}\
+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
{ \
return desc; \
} \
-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED