| /* |
| * Created by Phil on 27/01/2011. |
| * Copyright 2011 Two Blue Cubes Ltd. All rights reserved. |
| * |
| * Distributed under the Boost Software License, Version 1.0. (See accompanying |
| * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| */ |
| #ifndef TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED |
| #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED |
| |
| #include "catch_context.h" |
| |
| #include <vector> |
| #include <string> |
| #include <stdlib.h> |
| |
| namespace Catch { |
| |
| template<typename T> |
| struct IGenerator { |
| virtual ~IGenerator() {} |
| virtual T getValue( std::size_t index ) const = 0; |
| virtual std::size_t size () const = 0; |
| }; |
| |
| template<typename T> |
| class BetweenGenerator : public IGenerator<T> { |
| public: |
| BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} |
| |
| virtual T getValue( std::size_t index ) const { |
| return m_from+static_cast<int>( index ); |
| } |
| |
| virtual std::size_t size() const { |
| return static_cast<std::size_t>( 1+m_to-m_from ); |
| } |
| |
| private: |
| |
| T m_from; |
| T m_to; |
| }; |
| |
| template<typename T> |
| class ValuesGenerator : public IGenerator<T> { |
| public: |
| ValuesGenerator(){} |
| |
| void add( T value ) { |
| m_values.push_back( value ); |
| } |
| |
| virtual T getValue( std::size_t index ) const { |
| return m_values[index]; |
| } |
| |
| virtual std::size_t size() const { |
| return m_values.size(); |
| } |
| |
| private: |
| std::vector<T> m_values; |
| }; |
| |
| template<typename T> |
| class CompositeGenerator { |
| public: |
| CompositeGenerator() : m_totalSize( 0 ) {} |
| |
| // *** Move semantics, similar to auto_ptr *** |
| CompositeGenerator( CompositeGenerator& other ) |
| : m_fileInfo( other.m_fileInfo ), |
| m_totalSize( 0 ) |
| { |
| move( other ); |
| } |
| |
| CompositeGenerator& setFileInfo( const char* fileInfo ) { |
| m_fileInfo = fileInfo; |
| return *this; |
| } |
| |
| ~CompositeGenerator() { |
| deleteAll( m_composed ); |
| } |
| |
| operator T () const { |
| size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); |
| |
| size_t index = 0; |
| for( auto generator : m_composed ) |
| { |
| if( overallIndex >= index && overallIndex < index + generator->size() ) |
| { |
| return generator->getValue( overallIndex-index ); |
| } |
| index += generator->size(); |
| } |
| CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); |
| 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 |
| } |
| |
| void add( const IGenerator<T>* generator ) { |
| m_totalSize += generator->size(); |
| m_composed.push_back( generator ); |
| } |
| |
| CompositeGenerator& then( CompositeGenerator& other ) { |
| move( other ); |
| return *this; |
| } |
| |
| CompositeGenerator& then( T value ) { |
| ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); |
| valuesGen->add( value ); |
| add( valuesGen ); |
| return *this; |
| } |
| |
| private: |
| |
| void move( CompositeGenerator& other ) { |
| m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); |
| m_totalSize += other.m_totalSize; |
| other.m_composed.clear(); |
| } |
| |
| std::vector<const IGenerator<T>*> m_composed; |
| std::string m_fileInfo; |
| size_t m_totalSize; |
| }; |
| |
| namespace Generators |
| { |
| template<typename T> |
| CompositeGenerator<T> between( T from, T to ) { |
| CompositeGenerator<T> generators; |
| generators.add( new BetweenGenerator<T>( from, to ) ); |
| return generators; |
| } |
| |
| template<typename T> |
| CompositeGenerator<T> values( T val1, T val2 ) { |
| CompositeGenerator<T> generators; |
| ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); |
| valuesGen->add( val1 ); |
| valuesGen->add( val2 ); |
| generators.add( valuesGen ); |
| return generators; |
| } |
| |
| template<typename T> |
| CompositeGenerator<T> values( T val1, T val2, T val3 ){ |
| CompositeGenerator<T> generators; |
| ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); |
| valuesGen->add( val1 ); |
| valuesGen->add( val2 ); |
| valuesGen->add( val3 ); |
| generators.add( valuesGen ); |
| return generators; |
| } |
| |
| template<typename T> |
| CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { |
| CompositeGenerator<T> generators; |
| ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); |
| valuesGen->add( val1 ); |
| valuesGen->add( val2 ); |
| valuesGen->add( val3 ); |
| valuesGen->add( val4 ); |
| generators.add( valuesGen ); |
| return generators; |
| } |
| |
| } // end namespace Generators |
| |
| using namespace Generators; |
| |
| } // end namespace Catch |
| |
| #define INTERNAL_CATCH_LINESTR2( line ) #line |
| #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) |
| |
| #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) |
| |
| #endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED |