blob: 5c2d7d01ea62cb7d5473b8808e7db3be52de2a17 [file] [log] [blame]
Phil Nashd52f61c2010-11-14 22:47:30 +00001/*
2 * catch_objc.hpp
3 * Test
4 *
5 * Created by Phil on 14/11/2010.
6 * Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
7 *
8 * Distributed under the Boost Software License, Version 1.0. (See accompanying
9 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 *
11 */
12
13#ifndef TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
14#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
15
16#import <objc/runtime.h>
17#include <string>
18#include "catch.hpp"
19
20namespace Catch
21{
22 template<typename T>
23 class OcMethod : public TestCase
24 {
25 public:
26 OcMethod( SEL sel ) : m_sel( sel )
27 {
28 }
29
30 virtual void invoke() const
31 {
32 T* obj = [[T alloc] init];
33 if( [obj respondsToSelector: m_sel] )
34 [obj performSelector: m_sel];
35 [obj release];
36 }
37
38 virtual TestCase* clone() const
39 {
40 return new OcMethod<T>( m_sel );
41 }
42
43 virtual bool operator == ( const TestCase& other ) const
44 {
45 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
46 return ocmOther && ocmOther->m_sel == m_sel;
47 }
48
49 virtual bool operator < ( const TestCase& other ) const
50 {
51 const OcMethod* ocmOther = dynamic_cast<const OcMethod*> ( &other );
52 return ocmOther && ocmOther->m_sel < m_sel;
53 }
54
55 private:
56
57 SEL m_sel;
58 };
59
60 template<typename T>
61 struct OcAutoReg
62 {
63 OcAutoReg()
64 {
65 u_int count;
66 Method* methods = class_copyMethodList([T class], &count);
67
68 for( int i = 0; i < count ; i++ )
69 {
70 SEL selector = method_getName(methods[i]);
71 std::string methodName = sel_getName(selector);
72 if( startsWith( methodName, "Catch_TestCase_" ) )
73 {
74 std::string testCaseName = methodName.substr( 15 );
75 std::string name = getAnnotation( "Name", testCaseName );
76 std::string desc = getAnnotation( "Description", testCaseName );
77
78 TestRegistry::instance().registerTest( TestCaseInfo( new OcMethod<T>( selector ), name, desc ) );
79
80 }
81 }
82 free(methods);
83 }
84
85 private:
86 bool startsWith( const std::string& str, const std::string& sub )
87 {
88 return str.length() > sub.length() && str.substr( 0, sub.length() ) == sub;
89 }
90
91 const char* getAnnotation( const std::string& annotationName, const std::string& testCaseName )
92 {
93 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
94 SEL sel = NSSelectorFromString( selStr );
95 [selStr release];
96 if( [[T class] respondsToSelector: sel] )
97 return (const char*)[[T class] performSelector: sel];
98 return "";
99 }
100
101 };
102}
103
104#define CATCH_REGISTER_CLASS( className ) namespace{ Catch::OcAutoReg<className> reg; }
105
106#define OC_TEST_CASE( name, desc )\
107+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
108{\
109return name; \
110}\
111+(const char*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
112{ \
113return desc; \
114} \
115-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
116
117#endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED