diff --git a/build/build.properties b/build/build.properties
new file mode 100644
index 0000000..c3d72ad
--- /dev/null
+++ b/build/build.properties
@@ -0,0 +1 @@
+platform = vc80
diff --git a/build/build.xml b/build/build.xml
new file mode 100644
index 0000000..cce2904
--- /dev/null
+++ b/build/build.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/vc80/turtle.sln b/build/vc80/turtle.sln
new file mode 100644
index 0000000..32af7d8
--- /dev/null
+++ b/build/vc80/turtle.sln
@@ -0,0 +1,25 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "turtle", "turtle.vcproj", "{831F2DEE-1E35-4533-A3B2-12C01BA8DA1D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "turtle_test", "turtle_test.vcproj", "{74810A2A-33D8-47D6-9A50-71261F1683F5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ debug|Win32 = debug|Win32
+ release|Win32 = release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {831F2DEE-1E35-4533-A3B2-12C01BA8DA1D}.debug|Win32.ActiveCfg = debug|Win32
+ {831F2DEE-1E35-4533-A3B2-12C01BA8DA1D}.debug|Win32.Build.0 = debug|Win32
+ {831F2DEE-1E35-4533-A3B2-12C01BA8DA1D}.release|Win32.ActiveCfg = release|Win32
+ {831F2DEE-1E35-4533-A3B2-12C01BA8DA1D}.release|Win32.Build.0 = release|Win32
+ {74810A2A-33D8-47D6-9A50-71261F1683F5}.debug|Win32.ActiveCfg = debug|Win32
+ {74810A2A-33D8-47D6-9A50-71261F1683F5}.debug|Win32.Build.0 = debug|Win32
+ {74810A2A-33D8-47D6-9A50-71261F1683F5}.release|Win32.ActiveCfg = release|Win32
+ {74810A2A-33D8-47D6-9A50-71261F1683F5}.release|Win32.Build.0 = release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/build/vc80/turtle.vcproj b/build/vc80/turtle.vcproj
new file mode 100644
index 0000000..2cadb7f
--- /dev/null
+++ b/build/vc80/turtle.vcproj
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/vc80/turtle_test.vcproj b/build/vc80/turtle_test.vcproj
new file mode 100644
index 0000000..2da83b8
--- /dev/null
+++ b/build/vc80/turtle_test.vcproj
@@ -0,0 +1,239 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/libraries/turtle/check.hpp b/src/libraries/turtle/check.hpp
new file mode 100644
index 0000000..b50e48d
--- /dev/null
+++ b/src/libraries/turtle/check.hpp
@@ -0,0 +1,66 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_CHECK_HPP_INCLUDED
+#define MOCK_CHECK_HPP_INCLUDED
+
+#include "placeholder.hpp"
+#include "constraint.hpp"
+#include "format.hpp"
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ template< typename Arg >
+ class check
+ {
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function< bool( Arg ) > functor_type;
+
+ public:
+ template< typename T >
+ explicit check( const T& t )
+ : functor_( equal( t ).functor_ )
+ , desc_ ( detail::format( t ) )
+ {
+ if( !functor_ )
+ std::invalid_argument( "invalid functor" );
+ }
+
+ template< typename Constraint >
+ explicit check( const placeholder< Constraint >& c )
+ : functor_( c.functor_ )
+ , desc_ ( c.desc_ )
+ {
+ if( !functor_ )
+ std::invalid_argument( "invalid functor" );
+ }
+
+ template< typename Y >
+ bool operator()( Y& y ) const
+ {
+ return functor_( y );
+ }
+
+ friend std::ostream& operator<<( std::ostream& s, const check& c )
+ {
+ return s << c.desc_;
+ }
+
+ private:
+ functor_type functor_;
+ std::string desc_;
+ };
+}
+}
+
+#endif // #ifndef MOCK_CHECK_HPP_INCLUDED
diff --git a/src/libraries/turtle/config.hpp b/src/libraries/turtle/config.hpp
new file mode 100644
index 0000000..28e7f7f
--- /dev/null
+++ b/src/libraries/turtle/config.hpp
@@ -0,0 +1,26 @@
+//
+// Copyright Mathieu Champlon 2009
+//
+// 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 MOCK_CONFIG_HPP_INCLUDED
+#define MOCK_CONFIG_HPP_INCLUDED
+
+#include
+#include
+#include
+
+#ifndef MOCK_MAX_ARGS
+# define MOCK_MAX_ARGS 10
+#endif // MOCK_MAX_ARGS
+
+BOOST_PP_ASSERT( BOOST_PP_LESS_EQUAL(MOCK_MAX_ARGS, BOOST_FUNCTION_MAX_ARGS) )
+
+#ifdef BOOST_TEST_DECL
+# define MOCK_USE_BOOST_TEST
+#endif
+
+#endif // #ifndef MOCK_CONFIG_HPP_INCLUDED
diff --git a/src/libraries/turtle/constraint.hpp b/src/libraries/turtle/constraint.hpp
new file mode 100644
index 0000000..d1eefb8
--- /dev/null
+++ b/src/libraries/turtle/constraint.hpp
@@ -0,0 +1,132 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_CONSTRAINT_HPP_INCLUDED
+#define MOCK_CONSTRAINT_HPP_INCLUDED
+
+#include "placeholder.hpp"
+#include "functional.hpp"
+#include "format.hpp"
+#include
+
+namespace mock
+{
+ template< typename Functor, typename Description >
+ const detail::placeholder< Functor > constraint( const Functor& f,
+ const Description& desc )
+ {
+ std::stringstream s;
+ s << std::boolalpha << desc;
+ return detail::placeholder< Functor >( f, s.str() );
+ }
+ template< typename Functor >
+ const detail::placeholder< Functor > constraint( const Functor& f )
+ {
+ return detail::placeholder< Functor >( f, "?" );
+ }
+ template< typename Functor, typename T >
+ const detail::placeholder< Functor > constraint( const Functor& f,
+ const std::string& name,
+ const T& t )
+ {
+ return detail::placeholder< Functor >( f,
+ name + "( " + detail::format( t ) + " )" );
+ }
+
+namespace detail
+{
+ template<>
+ struct placeholder< nothing >
+ {
+ placeholder()
+ : desc_( "any" )
+ {}
+ nothing functor_;
+ std::string desc_;
+ };
+ template<>
+ struct placeholder< negation >
+ {
+ placeholder()
+ : desc_( "negate" )
+ {}
+ negation functor_;
+ std::string desc_;
+ };
+ template<>
+ struct placeholder< evaluation >
+ {
+ placeholder()
+ : desc_( "evaluate" )
+ {}
+ evaluation functor_;
+ std::string desc_;
+ };
+}
+ const detail::placeholder< detail::nothing > any;
+ const detail::placeholder< detail::negation > negate;
+ const detail::placeholder< detail::evaluation > evaluate;
+
+ template< typename T >
+ detail::placeholder< detail::equality< T > > equal( T t )
+ {
+ return constraint( detail::equality< T >( t ), "equal", t );
+ }
+
+ template< typename T >
+ detail::placeholder< detail::identity< T > > same( T& t )
+ {
+ return constraint( detail::identity< T >( boost::ref( t ) ),
+ "same", &t );
+ }
+
+ template< typename T >
+ detail::placeholder< detail::inferiority< T > > less( T t )
+ {
+ return constraint( detail::inferiority< T >( t ), "less", t );
+ }
+
+ template< typename T >
+ detail::placeholder< detail::superiority< T > > greater( T t )
+ {
+ return constraint( detail::superiority< T >( t ), "greater", t );
+ }
+
+ template< typename T >
+ detail::placeholder<
+ detail::or_< detail::inferiority< T >, detail::equality< T > > >
+ less_equal( T t )
+ {
+ return constraint( (less( t ) || equal( t )).functor_,
+ "less_equal", t );
+ }
+
+ template< typename T >
+ detail::placeholder<
+ detail::or_< detail::superiority< T >, detail::equality< T > > >
+ greater_equal( T t )
+ {
+ return constraint( (greater( t ) || equal( t )).functor_,
+ "greater_equal", t );
+ }
+
+ template< typename T >
+ detail::placeholder< detail::assignment< T > > assign( T t )
+ {
+ return constraint( detail::assignment< T >( t ), "assign", t );
+ }
+
+ template< typename T >
+ detail::placeholder< detail::retrieval< T > > retrieve( T& t )
+ {
+ return constraint( detail::retrieval< T >( boost::ref( t ) ),
+ "retrieve", t );
+ }
+}
+
+#endif // #ifndef MOCK_CONSTRAINT_HPP_INCLUDED
diff --git a/src/libraries/turtle/error.hpp b/src/libraries/turtle/error.hpp
new file mode 100644
index 0000000..a8ce8e2
--- /dev/null
+++ b/src/libraries/turtle/error.hpp
@@ -0,0 +1,98 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_ERROR_HPP_INCLUDED
+#define MOCK_ERROR_HPP_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ class errors_t : public boost::unit_test::singleton< errors_t >
+ {
+ public:
+ long count_;
+ private:
+ friend class boost::unit_test::singleton< errors_t >;
+ errors_t()
+ : count_( 0 )
+ {}
+ };
+ BOOST_TEST_SINGLETON_INST( errors )
+}
+
+ class exception : public boost::execution_exception
+ {
+ public:
+ explicit exception( const std::string& s )
+ : boost::execution_exception( boost::execution_exception::user_error, s )
+ {}
+ };
+
+ template< typename Result >
+ struct boost_test_error_policy
+ {
+ static void missing_result_specification()
+ {
+ ++detail::errors.count_;
+ static std::string m;
+ m = "mock error : missing result specification";
+ throw mock::exception( m );
+ }
+
+ static Result no_match( const std::string& context )
+ {
+ ++detail::errors.count_;
+ static std::string m;
+ m = "mock error : unexpected call : " + context;
+ throw mock::exception( m );
+ }
+
+ static void sequence_failed( const std::string& context,
+ const std::string& /*file*/, int /*line*/ )
+ {
+ ++detail::errors.count_;
+ static std::string m;
+ m = "mock error : unexpected call : " + context;
+ throw mock::exception( m );
+ }
+
+ static void verification_failed( const std::string& context,
+ const std::string& file, int line )
+ {
+ notify( "verification failed : " + context, file, line );
+ }
+
+ static void untriggered_expectation( const std::string& context,
+ const std::string& file, int line )
+ {
+ if( detail::errors.count_ == 0 )
+ notify( "untriggered expectation : " + context, file, line );
+ }
+
+ static void notify( const std::string& message,
+ const std::string& file, int line )
+ {
+ boost::test_tools::tt_detail::check_impl(
+ false,
+ boost::unit_test::lazy_ostream::instance() << message,
+ file, (std::size_t)line,
+ boost::test_tools::tt_detail::CHECK,
+ boost::test_tools::tt_detail::CHECK_MSG,
+ 0 );
+ }
+ };
+}
+
+#endif // #ifndef MOCK_ERROR_HPP_INCLUDED
diff --git a/src/libraries/turtle/expectation.hpp b/src/libraries/turtle/expectation.hpp
new file mode 100644
index 0000000..9a52199
--- /dev/null
+++ b/src/libraries/turtle/expectation.hpp
@@ -0,0 +1,202 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_EXPECTATION_HPP_INCLUDED
+#define MOCK_EXPECTATION_HPP_INCLUDED
+
+#include "config.hpp"
+#include "error.hpp"
+#include "verifiable.hpp"
+#include "matcher.hpp"
+#include "node.hpp"
+#include "root.hpp"
+#include "format.hpp"
+#include "invocation.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+ template< typename Signature,
+ typename ErrorPolicy = boost_test_error_policy<
+ BOOST_DEDUCED_TYPENAME boost::function<
+ Signature >::result_type > > // $$$$ MAT : concept check Signature is actually a signature
+ class expectation : private verifiable
+ {
+ public:
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function< Signature >::result_type result_type;
+ typedef detail::matcher< result_type,
+ Signature,
+ ErrorPolicy,
+ boost::function< Signature >::arity >
+ matcher_type;
+
+ expectation( node& parent = root, const std::string& name = "?" )
+ : name_( name )
+ , parent_( &parent )
+ , valid_( true )
+ {
+ parent_->add( *this );
+ }
+ expectation( const std::string& name )
+ : name_( name )
+ , parent_( &root )
+ , valid_( true )
+ {
+ parent_->add( *this );
+ }
+ virtual ~expectation()
+ {
+ parent_->remove( *this );
+ for( matchers_cit it = matchers_.begin();
+ it != matchers_.end(); ++it )
+ if( valid_ && ! it->verify() )
+ ErrorPolicy::untriggered_expectation(
+ context(), it->file(), it->line() );
+ }
+
+ expectation& set_name( const std::string& name )
+ {
+ name_ = name;
+ return *this;
+ }
+ expectation& set_parent( node& parent )
+ {
+ parent_->remove( *this );
+ parent.add( *this );
+ parent_ = &parent;
+ return *this;
+ }
+
+ virtual bool verify()
+ {
+ for( matchers_cit it = matchers_.begin();
+ it != matchers_.end(); ++it )
+ if( !it->verify() )
+ {
+ valid_ = false;
+ ErrorPolicy::verification_failed( context(),
+ it->file(), it->line() );
+ }
+ return valid_;
+ }
+ virtual void reset()
+ {
+ valid_ = true;
+ matchers_.clear();
+ }
+
+ matcher_type& expect( const std::string& file, int line )
+ {
+ matchers_.push_back( matcher_type() );
+ matchers_.back().set_location( file, line );
+ valid_ = true;
+ return matchers_.back();
+ }
+ matcher_type& expect()
+ {
+ matchers_.push_back( matcher_type() );
+ valid_ = true;
+ return matchers_.back();
+ }
+
+ result_type operator()() const
+ {
+ for( matchers_cit it = matchers_.begin();
+ it != matchers_.end(); ++it )
+ if( it->is_valid() )
+ {
+ if( !it->invoke() )
+ {
+ valid_ = false;
+ ErrorPolicy::sequence_failed( context( "" ),
+ it->file(), it->line() );
+ }
+ return it->functor()();
+ }
+ valid_ = false;
+ return ErrorPolicy::no_match( context( "" ) );
+ }
+
+#define MOCK_EXPECTATION_PARAMETER(z, n, d) BOOST_PP_COMMA_IF(n) const_cast< A##n & >( a##n )
+#define MOCK_EXPECTATION_DETAIL(z, n, d) + ", " + detail::format( a##n )
+#define MOCK_EXPECTATION_PARAMETERS(n) \
+ detail::format( a0 ) BOOST_PP_REPEAT_FROM_TO(1, n, MOCK_EXPECTATION_DETAIL, BOOST_PP_EMPTY)
+#define MOCK_EXPECTATION_OPERATOR(z, n, d) \
+ template< BOOST_PP_ENUM_PARAMS(n, typename A) > \
+ result_type operator()( BOOST_PP_ENUM_BINARY_PARAMS(n, const A, & a) ) const \
+ { \
+ for( matchers_cit it = matchers_.begin(); it != matchers_.end(); ++it ) \
+ if( it->is_valid( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_EXPECTATION_PARAMETER, BOOST_PP_EMPTY) ) ) \
+ { \
+ if( !it->invoke() ) \
+ { \
+ valid_ = false; \
+ ErrorPolicy::sequence_failed( context( MOCK_EXPECTATION_PARAMETERS(n) ), it->file(), it->line() ); \
+ } \
+ return it->functor()( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_EXPECTATION_PARAMETER, BOOST_PP_EMPTY) ); \
+ } \
+ valid_ = false; \
+ return ErrorPolicy::no_match( context( MOCK_EXPECTATION_PARAMETERS(n) ) ); \
+ }
+ BOOST_PP_REPEAT_FROM_TO(1, MOCK_MAX_ARGS, MOCK_EXPECTATION_OPERATOR, BOOST_PP_EMPTY)
+#undef MOCK_EXPECTATION_PARAMETER
+#undef MOCK_EXPECTATION_PARAMETERS
+#undef MOCK_EXPECTATION_DETAIL
+#undef MOCK_EXPECTATION_OPERATOR
+
+ friend std::ostream& operator<<( std::ostream& s, const expectation& e )
+ {
+ return s << e.context();
+ }
+
+ private:
+ typedef std::list< matcher_type > matchers_type;
+ typedef BOOST_DEDUCED_TYPENAME
+ matchers_type::const_iterator matchers_cit;
+
+ void serialize( std::ostream& s ) const
+ {
+ for( matchers_cit it = matchers_.begin();
+ it != matchers_.end(); ++it )
+ s << std::endl << *it;
+ }
+
+ std::string context() const
+ {
+ std::stringstream s;
+ s << *parent_ << name_;
+ serialize( s );
+ return s.str();
+ }
+ std::string context( const std::string& parameters ) const
+ {
+ std::stringstream s;
+ s << *parent_ << name_;
+ if( parameters.empty() )
+ s << "()";
+ else
+ s << "( " << parameters << " )";
+ serialize( s );
+ return s.str();
+ }
+
+ std::string name_;
+ node* parent_;
+ mutable bool valid_;
+ matchers_type matchers_;
+ };
+}
+
+#endif // #ifndef MOCK_EXPECTATION_HPP_INCLUDED
diff --git a/src/libraries/turtle/format.hpp b/src/libraries/turtle/format.hpp
new file mode 100644
index 0000000..03e596a
--- /dev/null
+++ b/src/libraries/turtle/format.hpp
@@ -0,0 +1,78 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_FORMAT_HPP_INCLUDED
+#define MOCK_FORMAT_HPP_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ struct eater
+ {
+ template< typename T >
+ eater( const T& ) {}
+ };
+
+ struct eaten
+ {};
+
+ template< typename S >
+ eaten operator<<( S& s, const eater& );
+
+ template< int I >
+ struct selector
+ {
+ };
+ template<>
+ struct selector< sizeof( std::ostream& ) >
+ {
+ typedef boost::true_type type;
+ };
+ template<>
+ struct selector< sizeof( eaten ) >
+ {
+ typedef boost::false_type type;
+ };
+
+ template< typename T >
+ struct is_serializable
+ {
+ static std::ostream& s();
+ static const T& t();
+
+ typedef BOOST_DEDUCED_TYPENAME
+ selector< sizeof( s() << t() ) >::type type;
+ };
+
+ template< typename T >
+ std::string format( const T& t,
+ BOOST_DEDUCED_TYPENAME boost::enable_if<
+ BOOST_DEDUCED_TYPENAME detail::is_serializable< T >::type >::type* = 0 )
+ {
+ std::stringstream s;
+ static_cast< std::ostream& >( s ) << std::boolalpha << t;
+ return s.str();
+ }
+ template< typename T >
+ std::string format( const T&,
+ BOOST_DEDUCED_TYPENAME boost::disable_if<
+ BOOST_DEDUCED_TYPENAME detail::is_serializable< T >::type >::type* = 0 )
+ {
+ return "?";
+ }
+}
+}
+
+#endif // #ifndef MOCK_FORMAT_HPP_INCLUDED
diff --git a/src/libraries/turtle/functional.hpp b/src/libraries/turtle/functional.hpp
new file mode 100644
index 0000000..3b0b2df
--- /dev/null
+++ b/src/libraries/turtle/functional.hpp
@@ -0,0 +1,160 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_FUNCTIONAL_HPP_INCLUDED
+#define MOCK_FUNCTIONAL_HPP_INCLUDED
+
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ class nothing
+ {
+ public:
+ template< typename Y >
+ bool operator()( const Y& ) const
+ {
+ return true;
+ }
+ };
+
+ class negation
+ {
+ public:
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return ! y;
+ }
+ };
+
+ class evaluation
+ {
+ public:
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return y();
+ }
+ };
+
+ template< typename T >
+ class equality
+ {
+ public:
+ explicit equality( const T& t )
+ : t_( t )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return y == t_;
+ }
+ private:
+ T t_;
+ };
+
+ template< typename T >
+ class identity
+ {
+ public:
+ explicit identity( const boost::reference_wrapper< T >& t )
+ : t_( t )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return &y == t_.get_pointer();
+ }
+ private:
+ boost::reference_wrapper< T > t_;
+ };
+
+ template< typename T >
+ class inferiority
+ {
+ public:
+ explicit inferiority( const T& t )
+ : t_( t )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return y < t_;
+ }
+ private:
+ T t_;
+ };
+
+ template< typename T >
+ class superiority
+ {
+ public:
+ explicit superiority( const T& t )
+ : t_( t )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return y > t_;
+ }
+ private:
+ T t_;
+ };
+
+ template< typename T >
+ class assignment
+ {
+ public:
+ explicit assignment( const T& t )
+ : t_( t )
+ {}
+ template< typename Y >
+ bool operator()( Y& y ) const
+ {
+ y = t_;
+ return true;
+ }
+ private:
+ T t_;
+ };
+
+ template< typename T >
+ class retrieval
+ {
+ public:
+ explicit retrieval( const boost::reference_wrapper< T >& t )
+ : t_( t )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y,
+ BOOST_DEDUCED_TYPENAME boost::disable_if<
+ boost::is_convertible< Y*, T >, Y >::type* = 0 ) const
+ {
+ t_.get() = y;
+ return true;
+ }
+ template< typename Y >
+ bool operator()( Y& y,
+ BOOST_DEDUCED_TYPENAME boost::enable_if<
+ boost::is_convertible< Y*, T >, Y >::type* = 0 ) const
+ {
+ t_.get() = &y;
+ return true;
+ }
+ private:
+ boost::reference_wrapper< T > t_;
+ };
+}
+}
+
+#endif // #ifndef MOCK_FUNCTIONAL_HPP_INCLUDED
diff --git a/src/libraries/turtle/invocation.hpp b/src/libraries/turtle/invocation.hpp
new file mode 100644
index 0000000..d833923
--- /dev/null
+++ b/src/libraries/turtle/invocation.hpp
@@ -0,0 +1,176 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_INVOCATION_HPP_INCLUDED
+#define MOCK_INVOCATION_HPP_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ class invocation : private boost::noncopyable
+ {
+ public:
+ invocation() {}
+
+ virtual ~invocation() {}
+
+ // Trigger invocation
+ // returns false if the invocation has failed
+ virtual bool invoke() = 0;
+
+ // Test whether the invocation is exhausted or not
+ // returns false if the invocation is exhausted
+ virtual bool is_valid() const = 0;
+
+ // Verify invocation
+ virtual bool verify() const = 0;
+
+ friend inline std::ostream& operator<<( std::ostream& s, const invocation& i )
+ {
+ return i.serialize( s );
+ }
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const = 0;
+ };
+
+ class between : public invocation
+ {
+ public:
+ between( std::size_t min, std::size_t max )
+ : min_ ( min )
+ , max_ ( max )
+ , count_( 0 )
+ {
+ if( min > max )
+ throw std::invalid_argument( "'min' > 'max'" );
+ }
+
+ virtual bool invoke()
+ {
+ if( count_ == max_ )
+ return false;
+ ++count_;
+ return true;
+ }
+
+ virtual bool is_valid() const
+ {
+ return count_ < max_;
+ }
+
+ virtual bool verify() const
+ {
+ return min_ <= count_ && count_ <= max_;
+ }
+
+ protected:
+ const std::size_t min_, max_;
+ std::size_t count_;
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "between( " << count_ << "/[" << min_ << ',' << max_ << "] )";
+ }
+ };
+
+ class exactly : public between
+ {
+ public:
+ explicit exactly( std::size_t count )
+ : between( count, count )
+ {}
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "exactly( " << count_ << '/' << max_ << " )";
+ }
+ };
+
+ class never : public exactly
+ {
+ public:
+ never()
+ : exactly( 0 )
+ {}
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "never()";
+ }
+ };
+
+ class once : public exactly
+ {
+ public:
+ once()
+ : exactly( 1 )
+ {}
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "once()";
+ }
+ };
+
+ class at_least : public between
+ {
+ public:
+ explicit at_least( std::size_t min )
+ : between( min, std::numeric_limits< std::size_t >::max() )
+ {}
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "at_least( " << count_ << '/' << min_ << " )";
+ }
+ };
+
+ class at_most : public between
+ {
+ public:
+ explicit at_most( std::size_t max )
+ : between( 0, max )
+ {}
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "at_most( " << count_ << '/' << max_ << " )";
+ }
+ };
+
+ class unlimited : public at_least
+ {
+ public:
+ unlimited()
+ : at_least( 0 )
+ {}
+
+ private:
+ virtual std::ostream& serialize( std::ostream& s ) const
+ {
+ return s << "unlimited()";
+ }
+ };
+}
+}
+
+#endif // #ifndef MOCK_INVOCATION_HPP_INCLUDED
diff --git a/src/libraries/turtle/matcher.hpp b/src/libraries/turtle/matcher.hpp
new file mode 100644
index 0000000..a685afc
--- /dev/null
+++ b/src/libraries/turtle/matcher.hpp
@@ -0,0 +1,222 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_MATCHER_HPP_INCLUDED
+#define MOCK_MATCHER_HPP_INCLUDED
+
+#include "config.hpp"
+#include "invocation.hpp"
+#include "result.hpp"
+#include "sequence.hpp"
+#include "check.hpp"
+#include "constraint.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ class matcher_base : private orderable
+ {
+ public:
+ matcher_base()
+ : i_( new detail::unlimited() )
+ , file_( "unknown location" )
+ , line_( 0 )
+ {}
+ virtual ~matcher_base()
+ {
+ for( sequences_cit it = sequences_.begin();
+ it != sequences_.end(); ++it )
+ (*it)->remove( *this );
+ }
+
+ void set_location( const std::string& file, int line )
+ {
+ file_ = file;
+ line_ = line;
+ }
+
+ bool verify() const
+ {
+ return i_->verify();
+ }
+
+ bool invoke() const
+ {
+ for( sequences_cit it = sequences_.begin();
+ it != sequences_.end(); ++it )
+ if( ! (*it)->is_valid( *this ) )
+ return false;
+ bool result = i_->invoke();
+ for( sequences_cit it = sequences_.begin();
+ it != sequences_.end(); ++it )
+ (*it)->call( *this );
+ return result;
+ }
+
+ matcher_base& in( sequence& s )
+ {
+ s.add( *this );
+ sequences_.push_back( &s );
+ return *this;
+ }
+
+ const std::string& file() const
+ {
+ return file_;
+ }
+ int line() const
+ {
+ return line_;
+ }
+
+ protected:
+ boost::shared_ptr< detail::invocation > i_;
+
+ void expect( detail::invocation* i )
+ {
+ i_.reset( i );
+ }
+
+ private:
+ virtual void remove( sequence& s )
+ {
+ sequences_.erase( std::remove( sequences_.begin(),
+ sequences_.end(), &s ), sequences_.end() );
+ }
+
+ typedef std::vector< sequence* > sequences_type;
+ typedef sequences_type::const_iterator sequences_cit;
+
+ sequences_type sequences_;
+ std::string file_;
+ int line_;
+ };
+
+ template< typename Result, typename Signature, typename ErrorPolicy, int >
+ class matcher
+ {
+ };
+
+#define MOCK_INVOCATIONS \
+ matcher& once() \
+ { \
+ expect( new detail::once() ); \
+ return *this; \
+ } \
+ matcher& never() \
+ { \
+ expect( new detail::never() ); \
+ return *this; \
+ } \
+ matcher& exactly( std::size_t count ) \
+ { \
+ expect( new detail::exactly( count ) ); \
+ return *this; \
+ } \
+ matcher& at_least( std::size_t min ) \
+ { \
+ expect( new detail::at_least( min ) ); \
+ return *this; \
+ } \
+ matcher& at_most( std::size_t max ) \
+ { \
+ expect( new detail::at_most( max ) ); \
+ return *this; \
+ } \
+ matcher& between( std::size_t min, std::size_t max ) \
+ { \
+ expect( new detail::at_most( min, max ) ); \
+ return *this; \
+ }
+
+ template< typename Result, typename Signature, typename ErrorPolicy >
+ class matcher< Result, Signature, ErrorPolicy, 0 >
+ : public matcher_base, public result< Result, Signature, ErrorPolicy >
+ {
+ public:
+ bool is_valid() const
+ {
+ return i_->is_valid();
+ }
+
+ MOCK_INVOCATIONS
+
+ friend std::ostream& operator<<( std::ostream& s, const matcher& m )
+ {
+ return s << (m.i_->is_valid() ? '.' : 'v')
+ << " expect( " << *m.i_ << " )";
+ }
+ };
+
+#define MOCK_MATCHER_TYPEDEF(z, n, d) \
+ typedef BOOST_DEDUCED_TYPENAME \
+ boost::function< Signature >::BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type) arg##n##_type; \
+ typedef detail::check< arg##n##_type > constraint##n##_type;
+#define MOCK_MATCHER_CONSTRUCTOR(z, n, d) BOOST_PP_COMMA_IF(n) c##n##_ ( any )
+#define MOCK_MATCHER_WITH(z, n, d) c##n##_ = constraint##n##_type( c##n );
+#define MOCK_MATCHER_MEMBER(z, n, d) constraint##n##_type c##n##_;
+#define MOCK_MATCHER_IS_VALID_PARAMS(z, n, d) BOOST_PP_COMMA_IF(n) arg##n##_type a##n
+#define MOCK_MATCHER_IS_VALID(z, n, d) && c##n##_( a##n )
+#define MOCK_MATCHER_SERIALIZE(z, n, d) << ", " << m.c##n##_
+#define MOCK_MATCHER(z, n, d) \
+ template< typename Result, typename Signature, typename ErrorPolicy > \
+ class matcher< Result, Signature, ErrorPolicy, n > \
+ : public matcher_base, public result< Result, Signature, ErrorPolicy > \
+ { \
+ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MATCHER_TYPEDEF, BOOST_PP_EMPTY) \
+ public: \
+ matcher() \
+ : BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MATCHER_CONSTRUCTOR, BOOST_PP_EMPTY) \
+ {} \
+ template< BOOST_PP_ENUM_PARAMS(n, typename C) > \
+ matcher& with( BOOST_PP_ENUM_BINARY_PARAMS(n, const C, & c) ) \
+ { \
+ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MATCHER_WITH, BOOST_PP_EMPTY) \
+ return *this; \
+ } \
+ bool is_valid( BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MATCHER_IS_VALID_PARAMS, BOOST_PP_EMPTY) ) const \
+ { \
+ return i_->is_valid() \
+ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MATCHER_IS_VALID, BOOST_PP_EMPTY); \
+ } \
+ MOCK_INVOCATIONS \
+ friend std::ostream& operator<<( std::ostream& s, const matcher& m ) \
+ { \
+ return s << (m.i_->is_valid() ? '.' : 'v') \
+ << " expect( " << *m.i_ << " ).with( " \
+ << m.c0_ \
+ BOOST_PP_REPEAT_FROM_TO(1, n, MOCK_MATCHER_SERIALIZE, BOOST_PP_EMPTY) \
+ << " )"; \
+ } \
+ private: \
+ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MATCHER_MEMBER, BOOST_PP_EMPTY) \
+ };
+ BOOST_PP_REPEAT_FROM_TO(1, MOCK_MAX_ARGS, MOCK_MATCHER, BOOST_PP_EMPTY)
+
+#undef MOCK_INVOCATIONS
+#undef MOCK_MATCHER_TYPEDEF
+#undef MOCK_MATCHER_CONSTRUCTOR
+#undef MOCK_MATCHER_WITH
+#undef MOCK_MATCHER_MEMBER
+#undef MOCK_MATCHER_IS_VALID_PARAMS
+#undef MOCK_MATCHER_IS_VALID
+#undef MOCK_MATCHER_SERIALIZE
+#undef MOCK_MATCHER
+
+}
+}
+
+#endif // #ifndef MOCK_MATCHER_HPP_INCLUDED
diff --git a/src/libraries/turtle/node.hpp b/src/libraries/turtle/node.hpp
new file mode 100644
index 0000000..e46a81b
--- /dev/null
+++ b/src/libraries/turtle/node.hpp
@@ -0,0 +1,91 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_NODE_HPP_INCLUDED
+#define MOCK_NODE_HPP_INCLUDED
+
+#include "verifiable.hpp"
+#include
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+ class node : private verifiable
+ {
+ public:
+ node()
+ : parent_( 0 )
+ {}
+ explicit node( node& parent )
+ : verifiable()
+ , parent_( &parent )
+ {
+ if( parent_ )
+ parent_->add( *this );
+ }
+ virtual ~node()
+ {
+ if( parent_ )
+ parent_->remove( *this );
+ }
+
+ void set_parent( node& parent )
+ {
+ if( parent_ )
+ parent_->remove( *this );
+ parent_ = &parent;
+ parent_->add( *this );
+ }
+
+ void add( verifiable& e )
+ {
+ v_.push_back( &e );
+ }
+ void remove( verifiable& e )
+ {
+ v_.erase( std::remove( v_.begin(), v_.end(), &e ), v_.end() );
+ }
+
+ virtual bool verify()
+ {
+ bool valid = true;
+ for( verifiables_cit it = v_.begin(); it != v_.end(); ++it )
+ if( ! (*it)->verify() )
+ valid = false;
+ return valid;
+ }
+ virtual void reset()
+ {
+ std::for_each( v_.begin(), v_.end(),
+ std::mem_fun( &verifiable::reset ) );
+ }
+
+ friend std::ostream& operator<<( std::ostream& s, node& n )
+ {
+ if( n.parent_ )
+ s << *n.parent_;
+ n.serialize( s );
+ return s;
+ }
+
+ protected:
+ virtual void serialize( std::ostream& s ) const = 0;
+
+ private:
+ typedef std::vector< verifiable* > verifiables_type;
+ typedef verifiables_type::const_iterator verifiables_cit;
+
+ node* parent_;
+ std::vector< verifiable* > v_;
+ };
+}
+
+#endif // #ifndef MOCK_NODE_HPP_INCLUDED
diff --git a/src/libraries/turtle/object.hpp b/src/libraries/turtle/object.hpp
new file mode 100644
index 0000000..e180c41
--- /dev/null
+++ b/src/libraries/turtle/object.hpp
@@ -0,0 +1,47 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_OBJECT_HPP_INCLUDED
+#define MOCK_OBJECT_HPP_INCLUDED
+
+#include "node.hpp"
+#include "root.hpp"
+#include
+#include
+
+namespace mock
+{
+ class object : public node
+ {
+ public:
+ explicit object( node& parent = root, const std::string& name = "" )
+ : node( parent )
+ , name_( name )
+ {}
+ explicit object( const std::string& name )
+ : node( root )
+ , name_( name )
+ {}
+
+ void set_name( const std::string& name )
+ {
+ name_ = name;
+ }
+
+ private:
+ virtual void serialize( std::ostream& s ) const
+ {
+ s << (name_.empty() ? "?" : name_) << "::";
+ }
+
+ private:
+ std::string name_;
+ };
+}
+
+#endif // #ifndef MOCK_OBJECT_HPP_INCLUDED
diff --git a/src/libraries/turtle/placeholder.hpp b/src/libraries/turtle/placeholder.hpp
new file mode 100644
index 0000000..b15548b
--- /dev/null
+++ b/src/libraries/turtle/placeholder.hpp
@@ -0,0 +1,111 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_PLACEHOLDER_HPP_INCLUDED
+#define MOCK_PLACEHOLDER_HPP_INCLUDED
+
+#include
+
+namespace mock
+{
+namespace detail
+{
+ template< typename Functor >
+ struct placeholder
+ {
+ placeholder( const Functor& f, const std::string& desc )
+ : functor_( f )
+ , desc_ ( desc )
+ {}
+ Functor functor_;
+ std::string desc_;
+ };
+
+ template< typename Constraint1, typename Constraint2 >
+ class and_
+ {
+ public:
+ and_( const Constraint1& c1, const Constraint2& c2 )
+ : c1_( c1 )
+ , c2_( c2 )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return c1_( y ) && c2_( y );
+ }
+ private:
+ Constraint1 c1_;
+ Constraint2 c2_;
+ };
+
+ template< typename Constraint1, typename Constraint2 >
+ class or_
+ {
+ public:
+ or_( const Constraint1& c1, const Constraint2& c2 )
+ : c1_( c1 )
+ , c2_( c2 )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return c1_( y ) || c2_( y );
+ }
+ private:
+ Constraint1 c1_;
+ Constraint2 c2_;
+ };
+
+ template< typename Constraint >
+ class not_
+ {
+ public:
+ explicit not_( const Constraint& c )
+ : c_( c )
+ {}
+ template< typename Y >
+ bool operator()( const Y& y ) const
+ {
+ return ! c_( y );
+ }
+ private:
+ Constraint c_;
+ };
+
+ template< typename F1, typename F2 >
+ const placeholder< or_< F1, F2 > >
+ operator||( const placeholder< F1 >& lhs,
+ const placeholder< F2 >& rhs )
+ {
+ return placeholder< or_< F1, F2 > >(
+ or_< F1, F2 >( lhs.functor_, rhs.functor_ ),
+ "(" + lhs.desc_ + " || " + rhs.desc_ + ")" );
+ }
+
+ template< typename F1, typename F2 >
+ const placeholder< and_< F1, F2 > >
+ operator&&( const placeholder< F1 >& lhs,
+ const placeholder< F2 >& rhs )
+ {
+ return placeholder< and_< F1, F2 > >(
+ and_< F1, F2 >( lhs.functor_, rhs.functor_ ),
+ "(" + lhs.desc_ + " && " + rhs.desc_ + ")" );
+ }
+
+ template< typename F >
+ const placeholder< not_< F > >
+ operator!( const placeholder< F >& ph )
+ {
+ return placeholder< not_< F > >(
+ not_< F >( ph.functor_ ), "! " + ph.desc_ );
+ }
+}
+}
+
+#endif // #ifndef MOCK_PLACEHOLDER_HPP_INCLUDED
diff --git a/src/libraries/turtle/result.hpp b/src/libraries/turtle/result.hpp
new file mode 100644
index 0000000..013bc14
--- /dev/null
+++ b/src/libraries/turtle/result.hpp
@@ -0,0 +1,254 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_RESULT_HPP_INCLUDED
+#define MOCK_RESULT_HPP_INCLUDED
+
+#include
+#include
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ template< typename T, typename Signature, typename ErrorPolicy >
+ class result
+ {
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function< Signature > functor_type;
+
+ public:
+ template< typename Value >
+ void returns( Value v )
+ {
+ set( v );
+ }
+
+ void calls( const functor_type& f )
+ {
+ if( !f )
+ throw std::invalid_argument( "null functor" );
+ f_ = f;
+ }
+
+ template< typename Exception >
+ void throws( Exception e )
+ {
+ f_ = boost::bind( &throw_exception< Exception >, e );
+ }
+
+ const functor_type& functor() const
+ {
+ if( !f_ )
+ ErrorPolicy::missing_result_specification();
+ return f_;
+ }
+
+ private:
+ void set( T t )
+ {
+ f_ = boost::bind( &return_value, t );
+ }
+ template< typename Y >
+ void set( const boost::reference_wrapper< Y >& t )
+ {
+ f_ = boost::bind( &return_value, t );
+ }
+
+ static T return_value( T t )
+ {
+ return t;
+ }
+
+ template< typename Exception >
+ static T throw_exception( const Exception& e )
+ {
+ throw e;
+ }
+
+ functor_type f_;
+ };
+
+ template< typename T, typename Signature, typename ErrorPolicy >
+ class result< T*, Signature, ErrorPolicy >
+ {
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function< Signature > functor_type;
+
+ public:
+ void returns( T* t )
+ {
+ f_ = boost::bind( &return_value, t );
+ }
+ template< typename Y >
+ void returns( const boost::reference_wrapper< Y >& t )
+ {
+ f_ = boost::bind( &return_value, t );
+ }
+
+ void calls( const functor_type& f )
+ {
+ if( !f )
+ throw std::invalid_argument( "null functor" );
+ f_ = f;
+ }
+
+ template< typename Exception >
+ void throws( Exception e )
+ {
+ f_ = boost::bind( &throw_exception< Exception >, e );
+ }
+
+ const functor_type& functor() const
+ {
+ if( !f_ )
+ ErrorPolicy::missing_result_specification();
+ return f_;
+ }
+
+ private:
+ static T* return_value( T* t )
+ {
+ return t;
+ }
+
+ template< typename Exception >
+ static T* throw_exception( const Exception& e )
+ {
+ throw e;
+ }
+
+ functor_type f_;
+ };
+
+ template< typename Signature, typename ErrorPolicy >
+ class result< void, Signature, ErrorPolicy >
+ {
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function< Signature > functor_type;
+
+ public:
+ result()
+ : f_( boost::bind( ¬hing ) )
+ {}
+
+ void calls( const functor_type& f )
+ {
+ if( !f )
+ throw std::invalid_argument( "null functor" );
+ f_ = f;
+ }
+
+ template< typename Exception >
+ void throws( Exception e )
+ {
+ f_ = boost::bind( &throw_exception< Exception >, e );
+ }
+
+ const functor_type& functor() const
+ {
+ return f_;
+ }
+
+ private:
+ static void nothing()
+ {}
+
+ template< typename Exception >
+ static void throw_exception( const Exception& e )
+ {
+ throw e;
+ }
+
+ functor_type f_;
+ };
+
+ template< typename T, typename Signature, typename ErrorPolicy >
+ class result< std::auto_ptr< T >, Signature, ErrorPolicy >
+ {
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function< Signature > functor_type;
+
+ public:
+ result()
+ : t_()
+ , f_()
+ {}
+ result( const result& rhs )
+ : t_( const_cast< result& >( rhs ).t_.release() )
+ , f_( t_.get() ? boost::bind( &return_value, boost::ref( t_ ) ) : rhs.f_ )
+ {}
+
+ template< typename Value >
+ void returns( Value v )
+ {
+ set( v );
+ }
+
+ void calls( const functor_type& f )
+ {
+ if( !f )
+ throw std::invalid_argument( "null functor" );
+ f_ = f;
+ }
+
+ template< typename Exception >
+ void throws( Exception e )
+ {
+ f_ = boost::bind( &throw_exception< Exception >, e );
+ t_.reset();
+ }
+
+ const functor_type& functor() const
+ {
+ if( !f_ )
+ ErrorPolicy::missing_result_specification();
+ return f_;
+ }
+
+ private:
+ template< typename Y >
+ void set( std::auto_ptr< Y > t )
+ {
+ t_ = t;
+ f_ = boost::bind( &return_value, boost::ref( t_ ) );
+ }
+ template< typename Y >
+ void set( const boost::reference_wrapper< Y >& t )
+ {
+ f_ = boost::bind( &return_value, t );
+ t_.reset();
+ }
+ template< typename Y >
+ void set( Y* t )
+ {
+ t_.reset( t );
+ f_ = boost::bind( &return_value, boost::ref( t_ ) );
+ }
+
+ static std::auto_ptr< T > return_value( std::auto_ptr< T > t )
+ {
+ return t;
+ }
+
+ template< typename Exception >
+ static std::auto_ptr< T > throw_exception( const Exception& e )
+ {
+ throw e;
+ }
+
+ mutable std::auto_ptr< T > t_;
+ functor_type f_;
+ };
+
+}
+}
+
+#endif // #ifndef MOCK_RESULT_HPP_INCLUDED
diff --git a/src/libraries/turtle/root.hpp b/src/libraries/turtle/root.hpp
new file mode 100644
index 0000000..addb59b
--- /dev/null
+++ b/src/libraries/turtle/root.hpp
@@ -0,0 +1,36 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_ROOT_HPP_INCLUDED
+#define MOCK_ROOT_HPP_INCLUDED
+
+#include "node.hpp"
+#include
+
+namespace mock
+{
+ class root_t : public boost::unit_test::singleton< root_t >, public node
+ {
+ private:
+ virtual void serialize( std::ostream& /*s*/ ) const
+ {}
+ BOOST_TEST_SINGLETON_CONS( root_t );
+ };
+ BOOST_TEST_SINGLETON_INST( root )
+
+ inline bool verify()
+ {
+ return root.verify();
+ }
+ inline void reset()
+ {
+ root.reset();
+ }
+}
+
+#endif // #ifndef MOCK_ROOT_HPP_INCLUDED
diff --git a/src/libraries/turtle/sequence.hpp b/src/libraries/turtle/sequence.hpp
new file mode 100644
index 0000000..0964d26
--- /dev/null
+++ b/src/libraries/turtle/sequence.hpp
@@ -0,0 +1,83 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_SEQUENCE_HPP_INCLUDED
+#define MOCK_SEQUENCE_HPP_INCLUDED
+
+#include
+#include
+
+namespace mock
+{
+ class sequence;
+
+namespace detail
+{
+ class orderable
+ {
+ public:
+ orderable() {}
+ virtual ~orderable() {}
+
+ virtual void remove( sequence& s ) = 0;
+ };
+}
+
+ class sequence
+ {
+ public:
+ ~sequence()
+ {
+ for( elements_it it = elements_.begin();
+ it != elements_.end(); ++it )
+ (*it)->remove( *this );
+ for( elements_it it = called_.begin();
+ it != called_.end(); ++it )
+ (*it)->remove( *this );
+ }
+
+ void add( detail::orderable& e )
+ {
+ elements_.push_back( &e );
+ }
+ void remove( detail::orderable& e )
+ {
+ elements_.erase( std::remove( elements_.begin(),
+ elements_.end(), &e ), elements_.end() );
+ called_.erase( std::remove( called_.begin(),
+ called_.end(), &e ), called_.end() );
+ }
+
+ bool is_valid( const detail::orderable& e ) const
+ {
+ return std::find( called_.begin(), called_.end(), &e )
+ == called_.end();
+ }
+
+ void call( const detail::orderable& e )
+ {
+ elements_it it =
+ std::find( elements_.begin(), elements_.end(), &e );
+ if( it != elements_.end() )
+ {
+ std::copy( elements_.begin(), it,
+ std::back_inserter( called_ ) );
+ elements_.erase( elements_.begin(), it );
+ }
+ }
+
+ private:
+ typedef std::vector< detail::orderable* > elements_type;
+ typedef elements_type::iterator elements_it;
+
+ elements_type elements_;
+ elements_type called_;
+ };
+}
+
+#endif // #ifndef MOCK_SEQUENCE_HPP_INCLUDED
diff --git a/src/libraries/turtle/tools.hpp b/src/libraries/turtle/tools.hpp
new file mode 100644
index 0000000..d654d82
--- /dev/null
+++ b/src/libraries/turtle/tools.hpp
@@ -0,0 +1,156 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_TOOLS_HPP_INCLUDED
+#define MOCK_TOOLS_HPP_INCLUDED
+
+#include "error.hpp"
+#include "object.hpp"
+#include "expectation.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#define BOOST_TYPEOF_SILENT
+#include
+#include
+
+namespace mock
+{
+namespace detail
+{
+ template< typename T >
+ T& ref( T& t )
+ {
+ return t;
+ }
+ template< typename T >
+ T& ref( T* t )
+ {
+ if( ! t )
+ throw std::invalid_argument( "derefencing null pointer" );
+ return *t;
+ }
+ template< typename T >
+ T& ref( std::auto_ptr< T >& t )
+ {
+ if( ! t.get() )
+ throw std::invalid_argument( "derefencing null pointer" );
+ return *t;
+ }
+ template< typename T >
+ T& ref( boost::shared_ptr< T >& t )
+ {
+ if( ! t.get() )
+ throw std::invalid_argument( "derefencing null pointer" );
+ return *t;
+ }
+}
+}
+
+#define MOCK_MIXIN(T) \
+ template< typename U > struct T##_mock_mixin : U \
+ { \
+ explicit T##_mock_mixin( const std::string& tag = "" ) \
+ { \
+ mock::object::set_name( BOOST_PP_STRINGIZE(T) + tag ); \
+ } \
+ explicit T##_mock_mixin( mock::node& parent, const std::string& tag = "" ) \
+ { \
+ mock::object::set_name( BOOST_PP_STRINGIZE(T) + tag ); \
+ mock::node::set_parent( parent ); \
+ } \
+ }; \
+ struct T##_super_class; \
+ typedef T##_mock_mixin< T##_super_class > T;
+#define MOCK_INTERFACE(T, I) \
+ MOCK_MIXIN(T) \
+ struct T##_typedef { typedef I interface_type; }; \
+ struct T##_super_class : I, mock::object, private T##_typedef
+#define MOCK_CLASS(T) \
+ MOCK_MIXIN(T) \
+ struct T##_super_class : mock::object
+
+namespace mock
+{
+namespace detail
+{
+ template< typename M >
+ struct signature
+ {
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function_types::result_type< M >::type result;
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function_types::parameter_types< M >::type parameters;
+ typedef BOOST_DEDUCED_TYPENAME
+ boost::function_types::function_type<
+ BOOST_DEDUCED_TYPENAME boost::mpl::push_front<
+ BOOST_DEDUCED_TYPENAME boost::mpl::pop_front<
+ BOOST_DEDUCED_TYPENAME boost::mpl::copy<
+ parameters,
+ boost::mpl::back_inserter<
+ boost::mpl::vector<>
+ >
+ >::type
+ >::type,
+ result
+ >::type
+ >::type type;
+ };
+}
+}
+
+#define MOCK_METHOD_ARG(z, n, S) BOOST_PP_COMMA_IF(n) \
+ BOOST_PP_CAT(BOOST_PP_CAT(boost::function< S >::arg, BOOST_PP_INC(n)),_type) \
+ BOOST_PP_CAT(a, BOOST_PP_INC(n))
+#define MOCK_METHOD_ARGS(n, S) \
+ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_METHOD_ARG, S)
+#define MOCK_MOCKER_ARG(z, n, d) \
+ BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(a, BOOST_PP_INC(n))
+#define MOCK_MOCKER_ARGS(n, M) \
+ BOOST_PP_REPEAT_FROM_TO(0, n, MOCK_MOCKER_ARG, BOOST_PP_EMPTY)
+#define MOCK_METHOD_STUB(M, n, S, t, c) \
+ boost::function< S >::result_type M( MOCK_METHOD_ARGS(n, S) ) c \
+ { \
+ return MOCK_MOCKER(*this, t)( MOCK_MOCKER_ARGS(n, M) ); \
+ }
+#define MOCK_METHOD_EXPECTATION(S, t) \
+ mutable mock::expectation< S > t##_exp;
+#define MOCK_METHOD_EXT(M, n, S, t) \
+ MOCK_METHOD_STUB(M, n, S, t,) \
+ MOCK_METHOD_STUB(M, n, S, t, const) \
+ MOCK_METHOD_EXPECTATION(S, t)
+#define MOCK_CONST_METHOD_EXT(M, n, S, t) \
+ MOCK_METHOD_STUB(M, n, S, t, const) \
+ MOCK_METHOD_EXPECTATION(S, t)
+#define MOCK_NON_CONST_METHOD_EXT(M, n, S, t) \
+ MOCK_METHOD_STUB(M, n, S, t,) \
+ MOCK_METHOD_EXPECTATION(S, t)
+#define MOCK_METHOD(M, n) \
+ MOCK_METHOD_EXT(M, n, MOCK_SIGNATURE(&interface_type::M), M)
+#define MOCK_SIGNATURE(pM) \
+ mock::detail::signature< BOOST_TYPEOF(pM) >::type
+#define MOCK_MOCKER(m, t) \
+ mock::detail::ref( m ).t##_exp.set_name( BOOST_PP_STRINGIZE(t) ).set_parent( \
+ const_cast< mock::object& >( dynamic_cast< const mock::object& >( mock::detail::ref( m ) ) ) )
+
+#define MOCK_EXPECT(m,t) MOCK_MOCKER(m,t).expect( __FILE__, __LINE__ )
+#define MOCK_RESET(m,t) MOCK_MOCKER(m,t).reset()
+#define MOCK_VERIFY(m,t) MOCK_MOCKER(m,t).verify()
+
+#endif // #ifndef MOCK_TOOLS_HPP_INCLUDED
diff --git a/src/libraries/turtle/verifiable.hpp b/src/libraries/turtle/verifiable.hpp
new file mode 100644
index 0000000..4f5ca3c
--- /dev/null
+++ b/src/libraries/turtle/verifiable.hpp
@@ -0,0 +1,30 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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 MOCK_VERIFIABLE_HPP_INCLUDED
+#define MOCK_VERIFIABLE_HPP_INCLUDED
+
+#include
+
+namespace mock
+{
+ class verifiable : private boost::noncopyable
+ {
+ public:
+ verifiable() {}
+ virtual ~verifiable() {}
+
+ // return false if verification fails
+ virtual bool verify() = 0;
+
+ // return to the initial state where calling verify won't throw
+ virtual void reset() = 0;
+ };
+}
+
+#endif // #ifndef MOCK_VERIFIABLE_HPP_INCLUDED
diff --git a/src/tests/turtle_test/constraint_test.cpp b/src/tests/turtle_test/constraint_test.cpp
new file mode 100644
index 0000000..d4fe4f1
--- /dev/null
+++ b/src/tests/turtle_test/constraint_test.cpp
@@ -0,0 +1,164 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+BOOST_AUTO_TEST_CASE( all_comparison_constraints_can_be_instanciated )
+{
+ mock::any;
+ mock::negate;
+ mock::evaluate;
+ mock::equal( 0 );
+ mock::less( 0 );
+ mock::greater( 0 );
+ mock::less_equal( 0 );
+ mock::greater_equal( 0 );
+}
+
+BOOST_AUTO_TEST_CASE( constraints_can_be_negated_using_the_not_operator )
+{
+ ! mock::any;
+ ! mock::negate;
+ ! mock::evaluate;
+ ! mock::equal( 0 );
+ ! mock::less( 0 );
+ ! mock::greater( 0 );
+ ! mock::less_equal( 0 );
+ ! mock::greater_equal( 0 );
+}
+
+BOOST_AUTO_TEST_CASE( constraints_can_be_combined_using_the_or_operator )
+{
+ mock::less( 0 ) || mock::greater( 0 );
+}
+
+BOOST_AUTO_TEST_CASE( constraints_can_be_combined_using_the_and_operator )
+{
+ mock::less( 0 ) && mock::greater( 0 );
+}
+
+BOOST_AUTO_TEST_CASE( same )
+{
+ int i = 0;
+ int j = 0;
+ BOOST_CHECK_EQUAL( i, j );
+ BOOST_CHECK( ! mock::same( i ).functor_( j ) );
+ BOOST_CHECK( mock::same( i ).functor_( i ) );
+}
+
+BOOST_AUTO_TEST_CASE( assign )
+{
+ {
+ int i = 0;
+ BOOST_CHECK( mock::assign( 3 ).functor_( i ) );
+ BOOST_CHECK_EQUAL( 3, i );
+ }
+ {
+ const int* i = 0;
+ const int j = 1;
+ BOOST_CHECK( mock::assign( &j ).functor_( i ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( retrieve )
+{
+ {
+ int i = 0;
+ const int j = 1;
+ BOOST_CHECK( mock::retrieve( i ).functor_( j ) );
+ BOOST_CHECK_EQUAL( i, j );
+ }
+ {
+ int* i = 0;
+ int j = 1;
+ BOOST_CHECK( mock::retrieve( i ).functor_( &j ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+ {
+ const int* i = 0;
+ const int j = 1;
+ BOOST_CHECK( mock::retrieve( i ).functor_( j ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+ {
+ int* i = 0;
+ int j = 1;
+ BOOST_CHECK( mock::retrieve( i ).functor_( j ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+ {
+ const int* i = 0;
+ const int j = 1;
+ BOOST_CHECK( mock::retrieve( i ).functor_( j ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+ {
+ int** i = 0;
+ int* j = 0;
+ BOOST_CHECK( mock::retrieve( i ).functor_( j ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+ {
+ const int** i = 0;
+ const int* j = 0;
+ BOOST_CHECK( mock::retrieve( i ).functor_( j ) );
+ BOOST_CHECK_EQUAL( i, &j );
+ }
+}
+
+namespace
+{
+ struct A
+ {
+ };
+ struct B
+ {
+ B& operator=( const A& )
+ {
+ return *this;
+ }
+ };
+}
+
+BOOST_AUTO_TEST_CASE( retrieve_uses_assignment_operator )
+{
+ B b;
+ const A a = A();
+ mock::retrieve( b ).functor_( a );
+}
+
+BOOST_AUTO_TEST_CASE( negate )
+{
+ int* i = 0;
+ int j;
+ BOOST_CHECK( mock::negate.functor_( i ) );
+ BOOST_CHECK( ! mock::negate.functor_( &j ) );
+}
+
+namespace
+{
+ bool return_true()
+ {
+ return true;
+ }
+ bool return_false()
+ {
+ return false;
+ }
+}
+
+BOOST_AUTO_TEST_CASE( evaluate )
+{
+ BOOST_CHECK( mock::evaluate.functor_( &return_true ) );
+ BOOST_CHECK( ! mock::evaluate.functor_( &return_false ) );
+}
diff --git a/src/tests/turtle_test/error_test.cpp b/src/tests/turtle_test/error_test.cpp
new file mode 100644
index 0000000..9cc0e7d
--- /dev/null
+++ b/src/tests/turtle_test/error_test.cpp
@@ -0,0 +1,27 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+BOOST_AUTO_TEST_CASE( a_mock_exception_is_not_an_std_exception_to_not_mess_with_user_exceptions )
+{
+ try
+ {
+ throw mock::exception( "" );
+ }
+ catch( std::exception& )
+ {
+ BOOST_FAIL( "mock::exception must not be an std::exception" );
+ }
+ catch( mock::exception& )
+ {}
+}
diff --git a/src/tests/turtle_test/expectation_test.cpp b/src/tests/turtle_test/expectation_test.cpp
new file mode 100644
index 0000000..1cd8d12
--- /dev/null
+++ b/src/tests/turtle_test/expectation_test.cpp
@@ -0,0 +1,762 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#define BOOST_AUTO_TEST_MAIN
+#include
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+namespace
+{
+ bool check_exception_contains( const mock::exception& e, const std::string& str )
+ {
+ return e.what().find( str ) != std::string::npos;
+ }
+}
+#define BOOST_CHECK_EXCEPTION_CONTAINS( S, C ) \
+ BOOST_CHECK_EXCEPTION( S, mock::exception, boost::bind( &check_exception_contains, _1, C ) );
+
+// functor
+
+BOOST_AUTO_TEST_CASE( an_expectation_can_be_passed_as_functor_using_boost_bind_and_boost_ref )
+{
+ mock::expectation< void() > e;
+ boost::function< void() > f = boost::bind( boost::ref( e ) );
+}
+
+// invocations
+
+BOOST_AUTO_TEST_CASE( triggering_an_empty_expectation_throws )
+{
+ {
+ mock::expectation< void() > e;
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "unexpected call" );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 1, "s" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_a_never_expectation_throws )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect().never();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "unexpected call" );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect().never();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 1, "s" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_unlimited_expectation_never_throws )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect();
+ BOOST_CHECK_NO_THROW( e() );
+ BOOST_CHECK_NO_THROW( e() );
+ }
+ {
+ mock::expectation< void( int, const std::string& ) > e;
+ e.expect();
+ BOOST_CHECK_NO_THROW( e( 1, "s" ) );
+ BOOST_CHECK_NO_THROW( e( 1, "s" ) );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_a_once_expectation_throws_after_one_call )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect().once();
+ BOOST_CHECK_NO_THROW( e() );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "unexpected call" );
+ }
+ {
+ mock::expectation< void( int, const std::string& ) > e;
+ e.expect().once();
+ BOOST_CHECK_NO_THROW( e( 1, "s" ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 1, "s" ), "unexpected call" );
+ }
+}
+
+/*
+BOOST_AUTO_TEST_CASE( literal_zero_can_be_used_in_expectation_operator_call_as_pointers )
+{
+ mock::expectation< void( int* ) > e;
+ e( 0 );
+}
+*/
+
+// verify
+
+BOOST_AUTO_TEST_CASE( verifying_an_empty_expectation_succeeds )
+{
+ {
+ mock::expectation< void() > e;
+ BOOST_CHECK( e.verify() );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ BOOST_CHECK( e.verify() );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( verifying_an_unlimited_expectation_succeeds )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect();
+ BOOST_CHECK( e.verify() );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect();
+ BOOST_CHECK( e.verify() );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( verifying_a_once_expectation_after_one_call_succeeds )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect().once();
+ e();
+ BOOST_CHECK( e.verify() );
+ }
+ {
+ mock::expectation< void( int, const std::string& ) > e;
+ e.expect().once();
+ e( 1, "s" );
+ BOOST_CHECK( e.verify() );
+ }
+}
+
+namespace
+{
+ template< typename Result >
+ struct silent_error
+ {
+ static Result no_match( const std::string& context )
+ {
+ throw std::runtime_error( __FUNCTION__ );
+ }
+ static void sequence_failed( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {}
+ static void verification_failed( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {}
+ static void untriggered_expectation( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {}
+ };
+}
+
+BOOST_AUTO_TEST_CASE( verifying_a_once_expectation_before_the_call_fails )
+{
+ {
+ mock::expectation< void(), silent_error< void > > e;
+ e.expect().once();
+ BOOST_CHECK( ! e.verify() );
+ }
+ {
+ mock::expectation< int( int, const std::string& ), silent_error< int > > e;
+ e.expect().once();
+ BOOST_CHECK( ! e.verify() );
+ }
+}
+
+// reset
+
+BOOST_AUTO_TEST_CASE( triggering_a_reset_expectation_throws )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect();
+ e.reset();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "unexpected call" );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect();
+ e.reset();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 1, "s" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( verifying_a_reset_expectation_succeeds )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect();
+ e.reset();
+ BOOST_CHECK( e.verify() );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect();
+ e.reset();
+ BOOST_CHECK( e.verify() );
+ }
+}
+
+// constraints
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_with_wrong_parameter_value_in_equal_constraint_throws )
+{
+ {
+ mock::expectation< void( int ) > e;
+ e.expect().with( 42 );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 43 ), "unexpected call" );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect().with( 42, "expected" );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 42, "actual" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( passing_raw_parameter_as_constraint_falls_back_to_using_the_equal_constraint )
+{
+ {
+ mock::expectation< void( int ) > e;
+ e.expect().with( 42 );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 43 ), "unexpected call" );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect().with( 42, "expected" );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 42, "actual" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_with_wrong_parameter_value_in_equal_or_less_constraint_throws )
+{
+ mock::expectation< void( int ) > e;
+ e.expect().with( mock::equal( 42 ) || mock::less( 42 ) );
+ BOOST_CHECK_NO_THROW( e( 41 ) );
+ BOOST_CHECK_NO_THROW( e( 42 ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 43 ), "unexpected call" );
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_with_wrong_parameter_value_in_equal_and_not_less_constraint_throws )
+{
+ mock::expectation< void( int ) > e;
+ e.expect().with( mock::equal( 42 ) && ! mock::less( 41 ) );
+ BOOST_CHECK_NO_THROW( e( 42 ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 43 ), "unexpected call" );
+}
+
+namespace
+{
+ class my_interface : boost::noncopyable
+ {
+ public:
+ virtual ~my_interface() {}
+ private:
+ virtual void my_method() = 0;
+ };
+ class my_implementation : public my_interface
+ {
+ virtual void my_method() {}
+ };
+}
+
+BOOST_AUTO_TEST_CASE( passing_call_values_by_reference_is_transparent )
+{
+ {
+ mock::expectation< void( my_interface& ) > e;
+ my_implementation imp;
+ e.expect().with( mock::same( imp ) );
+ e( imp );
+ }
+ {
+ mock::expectation< void( const my_interface& ) > e;
+ my_implementation imp;
+ e.expect().with( mock::same( imp ) );
+ e( imp );
+ }
+}
+
+namespace
+{
+ bool custom_constraint( int )
+ {
+ return false;
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_with_failing_custom_constraint_throws )
+{
+ {
+ mock::expectation< void( int ) > e;
+ e.expect().with( mock::constraint( &custom_constraint ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 42 ), "unexpected call" );
+ }
+ {
+ mock::expectation< int( int, const std::string& ) > e;
+ e.expect().with( mock::constraint( &custom_constraint ), "actual" );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 42, "actual" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_with_wrong_parameter_value_in_custom_constraint_throws )
+{
+ mock::expectation< void( int ) > e;
+ e.expect().with( mock::constraint( &custom_constraint, "custom constraint" ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 42 ), "custom constraint" );
+}
+/*
+BOOST_AUTO_TEST_CASE( literal_zero_can_be_used_in_place_of_null_pointers_in_constraints )
+{
+ mock::expectation< void( int* ) > e;
+ e.expect().with( 0 );
+ e.reset();
+}
+*/
+
+// result handling
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_with_no_return_set_throws )
+{
+ {
+ mock::expectation< int() > e;
+ e.expect();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "missing result specification" );
+ }
+ {
+ mock::expectation< int&() > e;
+ e.expect();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "missing result specification" );
+ }
+ {
+ mock::expectation< const std::string&() > e;
+ e.expect();
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "missing result specification" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_returns_the_set_value )
+{
+ {
+ mock::expectation< int() > e;
+ e.expect().returns( 42 );
+ BOOST_CHECK_EQUAL( 42, e() );
+ }
+ {
+ mock::expectation< int() > e;
+ const int i = 42;
+ e.expect().returns( i );
+ BOOST_CHECK_EQUAL( i, e() );
+ }
+ {
+ mock::expectation< int() > e;
+ int i = 42;
+ e.expect().returns( boost::ref( i ) );
+ i = 43;
+ BOOST_CHECK_EQUAL( 43, e() );
+ }
+ {
+ mock::expectation< int&() > e;
+ e.expect().returns( 42 );
+ BOOST_CHECK_EQUAL( 42, e() );
+ }
+ {
+ mock::expectation< int&() > e;
+ const int result = 42;
+ e.expect().returns( result );
+ BOOST_CHECK_EQUAL( result, e() );
+ }
+ {
+ mock::expectation< int&() > e;
+ int i = 42;
+ e.expect().returns( i );
+ i = 43;
+ BOOST_CHECK_EQUAL( 42, e() );
+ }
+ {
+ mock::expectation< int&() > e;
+ int i = 42;
+ e.expect().returns( boost::ref( i ) );
+ i = 43;
+ BOOST_CHECK_EQUAL( 43, e() );
+ BOOST_CHECK_EQUAL( 12, e() = 12 );
+ BOOST_CHECK_EQUAL( 12, i );
+ }
+ {
+ mock::expectation< std::string() > e;
+ e.expect().returns( "result" );
+ BOOST_CHECK_EQUAL( "result", e() );
+ }
+ {
+ mock::expectation< const std::string&() > e;
+ e.expect().returns( "result" );
+ BOOST_CHECK_EQUAL( "result", e() );
+ }
+ {
+ mock::expectation< int*() > e;
+ e.expect().returns( 0 );
+ BOOST_CHECK( ! e() );
+ }
+ {
+ mock::expectation< int() > e;
+ e.expect().returns( 0 );
+ BOOST_CHECK_EQUAL( 0, e() );
+ }
+ {
+ mock::expectation< int&() > e;
+ e.expect().returns( 0 );
+ BOOST_CHECK_EQUAL( 0, e() );
+ }
+}
+
+namespace
+{
+ struct A {};
+ struct B : A {};
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_returns_the_set_auto_ptr_value )
+{
+ {
+ mock::expectation< std::auto_ptr< int >() > e;
+ std::auto_ptr< int > ptr( new int( 3 ) );
+ e.expect().returns( boost::ref( ptr ) );
+ BOOST_CHECK_EQUAL( 3, *ptr );
+ BOOST_CHECK_EQUAL( 3, *e() );
+ BOOST_CHECK( ! ptr.get() );
+ BOOST_CHECK( ! e().get() );
+ }
+ {
+ mock::expectation< std::auto_ptr< int >() > e;
+ std::auto_ptr< int > ptr( new int( 3 ) );
+ e.expect().returns( ptr );
+ BOOST_CHECK( ! ptr.get() );
+ BOOST_CHECK_EQUAL( 3, *e() );
+ BOOST_CHECK( ! e().get() );
+ }
+ {
+ mock::expectation< std::auto_ptr< int >() > e;
+ e.expect().returns( new int( 3 ) );
+ BOOST_CHECK_EQUAL( 3, *e() );
+ BOOST_CHECK( ! e().get() );
+ }
+ {
+ mock::expectation< std::auto_ptr< int >() > e;
+ e.expect().returns( std::auto_ptr< int >( new int( 3 ) ) );
+ BOOST_CHECK_EQUAL( 3, *e() );
+ BOOST_CHECK( ! e().get() );
+ }
+ {
+ mock::expectation< std::auto_ptr< A >() > e;
+ e.expect().returns( new B );
+ BOOST_CHECK_NO_THROW( e() );
+ }
+ {
+ mock::expectation< std::auto_ptr< A >() > e;
+ e.expect().returns( std::auto_ptr< A >( new B ) );
+ BOOST_CHECK_NO_THROW( e() );
+ }
+ {
+ mock::expectation< std::auto_ptr< A >() > e;
+ e.expect().returns( std::auto_ptr< B >( new B ) );
+ BOOST_CHECK_NO_THROW( e() );
+ }
+}
+
+namespace
+{
+ int custom_result()
+ {
+ return 42;
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_calls_the_custom_functor )
+{
+ mock::expectation< int() > e;
+ e.expect().calls( &custom_result );
+ BOOST_CHECK_EQUAL( 42, e() );
+}
+
+namespace
+{
+ int custom_result_with_parameter( int i )
+ {
+ return i;
+ }
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_calls_the_custom_functor_with_parameters )
+{
+ mock::expectation< int( int ) > e;
+ e.expect().calls( &custom_result_with_parameter );
+ BOOST_CHECK_EQUAL( 42, e( 42 ) );
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_calls_the_custom_functor_without_parameters_thanks_to_boost_bind )
+{
+ mock::expectation< int( int ) > e;
+ e.expect().calls( boost::bind( &custom_result ) );
+ BOOST_CHECK_EQUAL( 42, e( 17 ) );
+}
+
+BOOST_AUTO_TEST_CASE( triggering_an_expectation_throws_the_set_exception )
+{
+ mock::expectation< void() > e;
+ e.expect().throws( std::runtime_error( "some exception" ) );
+ try
+ {
+ e();
+ }
+ catch( std::runtime_error& e )
+ {
+ BOOST_CHECK_EQUAL( "some exception", e.what() );
+ return;
+ }
+ BOOST_FAIL( "should have thrown" );
+}
+
+// multiple matchers
+
+BOOST_AUTO_TEST_CASE( expecting_twice_a_single_expectation_makes_it_callable_twice )
+{
+ {
+ mock::expectation< void() > e;
+ e.expect().once();
+ e.expect().once();
+ BOOST_CHECK_NO_THROW( e() );
+ BOOST_CHECK_NO_THROW( e() );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e(), "unexpected call" );
+ }
+ {
+ mock::expectation< void( const std::string& ) > e;
+ e.expect().once().with( "first" );
+ e.expect().once().with( "second" );
+ BOOST_CHECK_NO_THROW( e( "first" ) );
+ BOOST_CHECK_NO_THROW( e( "second" ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( "third" ), "unexpected call" );
+ }
+}
+
+BOOST_AUTO_TEST_CASE( best_matcher_is_selected_first )
+{
+ {
+ mock::expectation< void( int ) > e;
+ e.expect().once().with( 1 );
+ e.expect().once().with( 2 );
+ BOOST_CHECK_NO_THROW( e( 2 ) );
+ BOOST_CHECK_NO_THROW( e( 1 ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( 3 ), "unexpected call" );
+ }
+ {
+ mock::expectation< void( const std::string& ) > e;
+ e.expect().once().with( "first" );
+ e.expect().once().with( "second" );
+ BOOST_CHECK_NO_THROW( e( "second" ) );
+ BOOST_CHECK_NO_THROW( e( "first" ) );
+ BOOST_CHECK_EXCEPTION_CONTAINS( e( "third" ), "unexpected call" );
+ }
+}
+
+// error report
+
+BOOST_AUTO_TEST_CASE( expectation_can_be_serialized_to_be_human_readable )
+{
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once().with( 1 );
+ e.expect().once().with( 2 );
+ BOOST_CHECK_NO_THROW( e( 2 ) );
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( 1 )\n"
+ "v expect( once() ).with( 2 )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().never().with( 1 );
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ "v expect( never() ).with( 1 )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( const std::string& ) > e;
+ e.expect().never().with( mock::less( "first" ) );
+ e.expect().exactly( 2 ).with( "second" );
+ BOOST_CHECK_NO_THROW( e( "second" ) );
+ {
+ std::stringstream s;
+ s << e;
+ const std::string expected = "?\n"
+ "v expect( never() ).with( less( first ) )\n"
+ ". expect( exactly( 1/2 ) ).with( second )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ }
+ BOOST_CHECK_NO_THROW( e( "second" ) );
+ {
+ std::stringstream s;
+ s << e;
+ const std::string expected = "?\n"
+ "v expect( never() ).with( less( first ) )\n"
+ "v expect( exactly( 2/2 ) ).with( second )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ }
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once();
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( any )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once().with( mock::any );
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( any )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once();
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( any )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once().with( mock::constraint( &custom_constraint ) );
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( ? )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once().with( mock::constraint( &custom_constraint, "custom constraint" ) );
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( custom constraint )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+ {
+ mock::expectation< void( int ) > e( "my expectation" );
+ e.expect().once().with( mock::constraint( &custom_constraint, true ) );
+ std::stringstream s;
+ s << e;
+ const std::string expected = "my expectation\n"
+ ". expect( once() ).with( true )";
+ BOOST_CHECK_EQUAL( expected, s.str() );
+ e.reset();
+ }
+}
+
+namespace
+{
+ mock::expectation< void() > no_match_exp( "no_match" );
+ mock::expectation< void() > sequence_failed_exp( "sequence_failed" );
+ mock::expectation< void() > verification_failed_exp( "verification_failed" );
+ mock::expectation< void() > untriggered_expectation_exp( "untriggered_expectation" );
+
+ struct mock_error
+ {
+ static void no_match( const std::string& /*context*/ )
+ {
+ no_match_exp();
+ }
+ static void sequence_failed( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {
+ sequence_failed_exp();
+ }
+ static void verification_failed( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {
+ verification_failed_exp();
+ }
+ static void untriggered_expectation( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {
+ untriggered_expectation_exp();
+ }
+ };
+ struct error_guard
+ {
+ ~error_guard()
+ {
+ no_match_exp.verify();
+ no_match_exp.reset();
+ sequence_failed_exp.verify();
+ sequence_failed_exp.reset();
+ verification_failed_exp.verify();
+ verification_failed_exp.reset();
+ untriggered_expectation_exp.verify();
+ untriggered_expectation_exp.reset();
+ }
+ };
+}
+
+BOOST_FIXTURE_TEST_CASE( expectation_with_remaining_untriggered_matches_notifies_an_error_upon_destructions, error_guard )
+{
+ mock::expectation< void(), mock_error > e;
+ e.expect().once();
+ untriggered_expectation_exp.expect().once();
+}
+
+BOOST_FIXTURE_TEST_CASE( verifying_expectation_with_remaining_matches_disables_the_automatic_verification_upon_destruction, error_guard )
+{
+ mock::expectation< void(), mock_error > e;
+ e.expect().once();
+ verification_failed_exp.expect();
+ e.verify();
+}
+
+BOOST_FIXTURE_TEST_CASE( triggering_no_match_call_disables_the_automatic_verification_upon_destruction, error_guard )
+{
+ mock::expectation< void(), mock_error > e;
+ no_match_exp.expect();
+ e();
+}
+
+BOOST_FIXTURE_TEST_CASE( adding_a_matcher_reactivates_the_verification_upon_destruction, error_guard )
+{
+ mock::expectation< void(), mock_error > e;
+ no_match_exp.expect();
+ e();
+ e.expect().once();
+ untriggered_expectation_exp.expect().once();
+}
diff --git a/src/tests/turtle_test/format_test.cpp b/src/tests/turtle_test/format_test.cpp
new file mode 100644
index 0000000..9769953
--- /dev/null
+++ b/src/tests/turtle_test/format_test.cpp
@@ -0,0 +1,79 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+namespace
+{
+ struct non_serializable_type {};
+
+ struct serializable_type {};
+ std::ostream& operator<<( std::ostream& s, const serializable_type& )
+ {
+ return s << "serializable_type";
+ }
+}
+
+BOOST_AUTO_TEST_CASE( type_not_serializable_in_standard_stream_yields_an_interrogation_mark_when_serialized )
+{
+ BOOST_CHECK_EQUAL( "?", mock::detail::format( non_serializable_type() ) );
+}
+
+BOOST_AUTO_TEST_CASE( base_type_serializable_in_standard_stream_yields_its_value_when_serialized )
+{
+ BOOST_CHECK_EQUAL( "42", mock::detail::format( 42 ) );
+}
+
+BOOST_AUTO_TEST_CASE( custom_type_serializable_in_standard_stream_yields_its_value_when_serialized )
+{
+ BOOST_CHECK_EQUAL( "serializable_type", mock::detail::format( serializable_type() ) );
+}
+
+namespace
+{
+ struct convertible_to_int
+ {
+ operator int() const { return 0; }
+ };
+}
+
+BOOST_AUTO_TEST_CASE( custom_type_convertible_to_base_type_yields_its_value_when_serialized )
+{
+ BOOST_CHECK_EQUAL( "0", mock::detail::format( convertible_to_int() ) );
+}
+
+namespace
+{
+ struct serializable
+ {
+ friend std::ostream& operator<<( std::ostream& s, const serializable& )
+ {
+ return s << "serializable";
+ }
+ };
+ struct convertible_to_serializable
+ {
+ operator serializable() const { return serializable(); }
+ };
+}
+
+BOOST_AUTO_TEST_CASE( custom_type_convertible_to_another_type_serializable_in_standard_stream_yields_its_value_when_serialized )
+{
+ BOOST_CHECK_EQUAL( "serializable", mock::detail::format( convertible_to_serializable() ) );
+}
+
+BOOST_AUTO_TEST_CASE( booleans_are_serialized_as_booleans )
+{
+ BOOST_CHECK_EQUAL( "true", mock::detail::format( true ) );
+ BOOST_CHECK_EQUAL( "false", mock::detail::format( false ) );
+}
diff --git a/src/tests/turtle_test/invocation_test.cpp b/src/tests/turtle_test/invocation_test.cpp
new file mode 100644
index 0000000..a85613e
--- /dev/null
+++ b/src/tests/turtle_test/invocation_test.cpp
@@ -0,0 +1,79 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+BOOST_AUTO_TEST_CASE( unlimited )
+{
+ mock::detail::unlimited invocation;
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+}
+
+BOOST_AUTO_TEST_CASE( once )
+{
+ mock::detail::once invocation;
+ BOOST_CHECK( ! invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( ! invocation.is_valid() );
+ BOOST_CHECK( ! invocation.invoke() );
+}
+
+BOOST_AUTO_TEST_CASE( never )
+{
+ mock::detail::never invocation;
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( ! invocation.is_valid() );
+ BOOST_CHECK( ! invocation.invoke() );
+}
+
+BOOST_AUTO_TEST_CASE( at_most )
+{
+ mock::detail::at_most invocation( 1 );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( ! invocation.is_valid() );
+ BOOST_CHECK( ! invocation.invoke() );
+}
+
+BOOST_AUTO_TEST_CASE( at_least )
+{
+ mock::detail::at_least invocation( 1 );
+ BOOST_CHECK( ! invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+}
+
+BOOST_AUTO_TEST_CASE( between )
+{
+ mock::detail::between invocation( 1, 2 );
+ BOOST_CHECK( ! invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( invocation.is_valid() );
+ BOOST_CHECK( invocation.invoke() );
+ BOOST_CHECK( invocation.verify() );
+ BOOST_CHECK( ! invocation.is_valid() );
+ BOOST_CHECK( ! invocation.invoke() );
+}
diff --git a/src/tests/turtle_test/object_test.cpp b/src/tests/turtle_test/object_test.cpp
new file mode 100644
index 0000000..3005a9d
--- /dev/null
+++ b/src/tests/turtle_test/object_test.cpp
@@ -0,0 +1,72 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+BOOST_AUTO_TEST_CASE( verifying_an_empty_object_succeeds )
+{
+ mock::object o;
+ BOOST_CHECK( o.verify() );
+}
+
+namespace
+{
+ struct silent_error
+ {
+ static void verification_failed( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {}
+ static void untriggered_expectation( const std::string& /*context*/,
+ const std::string& /*file*/, int /*line*/ )
+ {}
+ };
+}
+
+BOOST_AUTO_TEST_CASE( verifying_an_object_containing_a_failing_expectation_fails )
+{
+ mock::object o;
+ mock::expectation< void(), silent_error > e( o );
+ e.expect().once();
+ BOOST_CHECK( ! o.verify() );
+}
+
+BOOST_AUTO_TEST_CASE( resetting_an_object_containing_a_failing_expectation_and_verifying_it_succeeds )
+{
+ mock::object o;
+ mock::expectation< void() > e( o );
+ e.expect().once();
+ o.reset();
+ BOOST_CHECK( o.verify() );
+ BOOST_CHECK( e.verify() );
+}
+
+BOOST_AUTO_TEST_CASE( verifying_an_object_containing_another_object_with_a_failing_expectation_fails )
+{
+ mock::object o1;
+ mock::object o2( o1 );
+ mock::expectation< void(), silent_error > e( o2 );
+ e.expect().once();
+ BOOST_CHECK( ! o1.verify() );
+}
+
+BOOST_AUTO_TEST_CASE( resetting_an_object_containing_another_object_with_a_failing_expectation_and_verifying_it_succeeds )
+{
+ mock::object o1;
+ mock::object o2( o1 );
+ mock::expectation< void() > e( o2 );
+ e.expect().once();
+ o1.reset();
+ BOOST_CHECK( o1.verify() );
+ BOOST_CHECK( o2.verify() );
+ BOOST_CHECK( e.verify() );
+}
diff --git a/src/tests/turtle_test/samples_test.cpp b/src/tests/turtle_test/samples_test.cpp
new file mode 100644
index 0000000..2f519b9
--- /dev/null
+++ b/src/tests/turtle_test/samples_test.cpp
@@ -0,0 +1,166 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+#include
+#include
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+#include
+#include
+
+#ifdef _MSC_VER
+# pragma warning( disable : 4355 4505 )
+#endif
+
+namespace
+{
+ MOCK_CLASS( my_mock )
+ {
+ MOCK_METHOD_EXT( my_method, 1, int( int ), my_method )
+ };
+}
+
+BOOST_AUTO_TEST_CASE( basic_mock_object_usage )
+{
+ my_mock m;
+ MOCK_EXPECT( m, my_method ).once().returns( 0 );
+ BOOST_CHECK_EQUAL( 0, m.my_method( 13 ) );
+ mock::verify();
+ mock::reset(); // $$$$ MAT : shouldn't reset implicitly call verify ?
+ MOCK_EXPECT( m, my_method ).once().with( 42 ).returns( 7 );
+ BOOST_CHECK_EQUAL( 7, m.my_method( 42 ) );
+ mock::verify();
+ mock::reset();
+ MOCK_EXPECT( m, my_method ).once().returns( 51 );
+ BOOST_CHECK_EQUAL( 51, m.my_method( 27 ) );
+}
+
+namespace
+{
+ class my_observer : boost::noncopyable
+ {
+ public:
+ virtual ~my_observer() {}
+
+ virtual void notify( int value ) = 0;
+ };
+
+ class my_manager : boost::noncopyable
+ {
+ public:
+ virtual ~my_manager() {}
+
+ virtual my_observer& get_observer() const = 0;
+ };
+
+ class my_subject : boost::noncopyable
+ {
+ public:
+ explicit my_subject( my_manager& f )
+ : o_( f.get_observer() )
+ , value_( 0 )
+ {}
+ void increment()
+ {
+ o_.notify( ++value_ );
+ }
+ private:
+ my_observer& o_;
+ int value_;
+ };
+
+ MOCK_INTERFACE( my_mock_observer, my_observer )
+ {
+ MOCK_METHOD( notify, 1 )
+ };
+
+ MOCK_INTERFACE( my_mock_manager, my_manager )
+ {
+ MOCK_METHOD( get_observer, 0 )
+ };
+
+ class fixture
+ {
+ public:
+ fixture()
+ : manager( "(the only one)" )
+ {}
+ my_mock_manager manager;
+ my_mock_observer observer;
+ };
+}
+
+BOOST_FIXTURE_TEST_CASE( basic_mock_object_collaboration_usage, fixture )
+{
+ MOCK_EXPECT( manager, get_observer ).returns( boost::ref( observer ) );
+ my_subject subject( manager );
+ MOCK_EXPECT( observer, notify ).once().with( 1 );
+ subject.increment();
+ MOCK_EXPECT( observer, notify ).once().with( 2 );
+ subject.increment();
+ MOCK_EXPECT( observer, notify ).once().with( 3 );
+ subject.increment();
+}
+
+namespace
+{
+ class my_ambiguited_interface : boost::noncopyable
+ {
+ public:
+ virtual ~my_ambiguited_interface() {}
+
+ virtual void my_method() = 0;
+ virtual void my_method( int ) = 0;
+ };
+
+ MOCK_INTERFACE( my_ambiguited_mock, my_ambiguited_interface )
+ {
+ MOCK_METHOD_EXT( my_method, 0, void(), tag1 )
+ MOCK_METHOD_EXT( my_method, 1, void( int ), tag2 )
+ };
+}
+
+BOOST_AUTO_TEST_CASE( mock_object_method_disambiguation )
+{
+ my_ambiguited_mock mock;
+ MOCK_EXPECT( mock, tag1 );
+ BOOST_CHECK_NO_THROW( mock.my_method() );
+ BOOST_CHECK_THROW( mock.my_method( 12 ), mock::exception );
+}
+
+namespace
+{
+ class my_const_ambiguited_interface : boost::noncopyable
+ {
+ public:
+ virtual ~my_const_ambiguited_interface() {}
+
+ virtual void my_method() = 0;
+ virtual void my_method() const = 0;
+ };
+
+ MOCK_INTERFACE( my_const_ambiguited_mock, my_const_ambiguited_interface )
+ {
+ MOCK_NON_CONST_METHOD_EXT( my_method, 0, void(), tag1 )
+ MOCK_CONST_METHOD_EXT( my_method, 0, void(), tag2 )
+ };
+}
+
+BOOST_AUTO_TEST_CASE( mock_object_method_const_disambiguation )
+{
+ my_const_ambiguited_mock mock;
+ MOCK_EXPECT( mock, tag1 );
+ BOOST_CHECK_NO_THROW( mock.my_method() );
+ const my_const_ambiguited_mock const_mock;
+ BOOST_CHECK_THROW( const_mock.my_method(), mock::exception );
+}
diff --git a/src/tests/turtle_test/sequence_test.cpp b/src/tests/turtle_test/sequence_test.cpp
new file mode 100644
index 0000000..56a2dcf
--- /dev/null
+++ b/src/tests/turtle_test/sequence_test.cpp
@@ -0,0 +1,78 @@
+//
+// Copyright Mathieu Champlon 2008
+//
+// 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)
+//
+
+#include
+#include
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+BOOST_AUTO_TEST_CASE( registering_to_a_sequence_and_calling_out_of_order_throws )
+{
+ mock::sequence s;
+ mock::expectation< void( int ) > e;
+ e.expect().once().with( 1 ).in( s );
+ e.expect().once().with( 2 ).in( s );
+ BOOST_CHECK_NO_THROW( e( 2 ) );
+ BOOST_CHECK_THROW( e( 1 ), mock::exception );
+}
+
+BOOST_AUTO_TEST_CASE( registering_to_a_sequence_and_calling_out_of_order_multiple_invocations_throws )
+{
+ mock::sequence s;
+ mock::expectation< void( int ) > e;
+ e.expect().with( 1 ).in( s );
+ e.expect().once().with( 2 ).in( s );
+ BOOST_CHECK_NO_THROW( e( 1 ) );
+ BOOST_CHECK_NO_THROW( e( 2 ) );
+ BOOST_CHECK_THROW( e( 1 ), mock::exception );
+}
+
+BOOST_AUTO_TEST_CASE( registering_to_a_sequence_and_calling_in_order_is_valid )
+{
+ mock::sequence s;
+ mock::expectation< void( int ) > e;
+ e.expect().once().with( 1 ).in( s );
+ e.expect().once().with( 2 ).in( s );
+ BOOST_CHECK_NO_THROW( e( 1 ) );
+ BOOST_CHECK_NO_THROW( e( 2 ) );
+}
+
+BOOST_AUTO_TEST_CASE( registering_to_a_sequence_enforces_call_order_verification_between_two_different_expectations )
+{
+ mock::sequence s;
+ mock::expectation< void() > e1, e2;
+ e1.expect().once().in( s );
+ e2.expect().once().in( s );
+ BOOST_CHECK_NO_THROW( e2() );
+ BOOST_CHECK_THROW( e1(), mock::exception );
+}
+
+BOOST_AUTO_TEST_CASE( destroying_a_sequence_removes_order_call_enforcement )
+{
+ mock::expectation< void() > e1, e2;
+ {
+ mock::sequence s;
+ e1.expect().once().in( s );
+ e2.expect().once().in( s );
+ }
+ BOOST_CHECK_NO_THROW( e2() );
+ BOOST_CHECK_NO_THROW( e1() );
+}
+
+BOOST_AUTO_TEST_CASE( resetting_an_expectation_removes_it_from_order_call_enforcement )
+{
+ mock::sequence s;
+ mock::expectation< void() > e1, e2;
+ e1.expect().once().in( s );
+ e2.expect().once().in( s );
+ e1.reset();
+ BOOST_CHECK_NO_THROW( e2() );
+}
diff --git a/src/tests/turtle_test/tools_test.cpp b/src/tests/turtle_test/tools_test.cpp
new file mode 100644
index 0000000..6b080a5
--- /dev/null
+++ b/src/tests/turtle_test/tools_test.cpp
@@ -0,0 +1,143 @@
+//
+// Copyright Mathieu Champlon 2009
+//
+// 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)
+//
+
+#include
+#include
+#include
+
+#include
+#define BOOST_LIB_NAME boost_unit_test_framework
+#include
+
+#ifdef _MSC_VER
+# pragma warning( disable : 4355 )
+#endif
+
+namespace
+{
+ void f1();
+ int f2( float );
+
+ BOOST_STATIC_ASSERT( (boost::mpl::equal< mock::expectation< void() >,
+ mock::expectation< BOOST_TYPEOF( f1 ) >
+ >::value) );
+ BOOST_STATIC_ASSERT( (boost::mpl::equal< mock::expectation< int( float ) >,
+ mock::expectation< BOOST_TYPEOF( f2 ) >
+ >::value) );
+
+ struct example
+ {
+ void method1();
+ float method2( int );
+ };
+
+ BOOST_STATIC_ASSERT(
+ (boost::mpl::equal<
+ mock::expectation< void() >,
+ mock::expectation<
+ mock::detail::signature<
+ BOOST_TYPEOF( &example::method1 )
+ >::type
+ >
+ >::value) );
+ BOOST_STATIC_ASSERT(
+ (boost::mpl::equal<
+ mock::expectation< float( int ) >,
+ mock::expectation<
+ mock::detail::signature<
+ BOOST_TYPEOF( &example::method2 )
+ >::type
+ >
+ >::value) );
+}
+
+BOOST_AUTO_TEST_CASE( ptr_uniformizes_reference_and_pointer )
+{
+ int i = 0;
+ BOOST_CHECK_EQUAL( mock::detail::ref( i ), mock::detail::ref( &i ) );
+}
+
+BOOST_AUTO_TEST_CASE( ptr_accesses_inner_pointer_from_auto_ptr )
+{
+ std::auto_ptr< int > i( new int( 0 ) );
+ BOOST_CHECK_EQUAL( *i, mock::detail::ref( i ) );
+}
+
+BOOST_AUTO_TEST_CASE( ptr_accesses_inner_pointer_from_shared_ptr )
+{
+ boost::shared_ptr< int > i( new int( 0 ) );
+ BOOST_CHECK_EQUAL( *i, mock::detail::ref( i ) );
+}
+
+namespace
+{
+ template< typename T >
+ void my_function( T& t )
+ {
+ t.my_method( "some parameter" );
+ }
+ MOCK_CLASS( mock_class )
+ {
+ MOCK_METHOD_EXT( my_method, 1, void( const std::string& ), my_method )
+ };
+}
+
+BOOST_AUTO_TEST_CASE( mock_object_for_static_polymorphism )
+{
+ const mock_class mock;
+ MOCK_EXPECT( mock, my_method ).once().with( "some parameter" );
+ my_function( mock );
+}
+
+namespace
+{
+ MOCK_CLASS( mock_class_with_operator )
+ {
+ MOCK_CONST_METHOD_EXT( operator+=, 1, mock_class_with_operator&( int ), addition )
+ };
+}
+
+BOOST_AUTO_TEST_CASE( mock_addition_operator )
+{
+ mock_class_with_operator mock;
+ MOCK_EXPECT( mock, addition ).once().returns( boost::ref( mock ) );
+ mock += 1;
+}
+
+namespace
+{
+ MOCK_CLASS( my_mock )
+ {
+ MOCK_METHOD_EXT( my_method, 1, void( int ), my_method )
+ };
+}
+
+BOOST_AUTO_TEST_CASE( MOCK_METHOD_EXT_macro_defines_a_bindable_method )
+{
+ my_mock m;
+ boost::bind( &my_mock::my_method, &m, 42 );
+}
+
+BOOST_AUTO_TEST_CASE( MOCK_VERIFY_macro )
+{
+ my_mock m;
+ MOCK_VERIFY( m, my_method );
+}
+
+BOOST_AUTO_TEST_CASE( MOCK_RESET_macro )
+{
+ my_mock m;
+ MOCK_RESET( m, my_method );
+}
+
+BOOST_AUTO_TEST_CASE( MOCK_EXPECT_macro )
+{
+ my_mock m;
+ MOCK_EXPECT( m, my_method ).once().with( 42 );
+ m.my_method( 42 );
+}