Initial import

git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@2 860be788-9bd5-4423-9f1e-828f051e677b
This commit is contained in:
mat007 2009-08-26 22:02:18 +00:00
parent 8081e7006f
commit 8e18676b92
31 changed files with 4062 additions and 0 deletions

1
build/build.properties Normal file
View file

@ -0,0 +1 @@
platform = vc80

32
build/build.xml Normal file
View file

@ -0,0 +1,32 @@
<project name="turtle" default="all">
<property environment="env"/>
<import file="${env.PONEY_HOME}/poney.xml"/>
<target name="turtle_test" description="build and run unit tests">
<build-test name="turtle" mode="all">
<compilerarg value="-Wno-uninitialized" location="mid" if="is-cygwin"/>
</build-test>
</target>
<target name="clean" description="clean intermediate build artifacts">
<delete dir="${out.dir}"/>
</target>
<target name="configure" description="update external libraries">
<update name="boost"/>
</target>
<target name="test" depends="turtle_test" description="run unit tests"/>
<target name="export" description="export the distribution">
<deploy>
<module name="turtle">
<include name="**/*.hpp"/>
</module>
</deploy>
</target>
<target name="all" depends="configure,test,export" description="build, run tests and package application"/>
</project>

25
build/vc80/turtle.sln Normal file
View file

@ -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

227
build/vc80/turtle.vcproj Normal file
View file

@ -0,0 +1,227 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="turtle"
ProjectGUID="{831F2DEE-1E35-4533-A3B2-12C01BA8DA1D}"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="debug|Win32"
OutputDirectory="../../out/vc80/$(ConfigurationName)/libraries/$(ProjectName)"
IntermediateDirectory="../../out/vc80/$(ConfigurationName)/libraries/$(ProjectName)"
ConfigurationType="4"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/Zm179"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(IntDir)&quot;, ../../include, ../../src/libraries, ../../src/libraries/$(ProjectName)"
PreprocessorDefinitions="WIN32,_DEBUG,_WINDOWS"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="$(ProjectName)_pch.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/lib$(ProjectName)-vc80-mt-gd.lib"
AdditionalLibraryDirectories="$(OutDir) , ../../lib/vc80"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="release|Win32"
OutputDirectory="../../out/vc80/$(ConfigurationName)/libraries/$(ProjectName)"
IntermediateDirectory="../../out/vc80/$(ConfigurationName)/libraries/$(ProjectName)"
ConfigurationType="4"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/Zm176"
AdditionalIncludeDirectories="&quot;$(IntDir)&quot;, ../../include, ../../src/libraries, ../../src/libraries/$(ProjectName)"
PreprocessorDefinitions="WIN32, NDEBUG,_WINDOWS"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="$(ProjectName)_pch.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
ProgramDataBaseFileName="$(IntDir)\$(ProjectName).pdb"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/lib$(ProjectName)-vc80-mt.lib"
AdditionalLibraryDirectories="$(OutDir) , ../../lib/vc80"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\src\libraries\turtle\check.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\config.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\constraint.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\error.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\expectation.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\format.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\functional.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\invocation.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\matcher.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\node.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\object.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\placeholder.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\result.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\root.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\sequence.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\tools.hpp"
>
</File>
<File
RelativePath="..\..\src\libraries\turtle\verifiable.hpp"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,239 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="turtle_test"
ProjectGUID="{74810A2A-33D8-47D6-9A50-71261F1683F5}"
RootNamespace="turtle_test"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="debug|Win32"
OutputDirectory="../../out/vc80/$(ConfigurationName)/tests/$(ProjectName)"
IntermediateDirectory="../../out/vc80/$(ConfigurationName)/tests/$(ProjectName)"
ConfigurationType="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/Zm172"
Optimization="0"
AdditionalIncludeDirectories="../../src/libraries, ../../include"
PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
PrecompiledHeaderThrough="$(ProjectName)_pch.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="4"
SuppressStartupBanner="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies=""
OutputFile="$(OutDir)/$(ProjectName).exe"
AdditionalLibraryDirectories="../../lib/vc80"
GenerateDebugInformation="true"
SubSystem="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="cd ../../run/vc80&#x0D;&#x0A;&quot;$(TargetDir)$(TargetName).exe&quot; --result_code=no --report_level=no --log_level=messages --data_directory=../../data/tests/$(ProjectName)&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
Name="release|Win32"
OutputDirectory="../../out/vc80/$(ConfigurationName)/tests/$(ProjectName)"
IntermediateDirectory="../../out/vc80/$(ConfigurationName)/tests/$(ProjectName)"
ConfigurationType="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/Zm162"
Optimization="2"
AdditionalIncludeDirectories="../../src/libraries, ../../include"
PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
BasicRuntimeChecks="0"
RuntimeLibrary="2"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
PrecompiledHeaderThrough="$(ProjectName)_pch.h"
PrecompiledHeaderFile="$(IntDir)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/"
ObjectFile="$(IntDir)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
WarningLevel="4"
SuppressStartupBanner="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies=""
OutputFile="$(OutDir)/$(ProjectName).exe"
AdditionalLibraryDirectories="../../lib/vc80"
GenerateDebugInformation="true"
SubSystem="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="cd ../../run/vc80&#x0D;&#x0A;&quot;$(TargetDir)$(TargetName).exe&quot; --result_code=no --report_level=no --log_level=messages --data_directory=../../data/tests/$(ProjectName)&#x0D;&#x0A;"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx;h;hpp;hxx;hm;inl;inc;xsd"
>
<File
RelativePath="..\..\src\tests\turtle_test\constraint_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\error_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\expectation_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\format_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\invocation_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\object_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\samples_test.cpp"
>
<FileConfiguration
Name="release|Win32"
>
<Tool
Name="VCCLCompilerTool"
GeneratePreprocessedFile="0"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\sequence_test.cpp"
>
</File>
<File
RelativePath="..\..\src\tests\turtle_test\tools_test.cpp"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -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 <boost/function.hpp>
#include <stdexcept>
#include <ostream>
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

View file

@ -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 <boost/preprocessor/comparison/less_equal.hpp>
#include <boost/preprocessor/debug/assert.hpp>
#include <boost/function.hpp>
#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

View file

@ -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 <sstream>
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

View file

@ -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 <stdexcept>
#include <string>
#include <boost/test/test_tools.hpp>
#include <boost/test/execution_monitor.hpp>
#include <boost/test/utils/trivial_singleton.hpp>
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

View file

@ -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 <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <ostream>
#include <list>
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

View file

@ -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 <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/utility/enable_if.hpp>
#include <sstream>
#include <ostream>
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

View file

@ -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 <boost/ref.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
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

View file

@ -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 <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <stdexcept>
#include <ostream>
#include <limits>
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

View file

@ -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 <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <ostream>
#include <vector>
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

View file

@ -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 <vector>
#include <algorithm>
#include <functional>
#include <string>
#include <ostream>
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

View file

@ -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 <string>
#include <ostream>
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

View file

@ -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 <string>
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

View file

@ -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 <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <memory>
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( &nothing ) )
{}
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

View file

@ -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 <boost/test/utils/trivial_singleton.hpp>
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

View file

@ -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 <vector>
#include <algorithm>
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

View file

@ -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 <boost/function.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/inc.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/push_back.hpp>
#include <boost/preprocessor/seq/pop_back.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/erase.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/back_inserter.hpp>
#define BOOST_TYPEOF_SILENT
#include <boost/typeof/typeof.hpp>
#include <stdexcept>
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

View file

@ -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 <boost/noncopyable.hpp>
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

View file

@ -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 <turtle/constraint.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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 ) );
}

View file

@ -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 <turtle/error.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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& )
{}
}

View file

@ -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 <turtle/expectation.hpp>
#include <turtle/constraint.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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();
}

View file

@ -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 <turtle/format.hpp>
#include <ostream>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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 ) );
}

View file

@ -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 <turtle/invocation.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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() );
}

View file

@ -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 <turtle/object.hpp>
#include <turtle/expectation.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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() );
}

View file

@ -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 <turtle/object.hpp>
#include <turtle/expectation.hpp>
#include <turtle/constraint.hpp>
#include <turtle/tools.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
#include <boost/noncopyable.hpp>
#include <boost/ref.hpp>
#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 );
}

View file

@ -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 <turtle/sequence.hpp>
#include <turtle/expectation.hpp>
#include <turtle/constraint.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
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() );
}

View file

@ -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 <turtle/tools.hpp>
#include <boost/static_assert.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/test/auto_unit_test.hpp>
#define BOOST_LIB_NAME boost_unit_test_framework
#include <boost/config/auto_link.hpp>
#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 );
}