1 /* 2 * Created by Phil on 27/01/2011. 3 * Copyright 2011 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_GENERATORS_HPP_INCLUDED 9 #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED 10 11 #include "catch_context.h" 12 13 #include <vector> 14 #include <string> 15 #include <stdlib.h> 16 17 namespace Catch { 18 19 template<typename T> 20 struct IGenerator { ~IGeneratorCatch::IGenerator21 virtual ~IGenerator() {} 22 virtual T getValue( std::size_t index ) const = 0; 23 virtual std::size_t size () const = 0; 24 }; 25 26 template<typename T> 27 class BetweenGenerator : public IGenerator<T> { 28 public: BetweenGenerator(T from,T to)29 BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} 30 getValue(std::size_t index) const31 virtual T getValue( std::size_t index ) const { 32 return m_from+static_cast<int>( index ); 33 } 34 size() const35 virtual std::size_t size() const { 36 return static_cast<std::size_t>( 1+m_to-m_from ); 37 } 38 39 private: 40 41 T m_from; 42 T m_to; 43 }; 44 45 template<typename T> 46 class ValuesGenerator : public IGenerator<T> { 47 public: ValuesGenerator()48 ValuesGenerator(){} 49 add(T value)50 void add( T value ) { 51 m_values.push_back( value ); 52 } 53 getValue(std::size_t index) const54 virtual T getValue( std::size_t index ) const { 55 return m_values[index]; 56 } 57 size() const58 virtual std::size_t size() const { 59 return m_values.size(); 60 } 61 62 private: 63 std::vector<T> m_values; 64 }; 65 66 template<typename T> 67 class CompositeGenerator { 68 public: CompositeGenerator()69 CompositeGenerator() : m_totalSize( 0 ) {} 70 71 // *** Move semantics, similar to auto_ptr *** CompositeGenerator(CompositeGenerator & other)72 CompositeGenerator( CompositeGenerator& other ) 73 : m_fileInfo( other.m_fileInfo ), 74 m_totalSize( 0 ) 75 { 76 move( other ); 77 } 78 setFileInfo(const char * fileInfo)79 CompositeGenerator& setFileInfo( const char* fileInfo ) { 80 m_fileInfo = fileInfo; 81 return *this; 82 } 83 ~CompositeGenerator()84 ~CompositeGenerator() { 85 deleteAll( m_composed ); 86 } 87 operator T() const88 operator T () const { 89 size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); 90 91 typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); 92 typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); 93 for( size_t index = 0; it != itEnd; ++it ) 94 { 95 const IGenerator<T>* generator = *it; 96 if( overallIndex >= index && overallIndex < index + generator->size() ) 97 { 98 return generator->getValue( overallIndex-index ); 99 } 100 index += generator->size(); 101 } 102 CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); 103 return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so 104 } 105 add(const IGenerator<T> * generator)106 void add( const IGenerator<T>* generator ) { 107 m_totalSize += generator->size(); 108 m_composed.push_back( generator ); 109 } 110 then(CompositeGenerator & other)111 CompositeGenerator& then( CompositeGenerator& other ) { 112 move( other ); 113 return *this; 114 } 115 then(T value)116 CompositeGenerator& then( T value ) { 117 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); 118 valuesGen->add( value ); 119 add( valuesGen ); 120 return *this; 121 } 122 123 private: 124 move(CompositeGenerator & other)125 void move( CompositeGenerator& other ) { 126 m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); 127 m_totalSize += other.m_totalSize; 128 other.m_composed.clear(); 129 } 130 131 std::vector<const IGenerator<T>*> m_composed; 132 std::string m_fileInfo; 133 size_t m_totalSize; 134 }; 135 136 namespace Generators 137 { 138 template<typename T> between(T from,T to)139 CompositeGenerator<T> between( T from, T to ) { 140 CompositeGenerator<T> generators; 141 generators.add( new BetweenGenerator<T>( from, to ) ); 142 return generators; 143 } 144 145 template<typename T> values(T val1,T val2)146 CompositeGenerator<T> values( T val1, T val2 ) { 147 CompositeGenerator<T> generators; 148 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); 149 valuesGen->add( val1 ); 150 valuesGen->add( val2 ); 151 generators.add( valuesGen ); 152 return generators; 153 } 154 155 template<typename T> values(T val1,T val2,T val3)156 CompositeGenerator<T> values( T val1, T val2, T val3 ){ 157 CompositeGenerator<T> generators; 158 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); 159 valuesGen->add( val1 ); 160 valuesGen->add( val2 ); 161 valuesGen->add( val3 ); 162 generators.add( valuesGen ); 163 return generators; 164 } 165 166 template<typename T> values(T val1,T val2,T val3,T val4)167 CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { 168 CompositeGenerator<T> generators; 169 ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); 170 valuesGen->add( val1 ); 171 valuesGen->add( val2 ); 172 valuesGen->add( val3 ); 173 valuesGen->add( val4 ); 174 generators.add( valuesGen ); 175 return generators; 176 } 177 178 } // end namespace Generators 179 180 using namespace Generators; 181 182 } // end namespace Catch 183 184 #define INTERNAL_CATCH_LINESTR2( line ) #line 185 #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) 186 187 #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) 188 189 #endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED 190