blob: d4709acfa2165b5045f3df45a7ed8e64725c6ce0 [file] [log] [blame]
Phil Nashd52f61c2010-11-14 22:47:30 +00001/*
Phil Nashd52f61c2010-11-14 22:47:30 +00002 * Created by Phil on 14/11/2010.
3 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
4 *
5 * Distributed under the Boost Software License, Version 1.0. (See accompanying
6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Phil Nashd52f61c2010-11-14 22:47:30 +00007 */
Phil Nashd52f61c2010-11-14 22:47:30 +00008#ifndef TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
9#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
10
Phil Nash0dc9e432012-08-01 08:17:07 +010011#include "catch_objc_arc.hpp"
12
Phil Nashd52f61c2010-11-14 22:47:30 +000013#import <objc/runtime.h>
Phil Nash6abf7022012-02-10 08:28:37 +000014
Phil Nashd52f61c2010-11-14 22:47:30 +000015#include <string>
Phil Nash823ea3e2011-04-26 08:32:40 +010016
Phil Nash89d1e6c2011-05-24 08:23:02 +010017// NB. Any general catch headers included here must be included
18// in catch.hpp first to make sure they are included by the single
19// header for non obj-usage
Phil Nash0847a0f2011-02-01 16:09:18 +000020#include "internal/catch_test_case_info.hpp"
Phil Nashd52f61c2010-11-14 22:47:30 +000021
Phil Nash58e9a8b2011-02-08 08:42:05 +000022///////////////////////////////////////////////////////////////////////////////
23// This protocol is really only here for (self) documenting purposes, since
24// all its methods are optional.
Phil Nashf59ecbc2010-11-16 07:00:08 +000025@protocol OcFixture
26
27@optional
28
29-(void) setUp;
30-(void) tearDown;
31
32@end
33
Phil Nash44fbbb02012-05-16 15:07:11 +010034namespace Catch {
35
36 class OcMethod : public ITestCase {
37
Phil Nashd52f61c2010-11-14 22:47:30 +000038 public:
Phil Nash44fbbb02012-05-16 15:07:11 +010039 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
Phil Nashd52f61c2010-11-14 22:47:30 +000040
Phil Nash44fbbb02012-05-16 15:07:11 +010041 virtual void invoke() const {
Phil Nash53c990a2012-03-17 18:20:06 +000042 id obj = [[m_cls alloc] init];
Phil Nashf59ecbc2010-11-16 07:00:08 +000043
Phil Nash53c990a2012-03-17 18:20:06 +000044 performOptionalSelector( obj, @selector(setUp) );
45 performOptionalSelector( obj, m_sel );
46 performOptionalSelector( obj, @selector(tearDown) );
Phil Nashf59ecbc2010-11-16 07:00:08 +000047
Phil Nash53c990a2012-03-17 18:20:06 +000048 arcSafeRelease( obj );
Phil Nashd52f61c2010-11-14 22:47:30 +000049 }
50
Phil Nash44fbbb02012-05-16 15:07:11 +010051 virtual ITestCase* clone() const {
Phil Nashf59ecbc2010-11-16 07:00:08 +000052 return new OcMethod( m_cls, m_sel );
Phil Nashd52f61c2010-11-14 22:47:30 +000053 }
54
Phil Nash44fbbb02012-05-16 15:07:11 +010055 virtual bool operator == ( const ITestCase& other ) const {
Phil Nashd52f61c2010-11-14 22:47:30 +000056 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
57 return ocmOther && ocmOther->m_sel == m_sel;
58 }
59
Phil Nash44fbbb02012-05-16 15:07:11 +010060 virtual bool operator < ( const ITestCase& other ) const {
Phil Nashd52f61c2010-11-14 22:47:30 +000061 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
62 return ocmOther && ocmOther->m_sel < m_sel;
63 }
64
65 private:
Phil Nashf59ecbc2010-11-16 07:00:08 +000066 Class m_cls;
Phil Nashd52f61c2010-11-14 22:47:30 +000067 SEL m_sel;
68 };
69
Phil Nash44fbbb02012-05-16 15:07:11 +010070 namespace Detail{
Phil Nashf59ecbc2010-11-16 07:00:08 +000071
Phil Nash44fbbb02012-05-16 15:07:11 +010072 inline bool startsWith( const std::string& str, const std::string& sub ) {
Phil Nashd52f61c2010-11-14 22:47:30 +000073 return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
74 }
75
Phil Nash44fbbb02012-05-16 15:07:11 +010076 inline std::string getAnnotation( Class cls,
77 const std::string& annotationName,
78 const std::string& testCaseName ) {
Phil Nashd52f61c2010-11-14 22:47:30 +000079 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
80 SEL sel = NSSelectorFromString( selStr );
Phil Nash53c990a2012-03-17 18:20:06 +000081 arcSafeRelease( selStr );
82 id value = performOptionalSelector( cls, sel );
83 if( value )
84 return [(NSString*)value UTF8String];
Phil Nashd52f61c2010-11-14 22:47:30 +000085 return "";
86 }
Phil Nashf59ecbc2010-11-16 07:00:08 +000087 }
88
Phil Nash44fbbb02012-05-16 15:07:11 +010089 inline size_t registerTestMethods() {
Phil Nashf59ecbc2010-11-16 07:00:08 +000090 size_t noTestMethods = 0;
91 int noClasses = objc_getClassList( NULL, 0 );
Phil Nashd52f61c2010-11-14 22:47:30 +000092
Phil Nash861a1e72012-04-28 12:29:52 +010093 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
Phil Nash53c990a2012-03-17 18:20:06 +000094 objc_getClassList( classes, noClasses );
Phil Nashf59ecbc2010-11-16 07:00:08 +000095
Phil Nash44fbbb02012-05-16 15:07:11 +010096 for( int c = 0; c < noClasses; c++ ) {
Phil Nashf59ecbc2010-11-16 07:00:08 +000097 Class cls = classes[c];
98 {
99 u_int count;
100 Method* methods = class_copyMethodList( cls, &count );
Graham Lee8cfe8212012-05-21 18:11:55 +0200101 for( u_int m = 0; m < count ; m++ ) {
Phil Nashf59ecbc2010-11-16 07:00:08 +0000102 SEL selector = method_getName(methods[m]);
103 std::string methodName = sel_getName(selector);
Phil Nash44fbbb02012-05-16 15:07:11 +0100104 if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) {
Phil Nashf59ecbc2010-11-16 07:00:08 +0000105 std::string testCaseName = methodName.substr( 15 );
Phil Nash53c990a2012-03-17 18:20:06 +0000106 std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
107 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
Phil Nashf59ecbc2010-11-16 07:00:08 +0000108
Phil Nash371db8b2012-05-21 18:52:09 +0100109 getCurrentContext().getTestCaseRegistry().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) );
Phil Nashf59ecbc2010-11-16 07:00:08 +0000110 noTestMethods++;
Phil Nashf59ecbc2010-11-16 07:00:08 +0000111 }
112 }
113 free(methods);
114 }
115 }
116 return noTestMethods;
Phil Nash966f5db2012-03-04 21:18:46 +0000117 }
118
Phil Nash44fbbb02012-05-16 15:07:11 +0100119 namespace Matchers {
120 namespace Impl {
121 namespace NSStringMatchers {
122
123 struct StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000124 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
Phil Nash44fbbb02012-05-16 15:07:11 +0100125 StringHolder() {
Phil Nash53c990a2012-03-17 18:20:06 +0000126 arcSafeRelease( m_substr );
Phil Nash966f5db2012-03-04 21:18:46 +0000127 }
128
Phil Nash0dc9e432012-08-01 08:17:07 +0100129 NSString* m_substr;
Phil Nash966f5db2012-03-04 21:18:46 +0000130 };
131
Phil Nash44fbbb02012-05-16 15:07:11 +0100132 struct Equals : StringHolder {
Phil Nashdb837a12012-03-14 20:04:50 +0000133 Equals( NSString* substr ) : StringHolder( substr ){}
134
Phil Nash44fbbb02012-05-16 15:07:11 +0100135 bool operator()( NSString* str ) const {
Phil Nashdb837a12012-03-14 20:04:50 +0000136 return [str isEqualToString:m_substr];
137 }
138
Phil Nash44fbbb02012-05-16 15:07:11 +0100139 friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) {
Phil Nashdb837a12012-03-14 20:04:50 +0000140 os << "equals string: " << Catch::toString( matcher.m_substr );
141 return os;
142 }
143 };
144
Phil Nash44fbbb02012-05-16 15:07:11 +0100145 struct Contains : StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000146 Contains( NSString* substr ) : StringHolder( substr ){}
147
Phil Nash44fbbb02012-05-16 15:07:11 +0100148 bool operator()( NSString* str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000149 return [str rangeOfString:m_substr].location != NSNotFound;
150 }
151
Phil Nash44fbbb02012-05-16 15:07:11 +0100152 friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) {
Phil Nash966f5db2012-03-04 21:18:46 +0000153 os << "contains: " << Catch::toString( matcher.m_substr );
154 return os;
155 }
156 };
157
Phil Nash44fbbb02012-05-16 15:07:11 +0100158 struct StartsWith : StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000159 StartsWith( NSString* substr ) : StringHolder( substr ){}
160
Phil Nash44fbbb02012-05-16 15:07:11 +0100161 bool operator()( NSString* str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000162 return [str rangeOfString:m_substr].location == 0;
163 }
164
Phil Nash44fbbb02012-05-16 15:07:11 +0100165 friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) {
Phil Nash966f5db2012-03-04 21:18:46 +0000166 os << "starts with: " << Catch::toString( matcher.m_substr );
167 return os;
168 }
169 };
Phil Nash44fbbb02012-05-16 15:07:11 +0100170 struct EndsWith : StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000171 EndsWith( NSString* substr ) : StringHolder( substr ){}
172
Phil Nash44fbbb02012-05-16 15:07:11 +0100173 bool operator()( NSString* str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000174 return [str rangeOfString:m_substr].location == [str length] - [m_substr length];
175 }
176
Phil Nash44fbbb02012-05-16 15:07:11 +0100177 friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) {
Phil Nash966f5db2012-03-04 21:18:46 +0000178 os << "ends with: " << Catch::toString( matcher.m_substr );
179 return os;
180 }
181 };
182
183 } // namespace NSStringMatchers
184 } // namespace Impl
185
Phil Nashdb837a12012-03-14 20:04:50 +0000186 inline Impl::NSStringMatchers::Equals
187 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
188
Phil Nash966f5db2012-03-04 21:18:46 +0000189 inline Impl::NSStringMatchers::Contains
190 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000191
Phil Nash966f5db2012-03-04 21:18:46 +0000192 inline Impl::NSStringMatchers::StartsWith
193 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000194
Phil Nash966f5db2012-03-04 21:18:46 +0000195 inline Impl::NSStringMatchers::EndsWith
196 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
197
198 } // namespace Matchers
199
200 using namespace Matchers;
201
202} // namespace Catch
Phil Nashd52f61c2010-11-14 22:47:30 +0000203
Phil Nash58e9a8b2011-02-08 08:42:05 +0000204///////////////////////////////////////////////////////////////////////////////
Phil Nashd52f61c2010-11-14 22:47:30 +0000205#define OC_TEST_CASE( name, desc )\
Phil Nash53c990a2012-03-17 18:20:06 +0000206+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000207{\
Phil Nash53c990a2012-03-17 18:20:06 +0000208return @ name; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000209}\
Phil Nash53c990a2012-03-17 18:20:06 +0000210+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000211{ \
Phil Nash53c990a2012-03-17 18:20:06 +0000212return @ desc; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000213} \
214-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
215
Phil Nashd10d2d32012-05-10 21:46:46 +0100216#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED