blob: eab0852232a488f97c3b80920aaf4035f786cd9d [file] [log] [blame]
Phil Nashd52f61c2010-11-14 22:47:30 +00001/*
2 * catch_objc.hpp
Phil Nash58e9a8b2011-02-08 08:42:05 +00003 * Catch
Phil Nashd52f61c2010-11-14 22:47:30 +00004 *
5 * Created by Phil on 14/11/2010.
6 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
7 *
8 * Distributed under the Boost Software License, Version 1.0. (See accompanying
9 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 *
11 */
12
13#ifndef TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
14#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
15
16#import <objc/runtime.h>
17#include <string>
Phil Nash823ea3e2011-04-26 08:32:40 +010018
Phil Nash89d1e6c2011-05-24 08:23:02 +010019// NB. Any general catch headers included here must be included
20// in catch.hpp first to make sure they are included by the single
21// header for non obj-usage
Phil Nash0847a0f2011-02-01 16:09:18 +000022#include "internal/catch_test_case_info.hpp"
Phil Nashd52f61c2010-11-14 22:47:30 +000023
Phil Nash58e9a8b2011-02-08 08:42:05 +000024///////////////////////////////////////////////////////////////////////////////
25// This protocol is really only here for (self) documenting purposes, since
26// all its methods are optional.
Phil Nashf59ecbc2010-11-16 07:00:08 +000027@protocol OcFixture
28
29@optional
30
31-(void) setUp;
32-(void) tearDown;
33
34@end
35
Phil Nashd52f61c2010-11-14 22:47:30 +000036namespace Catch
37{
Phil Nash0847a0f2011-02-01 16:09:18 +000038 class OcMethod : public ITestCase
Phil Nashd52f61c2010-11-14 22:47:30 +000039 {
40 public:
Phil Nash58e9a8b2011-02-08 08:42:05 +000041 ///////////////////////////////////////////////////////////////////////
42 OcMethod
43 (
44 Class cls,
45 SEL sel
46 )
47 : m_cls( cls ),
48 m_sel( sel )
Phil Nashd52f61c2010-11-14 22:47:30 +000049 {
50 }
51
Phil Nash58e9a8b2011-02-08 08:42:05 +000052 ///////////////////////////////////////////////////////////////////////
53 virtual void invoke
54 ()
55 const
Phil Nashd52f61c2010-11-14 22:47:30 +000056 {
Phil Nashf59ecbc2010-11-16 07:00:08 +000057 id obj = class_createInstance( m_cls, 0 );
58 obj = [obj init];
59
60 if( [obj respondsToSelector: @selector(setUp) ] )
61 [obj performSelector: @selector(setUp)];
62
Phil Nashd52f61c2010-11-14 22:47:30 +000063 if( [obj respondsToSelector: m_sel] )
64 [obj performSelector: m_sel];
Phil Nashf59ecbc2010-11-16 07:00:08 +000065
66 if( [obj respondsToSelector: @selector(tearDown) ] )
67 [obj performSelector: @selector(tearDown)];
68
Phil Nashd52f61c2010-11-14 22:47:30 +000069 [obj release];
70 }
71
Phil Nash58e9a8b2011-02-08 08:42:05 +000072 ///////////////////////////////////////////////////////////////////////
73 virtual ITestCase* clone
74 ()
75 const
Phil Nashd52f61c2010-11-14 22:47:30 +000076 {
Phil Nashf59ecbc2010-11-16 07:00:08 +000077 return new OcMethod( m_cls, m_sel );
Phil Nashd52f61c2010-11-14 22:47:30 +000078 }
79
Phil Nash58e9a8b2011-02-08 08:42:05 +000080 ///////////////////////////////////////////////////////////////////////
81 virtual bool operator ==
82 (
83 const ITestCase& other
84 )
85 const
Phil Nashd52f61c2010-11-14 22:47:30 +000086 {
87 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
88 return ocmOther && ocmOther->m_sel == m_sel;
89 }
90
Phil Nash58e9a8b2011-02-08 08:42:05 +000091 ///////////////////////////////////////////////////////////////////////
92 virtual bool operator <
93 (
94 const ITestCase& other
95 )
96 const
Phil Nashd52f61c2010-11-14 22:47:30 +000097 {
98 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
99 return ocmOther && ocmOther->m_sel < m_sel;
100 }
101
102 private:
Phil Nashf59ecbc2010-11-16 07:00:08 +0000103 Class m_cls;
Phil Nashd52f61c2010-11-14 22:47:30 +0000104 SEL m_sel;
105 };
106
Phil Nashf59ecbc2010-11-16 07:00:08 +0000107 namespace Detail
Phil Nashd52f61c2010-11-14 22:47:30 +0000108 {
Phil Nashf59ecbc2010-11-16 07:00:08 +0000109
Phil Nash58e9a8b2011-02-08 08:42:05 +0000110 ///////////////////////////////////////////////////////////////////////
111 inline bool startsWith
112 (
113 const std::string& str,
114 const std::string& sub
115 )
Phil Nashd52f61c2010-11-14 22:47:30 +0000116 {
117 return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
118 }
119
Phil Nash58e9a8b2011-02-08 08:42:05 +0000120 ///////////////////////////////////////////////////////////////////////
121 inline const char* getAnnotation
122 (
123 Class cls,
124 const std::string& annotationName,
125 const std::string& testCaseName
126 )
Phil Nashd52f61c2010-11-14 22:47:30 +0000127 {
128 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
129 SEL sel = NSSelectorFromString( selStr );
130 [selStr release];
Phil Nashf59ecbc2010-11-16 07:00:08 +0000131 if( [cls respondsToSelector: sel] )
132 return (const char*)[cls performSelector: sel];
Phil Nashd52f61c2010-11-14 22:47:30 +0000133 return "";
134 }
Phil Nashf59ecbc2010-11-16 07:00:08 +0000135 }
136
Phil Nash58e9a8b2011-02-08 08:42:05 +0000137 ///////////////////////////////////////////////////////////////////////////
138 inline size_t registerTestMethods
139 ()
Phil Nashf59ecbc2010-11-16 07:00:08 +0000140 {
141 size_t noTestMethods = 0;
142 int noClasses = objc_getClassList( NULL, 0 );
Phil Nashd52f61c2010-11-14 22:47:30 +0000143
Phil Nashf59ecbc2010-11-16 07:00:08 +0000144 std::vector<Class> classes( noClasses );
145 objc_getClassList( &classes[0], noClasses );
146
147 for( int c = 0; c < noClasses; c++ )
148 {
149 Class cls = classes[c];
150 {
151 u_int count;
152 Method* methods = class_copyMethodList( cls, &count );
153 for( int m = 0; m < count ; m++ )
154 {
155 SEL selector = method_getName(methods[m]);
156 std::string methodName = sel_getName(selector);
157 if( Detail::startsWith( methodName, "Catch_TestCase_" ) )
158 {
159 std::string testCaseName = methodName.substr( 15 );
Phil Nash0847a0f2011-02-01 16:09:18 +0000160 const char* name = Detail::getAnnotation( cls, "Name", testCaseName );
161 const char* desc = Detail::getAnnotation( cls, "Description", testCaseName );
Phil Nashf59ecbc2010-11-16 07:00:08 +0000162
Phil Nash823ea3e2011-04-26 08:32:40 +0100163 Hub::getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name, desc, "", 0 ) );
Phil Nashf59ecbc2010-11-16 07:00:08 +0000164 noTestMethods++;
165
166 }
167 }
168 free(methods);
169 }
170 }
171 return noTestMethods;
172 }
Phil Nashd52f61c2010-11-14 22:47:30 +0000173}
174
Phil Nash58e9a8b2011-02-08 08:42:05 +0000175///////////////////////////////////////////////////////////////////////////////
Phil Nashd52f61c2010-11-14 22:47:30 +0000176#define OC_TEST_CASE( name, desc )\
177+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
178{\
179return name; \
180}\
181+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
182{ \
183return desc; \
184} \
185-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
186
187#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED