blob: ad13e29550441cb545d999352cb211ea954f5d72 [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
Phil Nash9c6ce972012-08-14 08:38:22 +010036 class OcMethod : public SharedImpl<ITestCase> {
Phil Nash44fbbb02012-05-16 15:07:11 +010037
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 }
Phil Nashd52f61c2010-11-14 22:47:30 +000050 private:
Phil Nash9c6ce972012-08-14 08:38:22 +010051 virtual ~OcMethod() {}
52
Phil Nashf59ecbc2010-11-16 07:00:08 +000053 Class m_cls;
Phil Nashd52f61c2010-11-14 22:47:30 +000054 SEL m_sel;
55 };
56
Phil Nash44fbbb02012-05-16 15:07:11 +010057 namespace Detail{
Phil Nashf59ecbc2010-11-16 07:00:08 +000058
Phil Nash44fbbb02012-05-16 15:07:11 +010059 inline bool startsWith( const std::string& str, const std::string& sub ) {
Phil Nashd52f61c2010-11-14 22:47:30 +000060 return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
61 }
62
Phil Nash44fbbb02012-05-16 15:07:11 +010063 inline std::string getAnnotation( Class cls,
64 const std::string& annotationName,
65 const std::string& testCaseName ) {
Phil Nashd52f61c2010-11-14 22:47:30 +000066 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
67 SEL sel = NSSelectorFromString( selStr );
Phil Nash53c990a2012-03-17 18:20:06 +000068 arcSafeRelease( selStr );
69 id value = performOptionalSelector( cls, sel );
70 if( value )
71 return [(NSString*)value UTF8String];
Phil Nashd52f61c2010-11-14 22:47:30 +000072 return "";
73 }
Phil Nashf59ecbc2010-11-16 07:00:08 +000074 }
75
Phil Nash44fbbb02012-05-16 15:07:11 +010076 inline size_t registerTestMethods() {
Phil Nashf59ecbc2010-11-16 07:00:08 +000077 size_t noTestMethods = 0;
78 int noClasses = objc_getClassList( NULL, 0 );
Phil Nashd52f61c2010-11-14 22:47:30 +000079
Phil Nash861a1e72012-04-28 12:29:52 +010080 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
Phil Nash53c990a2012-03-17 18:20:06 +000081 objc_getClassList( classes, noClasses );
Phil Nashf59ecbc2010-11-16 07:00:08 +000082
Phil Nash44fbbb02012-05-16 15:07:11 +010083 for( int c = 0; c < noClasses; c++ ) {
Phil Nashf59ecbc2010-11-16 07:00:08 +000084 Class cls = classes[c];
85 {
86 u_int count;
87 Method* methods = class_copyMethodList( cls, &count );
Graham Lee8cfe8212012-05-21 18:11:55 +020088 for( u_int m = 0; m < count ; m++ ) {
Phil Nashf59ecbc2010-11-16 07:00:08 +000089 SEL selector = method_getName(methods[m]);
90 std::string methodName = sel_getName(selector);
Phil Nash44fbbb02012-05-16 15:07:11 +010091 if( Detail::startsWith( methodName, "Catch_TestCase_" ) ) {
Phil Nashf59ecbc2010-11-16 07:00:08 +000092 std::string testCaseName = methodName.substr( 15 );
Phil Nash53c990a2012-03-17 18:20:06 +000093 std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
94 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
Phil Nashf59ecbc2010-11-16 07:00:08 +000095
Phil Nashda0ae952012-08-07 07:58:34 +010096 getMutableRegistryHub().registerTest( TestCaseInfo( new OcMethod( cls, selector ), name.c_str(), desc.c_str(), SourceLineInfo() ) );
Phil Nashf59ecbc2010-11-16 07:00:08 +000097 noTestMethods++;
Phil Nashf59ecbc2010-11-16 07:00:08 +000098 }
99 }
100 free(methods);
101 }
102 }
103 return noTestMethods;
Phil Nash966f5db2012-03-04 21:18:46 +0000104 }
105
Phil Nash44fbbb02012-05-16 15:07:11 +0100106 namespace Matchers {
107 namespace Impl {
108 namespace NSStringMatchers {
109
110 struct StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000111 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
Phil Nash44fbbb02012-05-16 15:07:11 +0100112 StringHolder() {
Phil Nash53c990a2012-03-17 18:20:06 +0000113 arcSafeRelease( m_substr );
Phil Nash966f5db2012-03-04 21:18:46 +0000114 }
115
Phil Nash0dc9e432012-08-01 08:17:07 +0100116 NSString* m_substr;
Phil Nash966f5db2012-03-04 21:18:46 +0000117 };
118
Phil Nash44fbbb02012-05-16 15:07:11 +0100119 struct Equals : StringHolder {
Phil Nashdb837a12012-03-14 20:04:50 +0000120 Equals( NSString* substr ) : StringHolder( substr ){}
121
Phil Nash44fbbb02012-05-16 15:07:11 +0100122 bool operator()( NSString* str ) const {
Phil Nashdb837a12012-03-14 20:04:50 +0000123 return [str isEqualToString:m_substr];
124 }
125
Phil Nash44fbbb02012-05-16 15:07:11 +0100126 friend std::ostream& operator<<( std::ostream& os, const Equals& matcher ) {
Phil Nashdb837a12012-03-14 20:04:50 +0000127 os << "equals string: " << Catch::toString( matcher.m_substr );
128 return os;
129 }
130 };
131
Phil Nash44fbbb02012-05-16 15:07:11 +0100132 struct Contains : StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000133 Contains( NSString* substr ) : StringHolder( substr ){}
134
Phil Nash44fbbb02012-05-16 15:07:11 +0100135 bool operator()( NSString* str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000136 return [str rangeOfString:m_substr].location != NSNotFound;
137 }
138
Phil Nash44fbbb02012-05-16 15:07:11 +0100139 friend std::ostream& operator<<( std::ostream& os, const Contains& matcher ) {
Phil Nash966f5db2012-03-04 21:18:46 +0000140 os << "contains: " << Catch::toString( matcher.m_substr );
141 return os;
142 }
143 };
144
Phil Nash44fbbb02012-05-16 15:07:11 +0100145 struct StartsWith : StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000146 StartsWith( 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 == 0;
150 }
151
Phil Nash44fbbb02012-05-16 15:07:11 +0100152 friend std::ostream& operator<<( std::ostream& os, const StartsWith& matcher ) {
Phil Nash966f5db2012-03-04 21:18:46 +0000153 os << "starts with: " << Catch::toString( matcher.m_substr );
154 return os;
155 }
156 };
Phil Nash44fbbb02012-05-16 15:07:11 +0100157 struct EndsWith : StringHolder {
Phil Nash966f5db2012-03-04 21:18:46 +0000158 EndsWith( NSString* substr ) : StringHolder( substr ){}
159
Phil Nash44fbbb02012-05-16 15:07:11 +0100160 bool operator()( NSString* str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000161 return [str rangeOfString:m_substr].location == [str length] - [m_substr length];
162 }
163
Phil Nash44fbbb02012-05-16 15:07:11 +0100164 friend std::ostream& operator<<( std::ostream& os, const EndsWith& matcher ) {
Phil Nash966f5db2012-03-04 21:18:46 +0000165 os << "ends with: " << Catch::toString( matcher.m_substr );
166 return os;
167 }
168 };
169
170 } // namespace NSStringMatchers
171 } // namespace Impl
172
Phil Nashdb837a12012-03-14 20:04:50 +0000173 inline Impl::NSStringMatchers::Equals
174 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
175
Phil Nash966f5db2012-03-04 21:18:46 +0000176 inline Impl::NSStringMatchers::Contains
177 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000178
Phil Nash966f5db2012-03-04 21:18:46 +0000179 inline Impl::NSStringMatchers::StartsWith
180 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000181
Phil Nash966f5db2012-03-04 21:18:46 +0000182 inline Impl::NSStringMatchers::EndsWith
183 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
184
185 } // namespace Matchers
186
187 using namespace Matchers;
188
189} // namespace Catch
Phil Nashd52f61c2010-11-14 22:47:30 +0000190
Phil Nash58e9a8b2011-02-08 08:42:05 +0000191///////////////////////////////////////////////////////////////////////////////
Phil Nashd52f61c2010-11-14 22:47:30 +0000192#define OC_TEST_CASE( name, desc )\
Phil Nash53c990a2012-03-17 18:20:06 +0000193+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000194{\
Phil Nash53c990a2012-03-17 18:20:06 +0000195return @ name; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000196}\
Phil Nash53c990a2012-03-17 18:20:06 +0000197+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000198{ \
Phil Nash53c990a2012-03-17 18:20:06 +0000199return @ desc; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000200} \
201-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
202
Phil Nashd10d2d32012-05-10 21:46:46 +0100203#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED