blob: 640b4cc29c6290aac8f9d0ba2edad9b0e1840d13 [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 Nash2a9d8d92013-04-23 18:58:56 +010059 inline bool startsWith( std::string const& str, std::string const& 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,
Phil Nash2a9d8d92013-04-23 18:58:56 +010064 std::string const& annotationName,
65 std::string const& 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 }
Phil Nash49d7ce42013-03-21 08:58:22 +000075
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 Nash429699e2013-02-19 08:39:28 +000095 const char* className = class_getName( cls );
Phil Nashf59ecbc2010-11-16 07:00:08 +000096
Phil Nash429699e2013-02-19 08:39:28 +000097 getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
Phil Nashf59ecbc2010-11-16 07:00:08 +000098 noTestMethods++;
Phil Nashf59ecbc2010-11-16 07:00:08 +000099 }
100 }
101 free(methods);
102 }
103 }
104 return noTestMethods;
Phil Nash966f5db2012-03-04 21:18:46 +0000105 }
106
Phil Nash44fbbb02012-05-16 15:07:11 +0100107 namespace Matchers {
108 namespace Impl {
109 namespace NSStringMatchers {
110
Phil Nash44246342012-12-06 08:41:38 +0000111 template<typename MatcherT>
112 struct StringHolder : MatcherImpl<MatcherT, NSString*>{
Phil Nash966f5db2012-03-04 21:18:46 +0000113 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
Phil Nash44246342012-12-06 08:41:38 +0000114 StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
Phil Nash44fbbb02012-05-16 15:07:11 +0100115 StringHolder() {
Phil Nash53c990a2012-03-17 18:20:06 +0000116 arcSafeRelease( m_substr );
Phil Nash966f5db2012-03-04 21:18:46 +0000117 }
118
Phil Nash0dc9e432012-08-01 08:17:07 +0100119 NSString* m_substr;
Phil Nash966f5db2012-03-04 21:18:46 +0000120 };
121
Phil Nash44246342012-12-06 08:41:38 +0000122 struct Equals : StringHolder<Equals> {
Phil Nashdb837a12012-03-14 20:04:50 +0000123 Equals( NSString* substr ) : StringHolder( substr ){}
124
Phil Nash44246342012-12-06 08:41:38 +0000125 virtual bool match( ExpressionType const& str ) const {
Phil Nashdb837a12012-03-14 20:04:50 +0000126 return [str isEqualToString:m_substr];
127 }
128
Phil Nash44246342012-12-06 08:41:38 +0000129 virtual std::string toString() const {
130 return "equals string: \"" + Catch::toString( m_substr ) + "\"";
Phil Nashdb837a12012-03-14 20:04:50 +0000131 }
132 };
133
Phil Nash44246342012-12-06 08:41:38 +0000134 struct Contains : StringHolder<Contains> {
Phil Nash966f5db2012-03-04 21:18:46 +0000135 Contains( NSString* substr ) : StringHolder( substr ){}
136
Phil Nash44246342012-12-06 08:41:38 +0000137 virtual bool match( ExpressionType const& str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000138 return [str rangeOfString:m_substr].location != NSNotFound;
139 }
140
Phil Nash44246342012-12-06 08:41:38 +0000141 virtual std::string toString() const {
142 return "contains string: \"" + Catch::toString( m_substr ) + "\"";
Phil Nash966f5db2012-03-04 21:18:46 +0000143 }
144 };
145
Phil Nash44246342012-12-06 08:41:38 +0000146 struct StartsWith : StringHolder<StartsWith> {
Phil Nash966f5db2012-03-04 21:18:46 +0000147 StartsWith( NSString* substr ) : StringHolder( substr ){}
148
Phil Nash44246342012-12-06 08:41:38 +0000149 virtual bool match( ExpressionType const& str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000150 return [str rangeOfString:m_substr].location == 0;
151 }
152
Phil Nash44246342012-12-06 08:41:38 +0000153 virtual std::string toString() const {
154 return "starts with: \"" + Catch::toString( m_substr ) + "\"";
Phil Nash966f5db2012-03-04 21:18:46 +0000155 }
156 };
Phil Nash44246342012-12-06 08:41:38 +0000157 struct EndsWith : StringHolder<EndsWith> {
Phil Nash966f5db2012-03-04 21:18:46 +0000158 EndsWith( NSString* substr ) : StringHolder( substr ){}
159
Phil Nash44246342012-12-06 08:41:38 +0000160 virtual bool match( ExpressionType const& str ) const {
Phil Nash966f5db2012-03-04 21:18:46 +0000161 return [str rangeOfString:m_substr].location == [str length] - [m_substr length];
162 }
163
Phil Nash44246342012-12-06 08:41:38 +0000164 virtual std::string toString() const {
165 return "ends with: \"" + Catch::toString( m_substr ) + "\"";
Phil Nash966f5db2012-03-04 21:18:46 +0000166 }
167 };
168
169 } // namespace NSStringMatchers
170 } // namespace Impl
171
Phil Nashdb837a12012-03-14 20:04:50 +0000172 inline Impl::NSStringMatchers::Equals
173 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
174
Phil Nash966f5db2012-03-04 21:18:46 +0000175 inline Impl::NSStringMatchers::Contains
176 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000177
Phil Nash966f5db2012-03-04 21:18:46 +0000178 inline Impl::NSStringMatchers::StartsWith
179 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
Phil Nashdb837a12012-03-14 20:04:50 +0000180
Phil Nash966f5db2012-03-04 21:18:46 +0000181 inline Impl::NSStringMatchers::EndsWith
182 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
183
184 } // namespace Matchers
185
186 using namespace Matchers;
187
188} // namespace Catch
Phil Nashd52f61c2010-11-14 22:47:30 +0000189
Phil Nash58e9a8b2011-02-08 08:42:05 +0000190///////////////////////////////////////////////////////////////////////////////
Phil Nashd52f61c2010-11-14 22:47:30 +0000191#define OC_TEST_CASE( name, desc )\
Phil Nash53c990a2012-03-17 18:20:06 +0000192+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000193{\
Phil Nash53c990a2012-03-17 18:20:06 +0000194return @ name; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000195}\
Phil Nash53c990a2012-03-17 18:20:06 +0000196+(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
Phil Nashd52f61c2010-11-14 22:47:30 +0000197{ \
Phil Nash53c990a2012-03-17 18:20:06 +0000198return @ desc; \
Phil Nashd52f61c2010-11-14 22:47:30 +0000199} \
200-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
201
Phil Nashd10d2d32012-05-10 21:46:46 +0100202#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED