/* * catch_generators.hpp * Catch * * 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_hub.h" #include #include #include #include namespace Catch { template struct IGenerator { virtual ~IGenerator () {} virtual T getValue ( std::size_t index ) const = 0; virtual std::size_t size () const = 0; }; template class BetweenGenerator : public IGenerator { 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( index ); } /////////////////////////////////////////////////////////////////////////// virtual std::size_t size () const { return 1+m_to-m_from; } private: T m_from; T m_to; }; template class ValuesGenerator : public IGenerator { 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 m_values; }; template 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 = Hub::getGeneratorIndex( m_fileInfo, m_totalSize ); typename std::vector*>::const_iterator it = m_composed.begin(); typename std::vector*>::const_iterator itEnd = m_composed.end(); for( size_t index = 0; it != itEnd; ++it ) { const IGenerator* generator = *it; 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* generator ) { m_totalSize += generator->size(); m_composed.push_back( generator ); } /////////////////////////////////////////////////////////////////////////// CompositeGenerator& then ( CompositeGenerator& other ) { move( other ); return *this; } /////////////////////////////////////////////////////////////////////////// CompositeGenerator& then ( T value ) { ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( value ); add( valuesGen ); return *this; } private: /////////////////////////////////////////////////////////////////////////// void move ( CompositeGenerator& other ) { std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); m_totalSize += other.m_totalSize; other.m_composed.clear(); } std::vector*> m_composed; std::string m_fileInfo; size_t m_totalSize; }; namespace Generators { /////////////////////////////////////////////////////////////////////////// template CompositeGenerator between ( T from, T to ) { CompositeGenerator generators; generators.add( new BetweenGenerator( from, to ) ); return generators; } /////////////////////////////////////////////////////////////////////////// template CompositeGenerator values ( T val1, T val2 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); generators.add( valuesGen ); return generators; } /////////////////////////////////////////////////////////////////////////// template CompositeGenerator values ( T val1, T val2, T val3 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); valuesGen->add( val1 ); valuesGen->add( val2 ); valuesGen->add( val3 ); generators.add( valuesGen ); return generators; } /////////////////////////////////////////////////////////////////////////// template CompositeGenerator values ( T val1, T val2, T val3, T val4 ) { CompositeGenerator generators; ValuesGenerator* valuesGen = new ValuesGenerator(); 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