blob: eb8c5264470d00b0f8d6235fe2c517d987becd71 [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 Nashddfe9632012-08-14 19:30:30 +010020#include "internal/catch_test_case_info.h"
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 Nash44246342012-12-06 08:41:38 +000096 getMutableRegistryHub().registerTest( makeTestCase( 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
Phil Nash44246342012-12-06 08:41:38 +0000110 template<typename MatcherT>
111 struct StringHolder : MatcherImpl<MatcherT, NSString*>{
Phil Nash966f5db2012-03-04 21:18:46 +0000112 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
Phil Nash44246342012-12-06 08:41:38 +0000113 StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
Phil Nash44fbbb02012-05-16 15:07:11 +0100114 StringHolder() {
Phil Nash53c990a2012-03-17 18:20:06 +0000115 arcSafeRelease( m_substr );
Phil Nash966f5db2012-03-04 21:18:46 +0000116 }
117
Phil Nash0dc9e432012-08-01 08:17:07 +0100118 NSString* m_substr;
Phil Nash966f5db2012-03-04 21:18:46 +0000119 };
120
Phil Nash44246342012-12-06 08:41:38 +0000121 struct Equals : StringHolder<Equals> {
Phil Nashdb837a12012-03-14 20:04:50 +0000122 Equals( NSString* substr ) : StringHolder( substr ){}
123
Phil Nash44246342012-12-06 08:41:38 +0000124 virtual bool match( ExpressionType const& str ) const {
Phil Nashdb837a12012-03-14 20:04:50 +0000125 return [str isEqualToString:m_substr];
126 }
127
Phil Nash44246342012-12-06 08:41:38 +0000128 virtual std::string toString() const {
129 return "equals string: \"" + Catch::toString( m_substr ) + "\"";
Phil Nashdb837a12012-03-14 20:04:50 +0000130 }
131 };
132
Phil Nash44246342012-12-06 08:41:38 +0000133 struct Contains : StringHolder<Contains> {
Phil Nash966f5db2012-03-04 21:18:46 +0000134 Contains( NSString* substr ) : StringHolder( substr ){}
135
Phil Nash44246342012-12-06 08:41:38 +0000136 virtual bool match( ExpressionType const& str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000137 return [str rangeOfString:m_substr].location != NSNotFound;
138 }
139
Phil Nash44246342012-12-06 08:41:38 +0000140 virtual std::string toString() const {
141 return "contains string: \"" + Catch::toString( m_substr ) + "\"";
Phil Nash966f5db2012-03-04 21:18:46 +0000142 }
143 };
144
Phil Nash44246342012-12-06 08:41:38 +0000145 struct StartsWith : StringHolder<StartsWith> {
Phil Nash966f5db2012-03-04 21:18:46 +0000146 StartsWith( NSString* substr ) : StringHolder( substr ){}
147
Phil Nash44246342012-12-06 08:41:38 +0000148 virtual bool match( ExpressionType const& str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000149 return [str rangeOfString:m_substr].location == 0;
150 }
151
Phil Nash44246342012-12-06 08:41:38 +0000152 virtual std::string toString() const {
153 return "starts with: \"" + Catch::toString( m_substr ) + "\"";
Phil Nash966f5db2012-03-04 21:18:46 +0000154 }
155 };
Phil Nash44246342012-12-06 08:41:38 +0000156 struct EndsWith : StringHolder<EndsWith> {
Phil Nash966f5db2012-03-04 21:18:46 +0000157 EndsWith( NSString* substr ) : StringHolder( substr ){}
158
Phil Nash44246342012-12-06 08:41:38 +0000159 virtual bool match( ExpressionType const& str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000160 return [str rangeOfString:m_substr].location == [str length] - [m_substr length];
161 }
162
Phil Nash44246342012-12-06 08:41:38 +0000163 virtual std::string toString() const {
164 return "ends with: \"" + Catch::toString( m_substr ) + "\"";
Phil Nash966f5db2012-03-04 21:18:46 +0000165 }
166 };
167
168 } // namespace NSStringMatchers
169 } // namespace Impl
170
Phil Nashdb837a12012-03-14 20:04:50 +0000171 inline Impl::NSStringMatchers::Equals
172 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
173
Phil Nash966f5db2012-03-04 21:18:46 +0000174 inline Impl::NSStringMatchers::Contains
175 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000176
Phil Nash966f5db2012-03-04 21:18:46 +0000177 inline Impl::NSStringMatchers::StartsWith
178 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000179
Phil Nash966f5db2012-03-04 21:18:46 +0000180 inline Impl::NSStringMatchers::EndsWith
181 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
182
183 } // namespace Matchers
184
185 using namespace Matchers;
186
187} // namespace Catch
Phil Nashd52f61c2010-11-14 22:47:30 +0000188
Phil Nash58e9a8b2011-02-08 08:42:05 +0000189///////////////////////////////////////////////////////////////////////////////
Phil Nashd52f61c2010-11-14 22:47:30 +0000190#define OC_TEST_CASE( name, desc )\
Phil Nash53c990a2012-03-17 18:20:06 +0000191+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000192{\
Phil Nash53c990a2012-03-17 18:20:06 +0000193return @ name; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000194}\
Phil Nash53c990a2012-03-17 18:20:06 +0000195+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000196{ \
Phil Nash53c990a2012-03-17 18:20:06 +0000197return @ desc; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000198} \
199-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
200
Phil Nashd10d2d32012-05-10 21:46:46 +0100201#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED