catch_objc.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. #include "catch_objc_arc.hpp"
  11. #import <objc/runtime.h>
  12. #include <string>
  13. // NB. Any general catch headers included here must be included
  14. // in catch.hpp first to make sure they are included by the single
  15. // header for non obj-usage
  16. #include "catch_test_case_info.h"
  17. #include "catch_string_manip.h"
  18. #include "catch_tostring.h"
  19. ///////////////////////////////////////////////////////////////////////////////
  20. // This protocol is really only here for (self) documenting purposes, since
  21. // all its methods are optional.
  22. @protocol OcFixture
  23. @optional
  24. -(void) setUp;
  25. -(void) tearDown;
  26. @end
  27. namespace Catch {
  28. class OcMethod : public ITestInvoker {
  29. public:
  30. OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
  31. virtual void invoke() const {
  32. id obj = [[m_cls alloc] init];
  33. performOptionalSelector( obj, @selector(setUp) );
  34. performOptionalSelector( obj, m_sel );
  35. performOptionalSelector( obj, @selector(tearDown) );
  36. arcSafeRelease( obj );
  37. }
  38. private:
  39. virtual ~OcMethod() {}
  40. Class m_cls;
  41. SEL m_sel;
  42. };
  43. namespace Detail{
  44. inline std::string getAnnotation( Class cls,
  45. std::string const& annotationName,
  46. std::string const& testCaseName ) {
  47. NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
  48. SEL sel = NSSelectorFromString( selStr );
  49. arcSafeRelease( selStr );
  50. id value = performOptionalSelector( cls, sel );
  51. if( value )
  52. return [(NSString*)value UTF8String];
  53. return "";
  54. }
  55. }
  56. inline std::size_t registerTestMethods() {
  57. std::size_t noTestMethods = 0;
  58. int noClasses = objc_getClassList( nullptr, 0 );
  59. Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
  60. objc_getClassList( classes, noClasses );
  61. for( int c = 0; c < noClasses; c++ ) {
  62. Class cls = classes[c];
  63. {
  64. u_int count;
  65. Method* methods = class_copyMethodList( cls, &count );
  66. for( u_int m = 0; m < count ; m++ ) {
  67. SEL selector = method_getName(methods[m]);
  68. std::string methodName = sel_getName(selector);
  69. if( startsWith( methodName, "Catch_TestCase_" ) ) {
  70. std::string testCaseName = methodName.substr( 15 );
  71. std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
  72. std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
  73. const char* className = class_getName( cls );
  74. getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
  75. noTestMethods++;
  76. }
  77. }
  78. free(methods);
  79. }
  80. }
  81. return noTestMethods;
  82. }
  83. #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
  84. namespace Matchers {
  85. namespace Impl {
  86. namespace NSStringMatchers {
  87. struct StringHolder : MatcherBase<NSString*>{
  88. StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
  89. StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
  90. StringHolder() {
  91. arcSafeRelease( m_substr );
  92. }
  93. bool match( NSString* str ) const override {
  94. return false;
  95. }
  96. NSString* CATCH_ARC_STRONG m_substr;
  97. };
  98. struct Equals : StringHolder {
  99. Equals( NSString* substr ) : StringHolder( substr ){}
  100. bool match( NSString* str ) const override {
  101. return (str != nil || m_substr == nil ) &&
  102. [str isEqualToString:m_substr];
  103. }
  104. std::string describe() const override {
  105. return "equals string: " + Catch::Detail::stringify( m_substr );
  106. }
  107. };
  108. struct Contains : StringHolder {
  109. Contains( NSString* substr ) : StringHolder( substr ){}
  110. bool match( NSString* str ) const override {
  111. return (str != nil || m_substr == nil ) &&
  112. [str rangeOfString:m_substr].location != NSNotFound;
  113. }
  114. std::string describe() const override {
  115. return "contains string: " + Catch::Detail::stringify( m_substr );
  116. }
  117. };
  118. struct StartsWith : StringHolder {
  119. StartsWith( NSString* substr ) : StringHolder( substr ){}
  120. bool match( NSString* str ) const override {
  121. return (str != nil || m_substr == nil ) &&
  122. [str rangeOfString:m_substr].location == 0;
  123. }
  124. std::string describe() const override {
  125. return "starts with: " + Catch::Detail::stringify( m_substr );
  126. }
  127. };
  128. struct EndsWith : StringHolder {
  129. EndsWith( NSString* substr ) : StringHolder( substr ){}
  130. bool match( NSString* str ) const override {
  131. return (str != nil || m_substr == nil ) &&
  132. [str rangeOfString:m_substr].location == [str length] - [m_substr length];
  133. }
  134. std::string describe() const override {
  135. return "ends with: " + Catch::Detail::stringify( m_substr );
  136. }
  137. };
  138. } // namespace NSStringMatchers
  139. } // namespace Impl
  140. inline Impl::NSStringMatchers::Equals
  141. Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
  142. inline Impl::NSStringMatchers::Contains
  143. Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
  144. inline Impl::NSStringMatchers::StartsWith
  145. StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
  146. inline Impl::NSStringMatchers::EndsWith
  147. EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
  148. } // namespace Matchers
  149. using namespace Matchers;
  150. #endif // CATCH_CONFIG_DISABLE_MATCHERS
  151. } // namespace Catch
  152. ///////////////////////////////////////////////////////////////////////////////
  153. #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix
  154. #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \
  155. +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \
  156. { \
  157. return @ name; \
  158. } \
  159. +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \
  160. { \
  161. return @ desc; \
  162. } \
  163. -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )
  164. #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )
  165. #endif // TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED