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