1 /* 2 * 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) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED 9 #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED 10 11 #include "catch_objc_arc.hpp" 12 13 #import <objc/runtime.h> 14 15 #include <string> 16 17 // 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 20 #include "catch_test_case_info.h" 21 22 /////////////////////////////////////////////////////////////////////////////// 23 // This protocol is really only here for (self) documenting purposes, since 24 // all its methods are optional. 25 @protocol OcFixture 26 27 @optional 28 29 -(void) setUp; 30 -(void) tearDown; 31 32 @end 33 34 namespace Catch { 35 36 class OcMethod : public SharedImpl<ITestCase> { 37 38 public: OcMethod(Class cls,SEL sel)39 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} 40 invoke() const41 virtual void invoke() const { 42 id obj = [[m_cls alloc] init]; 43 44 performOptionalSelector( obj, @selector(setUp) ); 45 performOptionalSelector( obj, m_sel ); 46 performOptionalSelector( obj, @selector(tearDown) ); 47 48 arcSafeRelease( obj ); 49 } 50 private: ~OcMethod()51 virtual ~OcMethod() {} 52 53 Class m_cls; 54 SEL m_sel; 55 }; 56 57 namespace Detail{ 58 59 getAnnotation(Class cls,std::string const & annotationName,std::string const & testCaseName)60 inline std::string getAnnotation( Class cls, 61 std::string const& annotationName, 62 std::string const& testCaseName ) { 63 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; 64 SEL sel = NSSelectorFromString( selStr ); 65 arcSafeRelease( selStr ); 66 id value = performOptionalSelector( cls, sel ); 67 if( value ) 68 return [(NSString*)value UTF8String]; 69 return ""; 70 } 71 } 72 registerTestMethods()73 inline size_t registerTestMethods() { 74 size_t noTestMethods = 0; 75 int noClasses = objc_getClassList( CATCH_NULL, 0 ); 76 77 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); 78 objc_getClassList( classes, noClasses ); 79 80 for( int c = 0; c < noClasses; c++ ) { 81 Class cls = classes[c]; 82 { 83 u_int count; 84 Method* methods = class_copyMethodList( cls, &count ); 85 for( u_int m = 0; m < count ; m++ ) { 86 SEL selector = method_getName(methods[m]); 87 std::string methodName = sel_getName(selector); 88 if( startsWith( methodName, "Catch_TestCase_" ) ) { 89 std::string testCaseName = methodName.substr( 15 ); 90 std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); 91 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); 92 const char* className = class_getName( cls ); 93 94 getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); 95 noTestMethods++; 96 } 97 } 98 free(methods); 99 } 100 } 101 return noTestMethods; 102 } 103 104 namespace Matchers { 105 namespace Impl { 106 namespace NSStringMatchers { 107 108 struct StringHolder : MatcherBase<NSString*>{ StringHolderCatch::Matchers::Impl::NSStringMatchers::StringHolder109 StringHolder( NSString* substr ) : m_substr( [substr copy] ){} StringHolderCatch::Matchers::Impl::NSStringMatchers::StringHolder110 StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} StringHolderCatch::Matchers::Impl::NSStringMatchers::StringHolder111 StringHolder() { 112 arcSafeRelease( m_substr ); 113 } 114 matchCatch::Matchers::Impl::NSStringMatchers::StringHolder115 virtual bool match( NSString* arg ) const CATCH_OVERRIDE { 116 return false; 117 } 118 119 NSString* m_substr; 120 }; 121 122 struct Equals : StringHolder { EqualsCatch::Matchers::Impl::NSStringMatchers::Equals123 Equals( NSString* substr ) : StringHolder( substr ){} 124 matchCatch::Matchers::Impl::NSStringMatchers::Equals125 virtual bool match( NSString* str ) const CATCH_OVERRIDE { 126 return (str != nil || m_substr == nil ) && 127 [str isEqualToString:m_substr]; 128 } 129 describeCatch::Matchers::Impl::NSStringMatchers::Equals130 virtual std::string describe() const CATCH_OVERRIDE { 131 return "equals string: " + Catch::toString( m_substr ); 132 } 133 }; 134 135 struct Contains : StringHolder { ContainsCatch::Matchers::Impl::NSStringMatchers::Contains136 Contains( NSString* substr ) : StringHolder( substr ){} 137 matchCatch::Matchers::Impl::NSStringMatchers::Contains138 virtual bool match( NSString* str ) const { 139 return (str != nil || m_substr == nil ) && 140 [str rangeOfString:m_substr].location != NSNotFound; 141 } 142 describeCatch::Matchers::Impl::NSStringMatchers::Contains143 virtual std::string describe() const CATCH_OVERRIDE { 144 return "contains string: " + Catch::toString( m_substr ); 145 } 146 }; 147 148 struct StartsWith : StringHolder { StartsWithCatch::Matchers::Impl::NSStringMatchers::StartsWith149 StartsWith( NSString* substr ) : StringHolder( substr ){} 150 matchCatch::Matchers::Impl::NSStringMatchers::StartsWith151 virtual bool match( NSString* str ) const { 152 return (str != nil || m_substr == nil ) && 153 [str rangeOfString:m_substr].location == 0; 154 } 155 describeCatch::Matchers::Impl::NSStringMatchers::StartsWith156 virtual std::string describe() const CATCH_OVERRIDE { 157 return "starts with: " + Catch::toString( m_substr ); 158 } 159 }; 160 struct EndsWith : StringHolder { EndsWithCatch::Matchers::Impl::NSStringMatchers::EndsWith161 EndsWith( NSString* substr ) : StringHolder( substr ){} 162 matchCatch::Matchers::Impl::NSStringMatchers::EndsWith163 virtual bool match( NSString* str ) const { 164 return (str != nil || m_substr == nil ) && 165 [str rangeOfString:m_substr].location == [str length] - [m_substr length]; 166 } 167 describeCatch::Matchers::Impl::NSStringMatchers::EndsWith168 virtual std::string describe() const CATCH_OVERRIDE { 169 return "ends with: " + Catch::toString( m_substr ); 170 } 171 }; 172 173 } // namespace NSStringMatchers 174 } // namespace Impl 175 176 inline Impl::NSStringMatchers::Equals Equals(NSString * substr)177 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } 178 179 inline Impl::NSStringMatchers::Contains Contains(NSString * substr)180 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } 181 182 inline Impl::NSStringMatchers::StartsWith StartsWith(NSString * substr)183 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } 184 185 inline Impl::NSStringMatchers::EndsWith EndsWith(NSString * substr)186 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } 187 188 } // namespace Matchers 189 190 using namespace Matchers; 191 192 } // namespace Catch 193 194 /////////////////////////////////////////////////////////////////////////////// 195 #define OC_TEST_CASE( name, desc )\ 196 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ 197 {\ 198 return @ name; \ 199 }\ 200 +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ 201 { \ 202 return @ desc; \ 203 } \ 204 -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) 205 206 #endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED 207