From bbb6f3a00e9a13876b7763c0d7acc36fec03e6e9 Mon Sep 17 00:00:00 2001 From: MorleyDev Date: Wed, 4 Feb 2015 02:02:35 +0000 Subject: [PATCH] Refactored to allow for easy biicode support --- CMakeLists.txt | 77 ++-- LICENSE.md | 14 +- README.md | 48 +-- UnitTest11.hpp | 33 ++ UnitTest11/Assert/Fail.hpp | 14 + UnitTest11/Assert/That.hpp | 29 ++ UnitTest11/Category.hpp | 48 +++ UnitTest11/Core.hpp | 12 + UnitTest11/Is/Any.hpp | 54 +++ UnitTest11/Is/Between.hpp | 57 +++ UnitTest11/Is/Empty.hpp | 58 +++ UnitTest11/Is/EqualTo.hpp | 60 +++ UnitTest11/Is/False.hpp | 43 ++ UnitTest11/Is/GreaterThan.hpp | 54 +++ UnitTest11/Is/Infinity.hpp | 86 ++++ UnitTest11/Is/Iterable/Containing/Item.hpp | 76 ++++ UnitTest11/Is/Iterable/Containing/Subset.hpp | 107 +++++ UnitTest11/Is/Iterable/EquivalentTo.hpp | 103 +++++ UnitTest11/Is/Iterable/Of.hpp | 60 +++ UnitTest11/Is/LessThan.hpp | 57 +++ UnitTest11/Is/NaN.hpp | 90 ++++ UnitTest11/Is/Null.hpp | 48 +++ UnitTest11/Is/String/BeginningWith.hpp | 59 +++ UnitTest11/Is/String/Containing.hpp | 92 ++++ UnitTest11/Is/String/EndingWith.hpp | 65 +++ UnitTest11/Is/True.hpp | 43 ++ UnitTest11/Is/Zero.hpp | 41 ++ UnitTest11/Macros.hpp | 114 +++++ UnitTest11/Mock.hpp | 103 +++++ UnitTest11/Run.hpp | 40 ++ UnitTest11/TestFixture.hpp | 43 ++ UnitTest11/Will/Pass.hpp | 52 +++ UnitTest11/Will/Throw.hpp | 100 +++++ UnitTest11/detail/AndOperand.hpp | 41 ++ UnitTest11/detail/BaseOperand.hpp | 45 ++ UnitTest11/detail/DeclareFixture.hpp | 72 ++++ UnitTest11/detail/MockArgumentHandler.hpp | 71 ++++ UnitTest11/detail/MockReturnHandler.hpp | 61 +++ UnitTest11/detail/MockTimesVerify.hpp | 35 ++ UnitTest11/detail/MockVerify.hpp | 33 ++ UnitTest11/detail/NotOperand.hpp | 36 ++ UnitTest11/detail/OrOperand.hpp | 41 ++ UnitTest11/detail/TestFailedException.hpp | 40 ++ UnitTest11/detail/TestFixtureAbstract.hpp | 36 ++ UnitTest11/detail/TestFixtureResults.hpp | 20 + UnitTest11/detail/TestFixtureRunner.hpp | 34 ++ UnitTest11/detail/TestStage.hpp | 20 + UnitTest11/detail/TestStageBuilder.hpp | 29 ++ UnitTest11/detail/TestStageBuilderImpl.hpp | 44 ++ UnitTest11/detail/TestStageImpl.hpp | 30 ++ UnitTest11/detail/TestStep.hpp | 22 + UnitTest11/out/Output.hpp | 45 ++ UnitTest11/out/StdOutput.hpp | 50 +++ UnitTest11/utility/AreEqual.hpp | 62 +++ UnitTest11/utility/DefaultValue.hpp | 13 + UnitTest11/utility/Meta/IfElseTypes.hpp | 23 + .../utility/Meta/IsIterableContainer.hpp | 39 ++ UnitTest11/utility/Meta/IsIterableOfType.hpp | 37 ++ UnitTest11/utility/ToString.hpp | 130 ++++++ biicode.conf | 19 + configure | 26 +- src/CMakeLists.txt | 28 +- src/files.cmake | 152 +++---- src/out/StdOutput.cpp | 290 ++++++------- tests/CMakeLists.txt | 18 +- tests/Examples/EntityComponentStore.cpp | 402 +++++++++--------- tests/files.cmake | 76 ++-- 67 files changed, 3538 insertions(+), 562 deletions(-) create mode 100644 UnitTest11.hpp create mode 100644 UnitTest11/Assert/Fail.hpp create mode 100644 UnitTest11/Assert/That.hpp create mode 100644 UnitTest11/Category.hpp create mode 100644 UnitTest11/Core.hpp create mode 100644 UnitTest11/Is/Any.hpp create mode 100644 UnitTest11/Is/Between.hpp create mode 100644 UnitTest11/Is/Empty.hpp create mode 100644 UnitTest11/Is/EqualTo.hpp create mode 100644 UnitTest11/Is/False.hpp create mode 100644 UnitTest11/Is/GreaterThan.hpp create mode 100644 UnitTest11/Is/Infinity.hpp create mode 100644 UnitTest11/Is/Iterable/Containing/Item.hpp create mode 100644 UnitTest11/Is/Iterable/Containing/Subset.hpp create mode 100644 UnitTest11/Is/Iterable/EquivalentTo.hpp create mode 100644 UnitTest11/Is/Iterable/Of.hpp create mode 100644 UnitTest11/Is/LessThan.hpp create mode 100644 UnitTest11/Is/NaN.hpp create mode 100644 UnitTest11/Is/Null.hpp create mode 100644 UnitTest11/Is/String/BeginningWith.hpp create mode 100644 UnitTest11/Is/String/Containing.hpp create mode 100644 UnitTest11/Is/String/EndingWith.hpp create mode 100644 UnitTest11/Is/True.hpp create mode 100644 UnitTest11/Is/Zero.hpp create mode 100644 UnitTest11/Macros.hpp create mode 100644 UnitTest11/Mock.hpp create mode 100644 UnitTest11/Run.hpp create mode 100644 UnitTest11/TestFixture.hpp create mode 100644 UnitTest11/Will/Pass.hpp create mode 100644 UnitTest11/Will/Throw.hpp create mode 100644 UnitTest11/detail/AndOperand.hpp create mode 100644 UnitTest11/detail/BaseOperand.hpp create mode 100644 UnitTest11/detail/DeclareFixture.hpp create mode 100644 UnitTest11/detail/MockArgumentHandler.hpp create mode 100644 UnitTest11/detail/MockReturnHandler.hpp create mode 100644 UnitTest11/detail/MockTimesVerify.hpp create mode 100644 UnitTest11/detail/MockVerify.hpp create mode 100644 UnitTest11/detail/NotOperand.hpp create mode 100644 UnitTest11/detail/OrOperand.hpp create mode 100644 UnitTest11/detail/TestFailedException.hpp create mode 100644 UnitTest11/detail/TestFixtureAbstract.hpp create mode 100644 UnitTest11/detail/TestFixtureResults.hpp create mode 100644 UnitTest11/detail/TestFixtureRunner.hpp create mode 100644 UnitTest11/detail/TestStage.hpp create mode 100644 UnitTest11/detail/TestStageBuilder.hpp create mode 100644 UnitTest11/detail/TestStageBuilderImpl.hpp create mode 100644 UnitTest11/detail/TestStageImpl.hpp create mode 100644 UnitTest11/detail/TestStep.hpp create mode 100644 UnitTest11/out/Output.hpp create mode 100644 UnitTest11/out/StdOutput.hpp create mode 100644 UnitTest11/utility/AreEqual.hpp create mode 100644 UnitTest11/utility/DefaultValue.hpp create mode 100644 UnitTest11/utility/Meta/IfElseTypes.hpp create mode 100644 UnitTest11/utility/Meta/IsIterableContainer.hpp create mode 100644 UnitTest11/utility/Meta/IsIterableOfType.hpp create mode 100644 UnitTest11/utility/ToString.hpp create mode 100644 biicode.conf diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fab0fc..67878d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,35 +1,42 @@ -cmake_minimum_required (VERSION 2.6) -project(UNITTEST11 CXX) - -option(ENABLE_GCOV "Adds the --coverage flag to compilation" OFF) - -if (ENABLE_GCOV) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") - set(CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") -endif() - -if (MSVC) - set(CMAKE_CXX_FLAGS "/MP ${CMAKE_CXX_FLAGS}") - -elseif(CMAKE_COMPILER_IS_GNUCXX) - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GXX_VERSION) - if (GXX_VERSION VERSION_LESS 4.8) - if (GXX_VERSION VERSION_LESS 4.7) - set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}") - else() - set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") - endif() - else() - set (CMAKE_CXX_FLAGS "-std=c++1y ${CMAKE_CXX_FLAGS}") - endif() - -elseif ("${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang") - set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") -endif() - - - -add_subdirectory(src) - -enable_testing() -add_subdirectory(tests) +cmake_minimum_required (VERSION 2.6) +project(UNITTEST11 CXX) + +option(ENABLE_GCOV "Adds the --coverage flag to compilation" OFF) + +if (BIICODE) + include(${CMAKE_HOME_DIRECTORY}/biicode.cmake) + init_biicode_block() +endif() + +if (ENABLE_GCOV) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") +endif() + +if (MSVC) + set(CMAKE_CXX_FLAGS "/MP ${CMAKE_CXX_FLAGS}") + +elseif(CMAKE_COMPILER_IS_GNUCXX) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GXX_VERSION) + if (GXX_VERSION VERSION_LESS 4.8) + if (GXX_VERSION VERSION_LESS 4.7) + set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}") + else() + set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") + endif() + else() + set (CMAKE_CXX_FLAGS "-std=c++1y ${CMAKE_CXX_FLAGS}") + endif() + +elseif ("${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" MATCHES ".*clang") + set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") +endif() + +add_subdirectory(src) + +if (BIICODE) + add_biicode_targets() +else() + enable_testing() + add_subdirectory(tests) +endif() diff --git a/LICENSE.md b/LICENSE.md index 93dbb7a..10012ac 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ -UnitTest11 Copyright (C) 2013 Jason Morley (http://www.morleydev.co.uk) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +UnitTest11 Copyright (C) 2013 Jason Morley (http://www.morleydev.co.uk) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 3e5b93e..b5d2b00 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ -UnitTest11 -========== - -**Please note this library is still in early-stage active development and not yet finished. Breaking changes will be avoided when possible, but this cannot be guaranteed.** - -A unit testing and mocking library written in C++, for C++, taking advantage of the new C++11 features to write human-readable unit tests in a given-when-then-finally (arrange-act-assert-cleanup) format. - -Useful Links ------------- - -* Wiki Documentation: https://github.com/MorleyDev/UnitTest11/wiki -* Issue Tracker: https://github.com/MorleyDev/UnitTest11/issues?state=open - -Build Status ------------- - -* [![Build Status](https://api.travis-ci.org/MorleyDev/UnitTest11.png)](https://api.travis-ci.org/MorleyDev/UnitTest11) on **GNU G++ 4.6 (Debug, Linux)** -* [![Build Status](https://drone.io/github.com/MorleyDev/UnitTest11/status.png)](https://drone.io/github.com/MorleyDev/UnitTest11/latest) on **GNU G++ 4.8 (Release, Linux)** -* [![Build status](https://ci.appveyor.com/api/projects/status/0m779tplb2ceem86)](https://ci.appveyor.com/project/MorleyDev/unittest11) on **Visual Studio 2013 (Release, Windows)** - -Code Coverage -------------- - -[![Coverage Status](https://coveralls.io/repos/MorleyDev/UnitTest11/badge.png)](https://coveralls.io/r/MorleyDev/UnitTest11) +UnitTest11 +========== + +**Please note this library is still in early-stage active development and not yet finished. Breaking changes will be avoided when possible, but this cannot be guaranteed.** + +A unit testing and mocking library written in C++, for C++, taking advantage of the new C++11 features to write human-readable unit tests in a given-when-then-finally (arrange-act-assert-cleanup) format. + +Useful Links +------------ + +* Wiki Documentation: https://github.com/MorleyDev/UnitTest11/wiki +* Issue Tracker: https://github.com/MorleyDev/UnitTest11/issues?state=open + +Build Status +------------ + +* [![Build Status](https://api.travis-ci.org/MorleyDev/UnitTest11.png)](https://api.travis-ci.org/MorleyDev/UnitTest11) on **GNU G++ 4.6 (Debug, Linux)** +* [![Build Status](https://drone.io/github.com/MorleyDev/UnitTest11/status.png)](https://drone.io/github.com/MorleyDev/UnitTest11/latest) on **GNU G++ 4.8 (Release, Linux)** +* [![Build status](https://ci.appveyor.com/api/projects/status/0m779tplb2ceem86)](https://ci.appveyor.com/project/MorleyDev/unittest11) on **Visual Studio 2013 (Release, Windows)** + +Code Coverage +------------- + +[![Coverage Status](https://coveralls.io/repos/MorleyDev/UnitTest11/badge.png)](https://coveralls.io/r/MorleyDev/UnitTest11) diff --git a/UnitTest11.hpp b/UnitTest11.hpp new file mode 100644 index 0000000..37b81b5 --- /dev/null +++ b/UnitTest11.hpp @@ -0,0 +1,33 @@ +#ifndef UNITTEST11_HPP +#define UNITTEST11_HPP + +#include "UnitTest11/Core.hpp" +#include "UnitTest11/Run.hpp" + +#include "UnitTest11/Is/EqualTo.hpp" +#include "UnitTest11/Is/Empty.hpp" +#include "UnitTest11/Is/Any.hpp" +#include "UnitTest11/Is/True.hpp" +#include "UnitTest11/Is/False.hpp" +#include "UnitTest11/Is/Zero.hpp" +#include "UnitTest11/Is/NaN.hpp" +#include "UnitTest11/Is/Infinity.hpp" +#include "UnitTest11/Is/Null.hpp" +#include "UnitTest11/Is/Between.hpp" +#include "UnitTest11/Is/GreaterThan.hpp" +#include "UnitTest11/Is/LessThan.hpp" + +#include "UnitTest11/Is/String/Containing.hpp" +#include "UnitTest11/Is/String/BeginningWith.hpp" +#include "UnitTest11/Is/String/EndingWith.hpp" + +#include "UnitTest11/Is/Iterable/Of.hpp" +#include "UnitTest11/Is/Iterable/EquivalentTo.hpp" +#include "UnitTest11/Is/Iterable/Containing/Item.hpp" +#include "UnitTest11/Is/Iterable/Containing/Subset.hpp" + +#include "UnitTest11/Will/Throw.hpp" +#include "UnitTest11/Will/Pass.hpp" + + +#endif // UNITTEST11_HPP diff --git a/UnitTest11/Assert/Fail.hpp b/UnitTest11/Assert/Fail.hpp new file mode 100644 index 0000000..bb96b28 --- /dev/null +++ b/UnitTest11/Assert/Fail.hpp @@ -0,0 +1,14 @@ +#ifndef UNITTEST11_ASSERT_FAIL_HPP +#define UNITTEST11_ASSERT_FAIL_HPP + +#include + +namespace ut11 +{ + namespace Assert + { + extern void Fail(std::size_t line, std::string file, std::string message); + } +} + +#endif // UNITTEST11_ASSERT_FAIL_HPP diff --git a/UnitTest11/Assert/That.hpp b/UnitTest11/Assert/That.hpp new file mode 100644 index 0000000..10874b7 --- /dev/null +++ b/UnitTest11/Assert/That.hpp @@ -0,0 +1,29 @@ +#ifndef UNITTEST11_ASSERT_THAT_HPP +#define UNITTEST11_ASSERT_THAT_HPP + +#include "Fail.hpp" +#include + +namespace ut11 +{ + namespace Assert + { + template + inline void That(std::size_t line, std::string file, const Expected& expected, const Operand& operand) + { + if ( operand(expected) ) + return; + Fail(line, file, operand.GetErrorMessage(expected)); + } + + template + inline void That(std::size_t line, std::string file, std::string message, const Expected& expected, const Operand& operand) + { + if ( operand(expected) ) + return; + Fail(line, file, message); + } + } +} + +#endif // UNITTEST11_ASSERT_THAT_HPP diff --git a/UnitTest11/Category.hpp b/UnitTest11/Category.hpp new file mode 100644 index 0000000..21c2371 --- /dev/null +++ b/UnitTest11/Category.hpp @@ -0,0 +1,48 @@ +/* + * Category.hpp + * + * Created on: 10 Jun 2013 + * Author: Jason + */ + +#ifndef UT11_CATEGORY_HPP_INCLUDED +#define UT11_CATEGORY_HPP_INCLUDED + +#include + +namespace ut11 +{ + /*! \brief A category used when declaring a fixture to record what categories that fixture belongs to + * + * DeclareFixture(TestFixtureName)(Category("the_category")); + * DeclareFixture(TestFixtureName)({ Category("the_category"), Category("the_other_category") }); + */ + struct Category + { + public: + Category(std::string category) + : m_category(category) + { + } + + const std::string& GetName() const + { + return m_category; + } + + bool operator==(const Category& other) const + { + return m_category == other.m_category; + } + + bool operator<(const Category& other) const + { + return m_category < other.m_category; + } + + private: + std::string m_category; + }; +} + +#endif /* UT11_CATEGORY_HPP_INCLUDED */ diff --git a/UnitTest11/Core.hpp b/UnitTest11/Core.hpp new file mode 100644 index 0000000..0eaf48e --- /dev/null +++ b/UnitTest11/Core.hpp @@ -0,0 +1,12 @@ +#ifndef UT11_CORE_HPP_INCLUDED +#define UT11_CORE_HPP_INCLUDED + +#include "TestFixture.hpp" +#include "Assert/That.hpp" +#include "Macros.hpp" + +#include "detail/DeclareFixture.hpp" +#include "detail/MockTimesVerify.hpp" +#include "detail/MockVerify.hpp" + +#endif // UT11_CORE_HPP_INCLUDED diff --git a/UnitTest11/Is/Any.hpp b/UnitTest11/Is/Any.hpp new file mode 100644 index 0000000..496a4bb --- /dev/null +++ b/UnitTest11/Is/Any.hpp @@ -0,0 +1,54 @@ +#ifndef UNITTEST11_IS_ANY_HPP +#define UNITTEST11_IS_ANY_HPP + +#include "../detail/BaseOperand.hpp" +#include +#include +#include + +namespace ut11 +{ + namespace Operands + { + template + struct IsAny : public ut11::detail::BaseOperand> + { + bool operator()(const T&) const + { + return true; + } + + template bool operator()(const U&) const + { + return std::is_base_of::value || std::is_convertible::value; + } + + template inline std::string GetErrorMessage(const U&) const + { + std::stringstream errorMessage; + errorMessage << "Expected any of class " << (typeid(T).name()) << " or derived but was " << (typeid(U).name()); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is of type U, or is a base of or convertible to type U, otherwise false */ + template inline Operands::IsAny Any() + { + return Operands::IsAny(); + } + + namespace Not + { + /*! \brief Operand returns true if Actual is not of type U and it is not a base of or convertible to type U, otherwise false */ + template inline detail::NotOperand< Operands::IsAny > Any() + { + return !Operands::IsAny(); + } + } + } +} + +#endif // UNITTEST11_IS_ANY_HPP diff --git a/UnitTest11/Is/Between.hpp b/UnitTest11/Is/Between.hpp new file mode 100644 index 0000000..27f0f01 --- /dev/null +++ b/UnitTest11/Is/Between.hpp @@ -0,0 +1,57 @@ +#ifndef UNITTEST11_IS_BETWEEN_HPP +#define UNITTEST11_IS_BETWEEN_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" +#include + +namespace ut11 +{ + namespace Operands + { + template + struct IsBetween : public detail::BaseOperand> + { + const U& low; + const V& high; + + IsBetween(const U& low, const V& high) + : low(low), + high(high) + { + } + + template inline bool operator()(const T& value) const + { + return low < value && value <= high; + } + + template inline std::string GetErrorMessage(const Q& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected between " << ut11::utility::ToString(low) << " and " << ut11::utility::ToString(high) << " but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is greater than or equal to low, and Actual is less than or equal to high, otherwise false */ + template inline Operands::IsBetween Between(const U& low, const V& high) + { + return Operands::IsBetween(low, high); + } + + namespace Not + { + /*! \brief Operand returns true if Actual is less than low, or Actual is greater than high, otherwise false */ + template inline detail::NotOperand< Operands::IsBetween > Between(const U& low, const V& high) + { + return !Operands::IsBetween(low, high); + } + } + } +} + +#endif // UNITTEST11_IS_BETWEEN_HPP diff --git a/UnitTest11/Is/Empty.hpp b/UnitTest11/Is/Empty.hpp new file mode 100644 index 0000000..151624a --- /dev/null +++ b/UnitTest11/Is/Empty.hpp @@ -0,0 +1,58 @@ +/* + * Empty.hpp + * + * Created on: 27 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_IS_EMPTY_HPP_INCLUDED +#define UT11_IS_EMPTY_HPP_INCLUDED + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct IsEmpty : public ut11::detail::BaseOperand + { + inline bool operator()(const char* actual) const + { + return std::string(actual).length() == 0; + } + + template inline bool operator()(const T& actual) const + { + for(const auto& i : actual) + return false; + return true; + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected empty but was " << utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Passes if the given iterable is empty */ + extern Operands::IsEmpty Empty; + + namespace Not + { + /*! \brief Passes if the given iterable is not empty */ + extern detail::NotOperand Empty; + } + } +} + + +#endif /* UT11_IS_EMPTY_HPP_INCLUDED */ diff --git a/UnitTest11/Is/EqualTo.hpp b/UnitTest11/Is/EqualTo.hpp new file mode 100644 index 0000000..2f1e40f --- /dev/null +++ b/UnitTest11/Is/EqualTo.hpp @@ -0,0 +1,60 @@ +#ifndef UNITTEST11_IS_EQUALTO_HPP +#define UNITTEST11_IS_EQUALTO_HPP + +#include "../utility/AreEqual.hpp" +#include "../utility/ToString.hpp" +#include "../detail/BaseOperand.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + template struct EqualTo : public detail::BaseOperand> + { + private: + const U& m_expected; + + public: + explicit EqualTo(const U& expected) + : m_expected(expected) + { + } + + template inline bool operator()(const T& actual) const + { + return utility::AreEqual(m_expected, actual); + } + + template inline std::string GetErrorMessage(const T& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected " << utility::ToString(m_expected) << " but was " << utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual == Expected, otherwise false */ + template inline Operands::EqualTo EqualTo(const U& expected) + { + return Operands::EqualTo(expected); + } + + namespace Not + { + /*! \brief Operand returns true if Actual != Expected, otherwise false */ + template inline detail::NotOperand< Operands::EqualTo > EqualTo(const U& expected) + { + return !Operands::EqualTo(expected); + } + } + } +} + + +#endif // UNITTEST11_IS_EQUALTO_HPP diff --git a/UnitTest11/Is/False.hpp b/UnitTest11/Is/False.hpp new file mode 100644 index 0000000..b17d2fb --- /dev/null +++ b/UnitTest11/Is/False.hpp @@ -0,0 +1,43 @@ +#ifndef UNITTEST11_IS_FALSE_HPP +#define UNITTEST11_IS_FALSE_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct FalseOperand : public detail::BaseOperand + { + template bool operator()(const T& value) const + { + return !static_cast(value); + } + + template inline std::string GetErrorMessage(const T& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected false but was " << utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is false, otherwise false */ + extern Operands::FalseOperand False; + + namespace Not + { + /*! \brief Operand returns true if Actual is true, otherwise false */ + extern detail::NotOperand False; + } + } +} + +#endif // UNITTEST11_IS_FALSE_HPP diff --git a/UnitTest11/Is/GreaterThan.hpp b/UnitTest11/Is/GreaterThan.hpp new file mode 100644 index 0000000..5644ed8 --- /dev/null +++ b/UnitTest11/Is/GreaterThan.hpp @@ -0,0 +1,54 @@ +#ifndef UNITTEST11_IS_GREATERTHAN_HPP +#define UNITTEST11_IS_GREATERTHAN_HPP + +#include "../detail/BaseOperand.hpp" +#include + +namespace ut11 +{ + namespace Operands + { + template + struct IsGreaterThan : public detail::BaseOperand> + { + const U& low; + + explicit IsGreaterThan(const U& low) + : low(low) + { + } + + template inline bool operator()(const T& value) const + { + return value > low; + } + + template inline std::string GetErrorMessage(const Q& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected greater than " << ut11::utility::ToString(low) << " but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is greater than Expected, otherwise false */ + template inline Operands::IsGreaterThan GreaterThan(const U& low) + { + return Operands::IsGreaterThan(low); + } + + namespace Not + { + /*! \brief Operand returns true if Actual is not greater than Expected, otherwise false */ + template inline detail::NotOperand< Operands::IsGreaterThan > GreaterThan(const U& low) + { + return !Operands::IsGreaterThan(low); + } + } + } +} + +#endif // UNITTEST11_IS_GREATERTHAN_HPP diff --git a/UnitTest11/Is/Infinity.hpp b/UnitTest11/Is/Infinity.hpp new file mode 100644 index 0000000..77d5e32 --- /dev/null +++ b/UnitTest11/Is/Infinity.hpp @@ -0,0 +1,86 @@ +#ifndef UNITTEST11_IS_INFINITY_HPP +#define UNITTEST11_IS_INFINITY_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct IsInfinity : public detail::BaseOperand + { + template bool operator()(const U& value) const + { + return std::numeric_limits::has_infinity && (std::numeric_limits::infinity() == value || -std::numeric_limits::infinity() == value); + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected infinity but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + + struct IsPositiveInfinity : public detail::BaseOperand + { + template bool operator()(const U& value) const + { + return IsInfinity().operator()(value) && value >= 0; + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected positive infinity but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + + struct IsNegativeInfinity : public detail::BaseOperand + { + template bool operator()(const U& value) const + { + return IsInfinity().operator()(value) && value <= 0; + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected negative infinity but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is Positive or Negative Infinity, otherwise false */ + extern Operands::IsInfinity Infinity; + + /*! \brief Operand returns true if Actual is Positive Infinity, otherwise false */ + extern Operands::IsPositiveInfinity PositiveInfinity; + + /*! \brief Operand returns true if Actual is Negative Infinity, otherwise false */ + extern Operands::IsNegativeInfinity NegativeInfinity; + + namespace Not + { + /*! \brief Operand returns false if Actual is Positive or Negative Infinity, otherwise true */ + extern detail::NotOperand Infinity; + + /*! \brief Operand returns false if Actual is Positive Infinity, otherwise true */ + extern detail::NotOperand PositiveInfinity; + + /*! \brief Operand returns false if Actual is Negative Infinity, otherwise true */ + extern detail::NotOperand NegativeInfinity; + } + } +} + +#endif // UNITTEST11_IS_INFINITY_HPP diff --git a/UnitTest11/Is/Iterable/Containing/Item.hpp b/UnitTest11/Is/Iterable/Containing/Item.hpp new file mode 100644 index 0000000..a58be50 --- /dev/null +++ b/UnitTest11/Is/Iterable/Containing/Item.hpp @@ -0,0 +1,76 @@ +/* + * Item.hpp + * + * Created on: 28 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_IS_ITERABLE_CONTAINING_ITEM_HPP_INCLUDED +#define UT11_IS_ITERABLE_CONTAINING_ITEM_HPP_INCLUDED + +#include "../../../detail/BaseOperand.hpp" +#include "../../../utility/AreEqual.hpp" +#include "../../../utility/ToString.hpp" +#include + +namespace ut11 +{ + namespace Operands + { + template struct IsIterableContainingItem : public detail::BaseOperand> + { + const T& m_expected; + + explicit IsIterableContainingItem(const T& expected) + : m_expected(expected) + { + } + + template inline bool operator()(const U& actual) const + { + for(const auto& i : actual) + if ( utility::AreEqual(m_expected, i) ) + return true; + + return false; + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected iterable containing " << utility::ToString(m_expected) << " but was " << utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + namespace Iterable + { + namespace Containing + { + /*! \brief Passes if the given iterable contains at least one of the given item */ + template inline Operands::IsIterableContainingItem Item(const T& expected) + { + return Operands::IsIterableContainingItem(expected); + } + } + + namespace Not + { + namespace Containing + { + /*! \brief Passes if the given iterable does not contain at least one of the given item */ + template inline detail::NotOperand< Operands::IsIterableContainingItem > Item(const T& expected) + { + return !Operands::IsIterableContainingItem(expected); + } + } + } + } + } +} + + +#endif /* UT11_IS_ITERABLE_CONTAINING_ITEM_HPP_INCLUDED */ diff --git a/UnitTest11/Is/Iterable/Containing/Subset.hpp b/UnitTest11/Is/Iterable/Containing/Subset.hpp new file mode 100644 index 0000000..76ab1c7 --- /dev/null +++ b/UnitTest11/Is/Iterable/Containing/Subset.hpp @@ -0,0 +1,107 @@ +/* + * Subset.hpp + * + * Created on: 28 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_IS_ITERABLE_CONTAINING_SUBSET_HPP_INCLUDED +#define UT11_IS_ITERABLE_CONTAINING_SUBSET_HPP_INCLUDED + +#include "../../../detail/BaseOperand.hpp" +#include "../../../utility/AreEqual.hpp" +#include "../../../utility/ToString.hpp" +#include +#include + +namespace ut11 +{ + namespace Operands + { + template struct IsIterableContainingSubset : public detail::BaseOperand> + { + const T& m_expected; + + explicit IsIterableContainingSubset(const T& expected) + : m_expected(expected) + { + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected iterable containing subset" << utility::ToString(m_expected) << " but was " << utility::ToString(actual); + return errorMessage.str(); + } + + template bool operator()(const U& actual) const + { + auto actualIterators = CreateIteratorListFromInput(actual); + auto expectedIterators = CreateIteratorListFromInput(m_expected); + + while( !expectedIterators.empty() ) + { + if (CompareListsAndRemoveFirstDuplicate(expectedIterators, actualIterators)) + continue; + + return false; + } + return true; + } + + private: + template static bool CompareListsAndRemoveFirstDuplicate(A& a, B& b) + { + for(auto i = a.begin(); i != a.end(); ++i) + for(auto j = b.begin(); j != b.end(); ++j) + if ( utility::AreEqual(**i, **j) ) + { + a.erase(i); + b.erase(j); + return true; + } + + return false; + } + + template static std::list< decltype(std::declval().begin()) > CreateIteratorListFromInput(const U& input) + { + std::list< decltype(std::declval().begin()) > iterators; + for(auto i = input.begin(); i != input.end(); ++i) + iterators.push_back(i); + + return iterators; + } + }; + } + + namespace Is + { + namespace Iterable + { + namespace Containing + { + /*! \brief Passes if the given iterable does contains the given subset of items */ + template inline Operands::IsIterableContainingSubset Subset(const T& expected) + { + return Operands::IsIterableContainingSubset(expected); + } + } + + namespace Not + { + namespace Containing + { + /*! \brief Passes if the given iterable does not contain the given subset of items */ + template inline detail::NotOperand< Operands::IsIterableContainingSubset > Subset(const T& expected) + { + return !Operands::IsIterableContainingSubset(expected); + } + } + } + } + } +} + + +#endif /* UT11_IS_ITERABLE_CONTAINING_SUBSET_HPP_INCLUDED */ diff --git a/UnitTest11/Is/Iterable/EquivalentTo.hpp b/UnitTest11/Is/Iterable/EquivalentTo.hpp new file mode 100644 index 0000000..f9ed415 --- /dev/null +++ b/UnitTest11/Is/Iterable/EquivalentTo.hpp @@ -0,0 +1,103 @@ +/* + * EquivalentTo.hpp + * + * Created on: 23 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_IS_ITERABLE_EQUIVALENTTO_HPP_INCLUDED +#define UT11_IS_ITERABLE_EQUIVALENTTO_HPP_INCLUDED + +#include "../../detail/BaseOperand.hpp" +#include "../../utility/ToString.hpp" +#include "../../utility/AreEqual.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + template + struct IsIterableEquivalentTo : public detail::BaseOperand> + { + const T& m_expected; + + explicit IsIterableEquivalentTo(const T& expected) + : m_expected(expected) + { + } + + template bool operator()(const U& actual) const + { + auto actualIterators = CreateIteratorListFromInput(actual); + auto expectedIterators = CreateIteratorListFromInput(m_expected); + + while(!actualIterators.empty() || !expectedIterators.empty() ) + { + if (CompareListsAndRemoveFirstDuplicate(expectedIterators, actualIterators)) + continue; + + return false; + } + return true; + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected equivalent of " << utility::ToString(m_expected) << " but was " << utility::ToString(actual); + return errorMessage.str(); + } + + private: + template static bool CompareListsAndRemoveFirstDuplicate(A& a, B& b) + { + for(auto i = a.begin(); i != a.end(); ++i) + for(auto j = b.begin(); j != b.end(); ++j) + if ( utility::AreEqual(**i, **j) ) + { + a.erase(i); + b.erase(j); + return true; + } + + return false; + } + + template static std::list< decltype(std::declval().begin()) > CreateIteratorListFromInput(const U& input) + { + std::list< decltype(std::declval().begin()) > iterators; + for(auto i = input.begin(); i != input.end(); ++i) + iterators.push_back(i); + + return iterators; + } + }; + } + + namespace Is + { + namespace Iterable + { + /*! \brief Takes an expected and actual iterable (has ::begin and ::end functions) and returns true if the contents of those iterables are the same, ignoring order */ + template Operands::IsIterableEquivalentTo EquivalentTo(const T& expected) + { + return Operands::IsIterableEquivalentTo(expected); + } + + namespace Not + { + /*! \brief Takes an expected and actual iterable (has ::begin and ::end functions) and returns true if the contents of those iterables are not the same, ignoring order */ + template detail::NotOperand< Operands::IsIterableEquivalentTo > EquivalentTo(const T& expected) + { + return !Operands::IsIterableEquivalentTo(expected); + } + } + } + } +} + + +#endif /* UT11_IS_ITERABLE_EQUIVALENTTO_HPP_INCLUDED */ diff --git a/UnitTest11/Is/Iterable/Of.hpp b/UnitTest11/Is/Iterable/Of.hpp new file mode 100644 index 0000000..4151352 --- /dev/null +++ b/UnitTest11/Is/Iterable/Of.hpp @@ -0,0 +1,60 @@ +/* + * Of.hpp + * + * Created on: 23 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_IS_ITERABLE_OF_HPP_INCLUDED +#define UT11_IS_ITERABLE_OF_HPP_INCLUDED + +#include "../../detail/BaseOperand.hpp" +#include "../../utility/Meta/IsIterableOfType.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + template + struct IsIteratorOf : public ut11::detail::BaseOperand> + { + template inline bool operator()(const U& actual) const + { + return utility::Meta::IsIterableOfType::value; + } + + template inline std::string GetErrorMessage(const U&) const + { + std::stringstream errorMessage; + errorMessage << "Expected iterable of " << typeid(T).name() << " but was type " << typeid(U).name(); + return errorMessage.str(); + } + }; + } + + namespace Is + { + namespace Iterable + { + /*! \brief Passes if the actual is an iterable (has begin and end functions) whose items are of type T, or descended from type T */ + template inline Operands::IsIteratorOf Of() + { + return Operands::IsIteratorOf(); + } + + namespace Not + { + /*! \brief Passes if the actual is not an iterable (has begin and end functions) whose items are of type T, or descended from type T */ + template inline detail::NotOperand< Operands::IsIteratorOf > Of() + { + return !Operands::IsIteratorOf(); + } + } + } + } +} + +#endif /* UT11_IS_ITERABLE_OF_HPP_INCLUDED */ diff --git a/UnitTest11/Is/LessThan.hpp b/UnitTest11/Is/LessThan.hpp new file mode 100644 index 0000000..aaad616 --- /dev/null +++ b/UnitTest11/Is/LessThan.hpp @@ -0,0 +1,57 @@ +#ifndef UNITTEST11_IS_LESSTHAN_HPP +#define UNITTEST11_IS_LESSTHAN_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + template + struct IsLessThan : public detail::BaseOperand> + { + const U& high; + + explicit IsLessThan(const U& high) + : high(high) + { + } + + template inline bool operator()(const T& value) const + { + return value < high; + } + + template inline std::string GetErrorMessage(const Q& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected less than " << ut11::utility::ToString(high) << " but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is less than the Expected, otherwise false */ + template inline Operands::IsLessThan LessThan(const U& high) + { + return Operands::IsLessThan(high); + } + + namespace Not + { + /*! \brief Operand returns false if Actual is not less than the Expected, otherwise false */ + template inline detail::NotOperand< Operands::IsLessThan > LessThan(const U& high) + { + return !Operands::IsLessThan(high); + } + } + } +} + +#endif // UNITTEST11_IS_LESSTHAN_HPP diff --git a/UnitTest11/Is/NaN.hpp b/UnitTest11/Is/NaN.hpp new file mode 100644 index 0000000..3c83080 --- /dev/null +++ b/UnitTest11/Is/NaN.hpp @@ -0,0 +1,90 @@ +#ifndef UNITTEST11_IS_NAN_HPP +#define UNITTEST11_IS_NAN_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include +#include + +namespace ut11 +{ + namespace utility + { + namespace detail + { + template::value, bool IsIntegral = std::is_integral::value> + struct NanHelper + { + inline bool operator()(const T& value) + { + return std::isnan(value); + } + }; + + template + struct NanHelper // Not Float but Integer so Is Number + { + inline bool operator()(const T&) + { + return false; + } + }; + + template + struct NanHelper // Not Float or Integer so Not Number + { + inline bool operator()(const T&) + { + return true; + } + }; + } + + /*! \brief Can be partially specialised to handle custom cases when comparing for NaN + * + * \tparam T The type being checked for NaN + */ + template struct IsNotANumber + { + bool operator()(const T& value) const + { + return detail::NanHelper()(value); + } + }; + } + + namespace Operands + { + + struct IsNaN : public detail::BaseOperand + { + template bool operator()(const U& value) const + { + return utility::IsNotANumber()(value); + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected NaN but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual has a value that is Not A Number, otherwise false */ + extern Operands::IsNaN NaN; + + namespace Not + { + /*! \brief Operand returns true if Actual has a value that is a number, otherwise false */ + extern detail::NotOperand NaN; + } + } +} + +#endif // UNITTEST11_IS_NAN_HPP diff --git a/UnitTest11/Is/Null.hpp b/UnitTest11/Is/Null.hpp new file mode 100644 index 0000000..d92606e --- /dev/null +++ b/UnitTest11/Is/Null.hpp @@ -0,0 +1,48 @@ +#ifndef UNITTEST11_IS_NULL_HPP +#define UNITTEST11_IS_NULL_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct IsNull : public detail::BaseOperand + { + template bool operator()(std::weak_ptr value) const + { + return value.lock() == std::shared_ptr(nullptr); + } + + template bool operator()(const U& value) const + { + return value == U(nullptr); + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected null but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is null, otherwise false */ + extern Operands::IsNull Null; + + namespace Not + { + /*! \brief Operand returns true if Actual is not null, otherwise false */ + extern detail::NotOperand Null; + } + } +} + +#endif // UNITTEST11_IS_NULL_HPP diff --git a/UnitTest11/Is/String/BeginningWith.hpp b/UnitTest11/Is/String/BeginningWith.hpp new file mode 100644 index 0000000..37068bc --- /dev/null +++ b/UnitTest11/Is/String/BeginningWith.hpp @@ -0,0 +1,59 @@ +#ifndef UT11_IS_STRING_BEGINNINGWITH_HPP_INCLUDED +#define UT11_IS_STRING_BEGINNINGWITH_HPP_INCLUDED + +#include "../../detail/BaseOperand.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct IsStringBeginningWith : public ut11::detail::BaseOperand + { + std::string m_expected; + + explicit IsStringBeginningWith(const std::string& expected) + : m_expected(expected) + { + } + + inline bool operator()(const std::string& actual) const + { + return ( actual.length() >= m_expected.length() && actual.substr(0, m_expected.length()) == m_expected); + } + + inline std::string GetErrorMessage(const std::string& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected string BeginningWith " << m_expected << " but was " << actual; + return errorMessage.str(); + } + }; + } + + namespace Is + { + namespace String + { + /*! \brief Operand returns true if string begins with expected string, otherwise returns false */ + inline Operands::IsStringBeginningWith BeginningWith(std::string expected) + { + return Operands::IsStringBeginningWith(expected); + } + + namespace Not + { + /*! \brief Operand returns false if string begins with expected string, otherwise returns true */ + inline detail::NotOperand BeginningWith(std::string expected) + { + return !Operands::IsStringBeginningWith(expected); + } + } + } + } +} + + +#endif /* UT11_IS_STRING_BEGINNINGWITH_HPP_INCLUDED */ diff --git a/UnitTest11/Is/String/Containing.hpp b/UnitTest11/Is/String/Containing.hpp new file mode 100644 index 0000000..8ed1d19 --- /dev/null +++ b/UnitTest11/Is/String/Containing.hpp @@ -0,0 +1,92 @@ +#ifndef UNITTEST11_IS_STRING_CONTAINING_HPP +#define UNITTEST11_IS_STRING_CONTAINING_HPP + +#include "../../detail/BaseOperand.hpp" +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct IsStringContainingSubstring : public ut11::detail::BaseOperand + { + std::string m_expected; + + IsStringContainingSubstring(const std::string& expected) + : m_expected(expected) + { + } + + inline bool operator()(const std::string& actual) const + { + return actual.find(m_expected) != std::string::npos; + } + + inline std::string GetErrorMessage(const std::string& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected string containing " << m_expected << " but was " << actual; + return errorMessage.str(); + } + }; + + struct IsStringContainingCharacter : public ut11::detail::BaseOperand + { + const char m_expected; + + explicit IsStringContainingCharacter(const char expected) + : m_expected(expected) + { + } + + inline bool operator()(const std::string& actual) const + { + return actual.find(m_expected) != std::string::npos; + } + + inline std::string GetErrorMessage(const std::string& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected string containing " << m_expected << " but was " << actual; + return errorMessage.str(); + } + }; + } + + namespace Is + { + namespace String + { + /*! \brief Operand returns true if string contains expected string, otherwise returns false */ + inline Operands::IsStringContainingSubstring Containing(std::string expected) + { + return Operands::IsStringContainingSubstring(expected); + } + + /*! \brief Operand returns true if string contains expected character, otherwise returns false */ + inline Operands::IsStringContainingCharacter Containing(const char expected) + { + return Operands::IsStringContainingCharacter(expected); + } + + namespace Not + { + /*! \brief Operand returns false if string contains expected string, otherwise returns true */ + inline detail::NotOperand Containing(std::string expected) + { + return !Operands::IsStringContainingSubstring(expected); + } + + /*! \brief Operand returns false if string contains expected character, otherwise returns true */ + inline detail::NotOperand Containing(const char expected) + { + return !Operands::IsStringContainingCharacter(expected); + } + } + } + + } +} + +#endif /* UNITTEST11_IS_STRING_CONTAINING_HPP */ diff --git a/UnitTest11/Is/String/EndingWith.hpp b/UnitTest11/Is/String/EndingWith.hpp new file mode 100644 index 0000000..f6bac69 --- /dev/null +++ b/UnitTest11/Is/String/EndingWith.hpp @@ -0,0 +1,65 @@ +/* + * EndingWith.hpp + * + * Created on: 22 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_IS_STRING_ENDINGWITH_HPP_INCLUDED +#define UT11_IS_STRING_ENDINGWITH_HPP_INCLUDED + +#include "../../detail/BaseOperand.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct IsStringEndingWith : public ut11::detail::BaseOperand + { + std::string m_expected; + + explicit IsStringEndingWith(const std::string& expected) + : m_expected(expected) + { + } + + inline bool operator()(const std::string& actual) const + { + return ( actual.length() >= m_expected.length() && actual.substr(actual.length()-m_expected.length(), m_expected.length()) == m_expected); + } + + inline std::string GetErrorMessage(const std::string& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected string EndingWith " << m_expected << " but was " << actual; + return errorMessage.str(); + } + }; + } + + namespace Is + { + namespace String + { + /*! \brief Operand returns true if string ends with expected string, otherwise returns false */ + inline Operands::IsStringEndingWith EndingWith(std::string expected) + { + return Operands::IsStringEndingWith(expected); + } + + namespace Not + { + /*! \brief Operand returns false if string ends with expected string, otherwise returns true */ + inline detail::NotOperand EndingWith(std::string expected) + { + return !Operands::IsStringEndingWith(expected); + } + } + } + } +} + +#endif /* UT11_IS_STRING_ENDINGWITH_HPP_INCLUDED */ diff --git a/UnitTest11/Is/True.hpp b/UnitTest11/Is/True.hpp new file mode 100644 index 0000000..37aa52b --- /dev/null +++ b/UnitTest11/Is/True.hpp @@ -0,0 +1,43 @@ +#ifndef UNITTEST11_IS_TRUE_HPP +#define UNITTEST11_IS_TRUE_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" + +#include +#include + +namespace ut11 +{ + namespace Operands + { + struct TrueOperand : public detail::BaseOperand + { + template bool operator()(const T& value) const + { + return static_cast(value); + } + + template inline std::string GetErrorMessage(const T& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected true but was " << utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual is true, otherwise false */ + extern Operands::TrueOperand True; + + namespace Not + { + /*! \brief Operand returns true if Actual is false, otherwise false */ + extern detail::NotOperand True; + } + } +} + +#endif // UNITTEST11_IS_TRUE_HPP diff --git a/UnitTest11/Is/Zero.hpp b/UnitTest11/Is/Zero.hpp new file mode 100644 index 0000000..23a7fd4 --- /dev/null +++ b/UnitTest11/Is/Zero.hpp @@ -0,0 +1,41 @@ +#ifndef UNITTEST11_IS_ZERO_HPP +#define UNITTEST11_IS_ZERO_HPP + +#include "../detail/BaseOperand.hpp" +#include "../utility/ToString.hpp" +#include + +namespace ut11 +{ + namespace Operands + { + struct IsZero : public detail::BaseOperand + { + template bool operator()(const U& value) const + { + return value == U(0); + } + + template inline std::string GetErrorMessage(const U& actual) const + { + std::stringstream errorMessage; + errorMessage << "Expected zero but was " << ut11::utility::ToString(actual); + return errorMessage.str(); + } + }; + } + + namespace Is + { + /*! \brief Operand returns true if Actual == 0, otherwise false */ + extern Operands::IsZero Zero; + + namespace Not + { + /*! \brief Operand returns true if Actual != 0, otherwise false */ + extern detail::NotOperand Zero; + } + } +} + +#endif // UNITTEST11_IS_ZERO_HPP diff --git a/UnitTest11/Macros.hpp b/UnitTest11/Macros.hpp new file mode 100644 index 0000000..0c179bb --- /dev/null +++ b/UnitTest11/Macros.hpp @@ -0,0 +1,114 @@ +#ifndef UNITTEST11_MACROS_HPP +#define UNITTEST11_MACROS_HPP + +#ifdef __COUNTER__ +#define UT11_UNIQUE_NUMBER __COUNTER__ +#else +#define UT11_UNIQUE_NUMBER __LINE__ +#endif + + +// Work around for Visual Studio compiler bug where variadic macros are not correctly expanded +#ifdef _MSC_VER +#define UT11_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define UT11_VA_NUM_ARGS_REVERSE_SEQUENCE 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +#define UT11_LEFT_PARENTHESIS ( +#define UT11_RIGHT_PARENTHESIS ) +#define UT11_VA_NARGS(...) UT11_VA_NUM_ARGS_HELPER UT11_LEFT_PARENTHESIS __VA_ARGS__, UT11_VA_NUM_ARGS_REVERSE_SEQUENCE UT11_RIGHT_PARENTHESIS + +#else +#define UT11_VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, N, ...) N +#define UT11_VA_NARGS(...) UT11_VA_NARGS_IMPL(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) +#endif + +#define UT11_MACRO_CONCAT_IMPL(func, suffix) func##suffix +#define UT11_MACRO_CONCAT(func, suffix) UT11_MACRO_CONCAT_IMPL(func, suffix) + +#define UT11_MOCK_ACTION_1(Name) mutable ut11::Mock mock##Name; virtual void Name() { mock##Name(); } +#define UT11_MOCK_ACTION_2(Name, Arg1) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1) { mock##Name(a1); } +#define UT11_MOCK_ACTION_3(Name, Arg1, Arg2) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2) { mock##Name(a1, a2); } +#define UT11_MOCK_ACTION_4(Name, Arg1, Arg2, Arg3) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3) { mock##Name(a1, a2, a3); } +#define UT11_MOCK_ACTION_5(Name, Arg1, Arg2, Arg3, Arg4) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { mock##Name(a1, a2, a3, a4); } +#define UT11_MOCK_ACTION_6(Name, Arg1, Arg2, Arg3, Arg4, Arg5) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { mock##Name(a1, a2, a3, a4, a5); } +#define UT11_MOCK_ACTION_7(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { mock##Name(a1, a2, a3, a4, a5, a6); } +#define UT11_MOCK_ACTION_8(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) { mock##Name(a1, a2, a3, a4, a5, a6, a7); } +#define UT11_MOCK_ACTION_9(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8) { mock##Name(a1, a2, a3, a4, a5, a6, a7, a8, a9); } +#define UT11_MOCK_ACTION_10(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9) mutable ut11::Mock mock##Name; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8, Arg9 a9) { mock##Name(a1, a2, a3, a4, a5, a6, a7, a8, a9); } + +#define UT11_MOCK_FUNCTION_2(Return, Name) mutable ut11::Mock mock##Name; virtual Return Name() { return mock##Name(); } +#define UT11_MOCK_FUNCTION_3(Return, Name, Arg1) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1) { return mock##Name(a1); } +#define UT11_MOCK_FUNCTION_4(Return, Name, Arg1, Arg2) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2) { return mock##Name(a1, a2); } +#define UT11_MOCK_FUNCTION_5(Return, Name, Arg1, Arg2, Arg3) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3) { return mock##Name(a1, a2, a3); } +#define UT11_MOCK_FUNCTION_6(Return, Name, Arg1, Arg2, Arg3, Arg4) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { return mock##Name(a1, a2, a3, a4); } +#define UT11_MOCK_FUNCTION_7(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { return mock##Name(a1, a2, a3, a4, a5); } +#define UT11_MOCK_FUNCTION_8(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { return mock##Name(a1, a2, a3, a4, a5, a6); } +#define UT11_MOCK_FUNCTION_9(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) { return mock##Name(a1, a2, a3, a4, a5, a6, a7); } +#define UT11_MOCK_FUNCTION_10(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8) { return mock##Name(a1, a2, a3, a4, a5, a6, a7, a8, a9); } +#define UT11_MOCK_FUNCTION_11(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9) mutable ut11::Mock mock##Name; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8, Arg9 a9) { return mock##Name(a1, a2, a3, a4, a5, a6, a7, a8, a9); } + +#define UT11_MOCK_ACTION_CONST_1(Name) mutable ut11::Mock mock##Name##Const; virtual void Name() const { mock##Name##Const(); } +#define UT11_MOCK_ACTION_CONST_2(Name, Arg1) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1) const { mock##Name##Const(a1); } +#define UT11_MOCK_ACTION_CONST_3(Name, Arg1, Arg2) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2) const { mock##Name##Const(a1, a2); } +#define UT11_MOCK_ACTION_CONST_4(Name, Arg1, Arg2, Arg3) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3) const { mock##Name##Const(a1, a2, a3); } +#define UT11_MOCK_ACTION_CONST_5(Name, Arg1, Arg2, Arg3, Arg4) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) const { mock##Name##Const(a1, a2, a3, a4); } +#define UT11_MOCK_ACTION_CONST_6(Name, Arg1, Arg2, Arg3, Arg4, Arg5) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) const { mock##Name##Const(a1, a2, a3, a4, a5); } +#define UT11_MOCK_ACTION_CONST_7(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) const { mock##Name##Const(a1, a2, a3, a4, a5, a6); } +#define UT11_MOCK_ACTION_CONST_8(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) const { mock##Name##Const(a1, a2, a3, a4, a5, a6, a7); } +#define UT11_MOCK_ACTION_CONST_9(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8) const { mock##Name##Const(a1, a2, a3, a4, a5, a6, a7, a8, a9); } +#define UT11_MOCK_ACTION_CONST_10(Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9) mutable ut11::Mock mock##Name##Const; virtual void Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8, Arg9 a9) const { mock##Name##Const(a1, a2, a3, a4, a5, a6, a7, a8, a9); } + +#define UT11_MOCK_FUNCTION_CONST_2(Return, Name) mutable ut11::Mock mock##Name##Const; virtual Return Name() const { return mock##Name##Const(); } +#define UT11_MOCK_FUNCTION_CONST_3(Return, Name, Arg1) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1) const { return mock##Name##Const(a1); } +#define UT11_MOCK_FUNCTION_CONST_4(Return, Name, Arg1, Arg2) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2) const { return mock##Name##Const(a1, a2); } +#define UT11_MOCK_FUNCTION_CONST_5(Return, Name, Arg1, Arg2, Arg3) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3) const { return mock##Name##Const(a1, a2, a3); } +#define UT11_MOCK_FUNCTION_CONST_6(Return, Name, Arg1, Arg2, Arg3, Arg4) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) const { return mock##Name##Const(a1, a2, a3, a4); } +#define UT11_MOCK_FUNCTION_CONST_7(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) const { return mock##Name##Const(a1, a2, a3, a4, a5); } +#define UT11_MOCK_FUNCTION_CONST_8(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) const { return mock##Name##Const(a1, a2, a3, a4, a5, a6); } +#define UT11_MOCK_FUNCTION_CONST_9(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7) const { return mock##Name##Const(a1, a2, a3, a4, a5, a6, a7); } +#define UT11_MOCK_FUNCTION_CONST_10(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8) const { return mock##Name##Const(a1, a2, a3, a4, a5, a6, a7, a8, a9); } +#define UT11_MOCK_FUNCTION_CONST_11(Return, Name, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9) mutable ut11::Mock mock##Name##Const; virtual Return Name(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6, Arg7 a7, Arg8 a8, Arg9 a9) const { return mock##Name##Const(a1, a2, a3, a4, a5, a6, a7, a8, a9); } + +#ifdef _MSC_VER +#define UT11_MOCK_ACTION_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_ACTION_, N) UT11_LEFT_PARENTHESIS __VA_ARGS__ UT11_RIGHT_PARENTHESIS +#define UT11_MOCK_FUNCTION_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_FUNCTION_, N) UT11_LEFT_PARENTHESIS __VA_ARGS__ UT11_RIGHT_PARENTHESIS + +#define UT11_MOCK_ACTION_CONST_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_ACTION_CONST_, N) UT11_LEFT_PARENTHESIS __VA_ARGS__ UT11_RIGHT_PARENTHESIS +#define UT11_MOCK_FUNCTION_CONST_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_FUNCTION_CONST_, N) UT11_LEFT_PARENTHESIS __VA_ARGS__ UT11_RIGHT_PARENTHESIS + +#else +#define UT11_MOCK_ACTION_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_ACTION_, N)(__VA_ARGS__) +#define UT11_MOCK_FUNCTION_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_FUNCTION_, N)(__VA_ARGS__) + +#define UT11_MOCK_ACTION_CONST_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_ACTION_CONST_, N)(__VA_ARGS__) +#define UT11_MOCK_FUNCTION_CONST_N(N, ...) UT11_MACRO_CONCAT(UT11_MOCK_FUNCTION_CONST_, N)(__VA_ARGS__) +#endif + +/*! \brief A mock action with no return values (Name, Arguments...) */ +#define MockAction(...) UT11_MOCK_ACTION_N(UT11_VA_NARGS(__VA_ARGS__), __VA_ARGS__) + +/*! \brief A mock function with a return value (Return, Name, Arguments...) */ +#define MockFunction(...) UT11_MOCK_FUNCTION_N(UT11_VA_NARGS(__VA_ARGS__), __VA_ARGS__) + +/*! \brief A mock const action with no return values (Name, Arguments...) */ +#define MockActionConst(...) UT11_MOCK_ACTION_CONST_N(UT11_VA_NARGS(__VA_ARGS__), __VA_ARGS__) + +/*! \brief A mock const function with a return value (Return, Name, Arguments...) */ +#define MockFunctionConst(...) UT11_MOCK_FUNCTION_CONST_N(UT11_VA_NARGS(__VA_ARGS__), __VA_ARGS__) + +/*! \brief Verify a mock function was called with the passed predicates (mock, arguments) */ +#define MockVerify(...) ::ut11::detail::MockVerifyer(__VA_ARGS__, __LINE__, __FILE__) + +/*! \brief Verify a mock function was called with the passed predicates the specified number of times (mock, count, arguments) */ +#define MockVerifyTimes(times, ...) ::ut11::detail::MockTimesVerifyer(__VA_ARGS__, times, __LINE__, __FILE__) + +/*! \brief Declare a Test Fixture, adding it to the runner +* +* Adds a test fixture of type T to the runner. +* Passes any arguments given on the right of the fixture name to that fixture's constructor. +*/ +#define DeclareFixture(...) static const int UT11_MACRO_CONCAT(ut11Fixture, UT11_UNIQUE_NUMBER) = ut11::detail::DeclareFixtureObj<__VA_ARGS__>(#__VA_ARGS__) + +/*! \brief Assert that for the given Actual, the Expectation is true */ +#define AssertThat(...) ut11::Assert::That(__LINE__, __FILE__, __VA_ARGS__) + +#endif // UNITTEST11_MACROS_HPP diff --git a/UnitTest11/Mock.hpp b/UnitTest11/Mock.hpp new file mode 100644 index 0000000..624193c --- /dev/null +++ b/UnitTest11/Mock.hpp @@ -0,0 +1,103 @@ +#ifndef UNITTEST11_MOCK_HPP +#define UNITTEST11_MOCK_HPP + +#include "detail/MockArgumentHandler.hpp" +#include "detail/MockReturnHandler.hpp" +#include "Assert/Fail.hpp" + +#include +#include + +namespace ut11 +{ + /*! \brief A Mock functor object that can be used to mock out injected an std::function or to build up a Mock class */ + template class Mock; + template class Mock + { + public: + Mock() + : m_callbackHandler(), + m_argumentHandler(), + m_returnHandler() + { + } + + ~Mock() + { + } + + R operator()(ARGS... args) + { + if ( m_callbackHandler ) + m_callbackHandler(args...); + + m_argumentHandler.AddCall(args...); + return m_returnHandler(args...); + } + + void SetCallback(std::function callback) + { + m_callbackHandler = callback; + } + + template void SetReturn(V value) { m_returnHandler.SetReturn(value); } + + void VerifyAny(std::size_t line, std::string file) const + { + if ( m_argumentHandler.TotalCount() == 0 ) + Assert::Fail(line, file, GetVerifyFailMessage()); + } + + template void Verify(std::size_t line, std::string file, const Expectations&... expectations) const + { + if ( m_argumentHandler.CountCalls(expectations...) == 0 ) + Assert::Fail(line, file, GetVerifyFailMessage()); + } + + template void VerifyTimes(std::size_t line, std::string file, const Operand& count, const Expectations&... expectations) const + { + VerifyTimes(typename std::is_integral::type(), line, file, count, expectations...); + } + + private: + template void VerifyTimes(std::false_type isNotOperand, std::size_t line, std::string file, const Operand& operand, const Expectations&... expectations) const + { + auto actual = m_argumentHandler.CountCalls(expectations...); + if ( !operand(actual) ) + Assert::Fail(line, file, GetVerifyFailTimesMessageForOperand(operand, actual)); + } + + template void VerifyTimes(std::true_type isOperand, std::size_t line, std::string file, const Count& count, const Expectations&... expectations) const + { + auto actual = m_argumentHandler.CountCalls(expectations...); + if ( actual != count ) + Assert::Fail(line, file, GetVerifyFailTimesMessageForCount(count, actual)); + } + + std::string GetVerifyFailMessage() const + { + return "Expected function call was not found"; + } + + std::string GetVerifyFailTimesMessageForCount(std::size_t expected, std::size_t actual) const + { + std::stringstream output; + output << "Expected function to be called " << expected << " times was actually called " << actual << " times"; + return output.str(); + } + + template std::string GetVerifyFailTimesMessageForOperand(Operand& operand, std::size_t actual) const + { + std::stringstream output; + output << "Expected function call count was not found." << operand.GetErrorMessage(actual) << "\nWas actually called " << actual << " times"; + return output.str(); + } + + std::function m_callbackHandler; + detail::MockArgumentHandler m_argumentHandler; + detail::MockReturnHandler m_returnHandler; + }; +} + + +#endif // UNITTEST11_MOCK_HPP diff --git a/UnitTest11/Run.hpp b/UnitTest11/Run.hpp new file mode 100644 index 0000000..065dc14 --- /dev/null +++ b/UnitTest11/Run.hpp @@ -0,0 +1,40 @@ +#ifndef UT11_RUN_HPP_INCLUDED +#define UT11_RUN_HPP_INCLUDED + +#include "out/Output.hpp" +#include +#include + +namespace ut11 +{ + /*! \brief Runs all test fixtures with the default std::cout output + * + * \return The number of fixtures that failed + */ + int Run(); + + /*! \brief Runs test fixtures with the default std::cout output, using the passes arguments to deduce the fixtures to run + * + * \return The number of fixtures that failed + */ + int Run(const int argumentCount, const char* const* arguments); + + /*! \brief Runs all test fixtures using the passed output to report tests being ran, success and failures. + * + * \return The number of fixtures that failed + */ + int Run(out::Output&); + + /*! \brief Runs test fixtures with the given output, using the passes arguments to deduce the fixtures to run + * + * \return The number of fixtures that failed + */ + int Run(out::Output&, const int argumentCount, const char* const* arguments); + + /*! \brief Runs all test fixtures that have a category that matches one of the given names + * + * \return The number of fixtures that failed + */ + int RunCategories(out::Output&, std::vector fixtures); +} +#endif // !UT11_RUN_HPP_INCLUDED diff --git a/UnitTest11/TestFixture.hpp b/UnitTest11/TestFixture.hpp new file mode 100644 index 0000000..b3a01ad --- /dev/null +++ b/UnitTest11/TestFixture.hpp @@ -0,0 +1,43 @@ +#ifndef UNITTEST11_TESTFIXTURE_HPP +#define UNITTEST11_TESTFIXTURE_HPP + +#include "detail/TestFixtureAbstract.hpp" +#include "detail/TestStageBuilderImpl.hpp" + +#include + +namespace ut11 +{ + /*! \brief The test fixture class all tests must inherit from */ + class TestFixture : public detail::TestFixtureAbstract + { + public: + TestFixture(); + explicit TestFixture(std::string name); + TestFixture(std::string name, std::unique_ptr builder); + virtual ~TestFixture(); + + virtual void AddCategory(ut11::Category); + virtual std::set GetCategories() const; + + virtual void Given(std::string description, std::function logic); + virtual void When(std::string description, std::function logic); + virtual void Then(std::string description, std::function logic); + virtual void Finally(std::string description, std::function logic); + + inline void SetName(std::string name) { m_name = name; } + virtual std::string GetName() const { return m_name; } + + virtual detail::TestFixtureResults Run(out::Output& output); + + /*! \brief The function to inherit from that is called to build the test Given/When/Then/Finally tree */ + virtual void Run(); + + private: + std::string m_name; + std::unique_ptr m_StageBuilder; + std::set m_categories; + }; +} + +#endif // UNITTEST11_TESTFIXTURE_HPP diff --git a/UnitTest11/Will/Pass.hpp b/UnitTest11/Will/Pass.hpp new file mode 100644 index 0000000..7a1d6ef --- /dev/null +++ b/UnitTest11/Will/Pass.hpp @@ -0,0 +1,52 @@ +#ifndef UNITTEST11_WILL_PASS_HPP +#define UNITTEST11_WILL_PASS_HPP + +#include "../detail/BaseOperand.hpp" +#include + +namespace ut11 +{ + namespace Operands + { + template + class WillPass : public detail::BaseOperand> + { + private: + CALLBACK m_predicate; + + public: + explicit WillPass(CALLBACK predicate) + : m_predicate(predicate) + { + } + + template inline bool operator()(const T& value) const + { + return m_predicate(value); + } + + template + inline std::string GetErrorMessage(const T&) const { return "Expected predicate to return true"; } + }; + } + + namespace Will + { + /*! \brief Operand will return true if the passed predicate returns true when called with the Actual value, otherwise returns false */ + template Operands::WillPass Pass(CALLBACK predicate) + { + return Operands::WillPass(predicate); + } + + namespace Not + { + /*! \brief Operand will return true if the passed predicate returns false when called with the Actual value, otherwise returns false */ + template detail::NotOperand< Operands::WillPass > Pass(CALLBACK predicate) + { + return !Operands::WillPass(predicate); + } + } + } +} + +#endif // UNITTEST11_WILL_PASS_HPP diff --git a/UnitTest11/Will/Throw.hpp b/UnitTest11/Will/Throw.hpp new file mode 100644 index 0000000..9628c05 --- /dev/null +++ b/UnitTest11/Will/Throw.hpp @@ -0,0 +1,100 @@ +#ifndef UNITTEST11_WILL_THROW_HPP +#define UNITTEST11_WILL_THROW_HPP + +#include "../detail/BaseOperand.hpp" + +#include +#include +#include +#include + +namespace ut11 +{ + namespace Operands + { + template struct WillThrow : public detail::BaseOperand < WillThrow > + { + inline explicit WillThrow(std::string exceptionName = typeid(Exception).name()) + : m_exceptionName(exceptionName), + m_errorMessage("Expected " + exceptionName + " to be thrown, but no exception was thrown") + { + } + + inline std::string GetErrorMessage(std::function) const { return m_errorMessage; } + + inline bool operator()(std::function function) const + { + try + { + function(); + } + catch(const Exception&) + { + return true; + } + catch(const std::exception& ex) + { + std::stringstream stream; + stream << "Expected " << m_exceptionName << " to be thrown, but std::exception was thrown instead (what: " << ex.what() << ")"; + m_errorMessage = stream.str(); + } + catch(...) + { + std::stringstream stream; + stream << "Expected " << m_exceptionName << " to be thrown, but an unknown exception was thrown instead"; + m_errorMessage = stream.str(); + } + return false; + } + + private: + std::string m_exceptionName; + mutable std::string m_errorMessage; + }; + + template<> struct WillThrow : public detail::BaseOperand> + { + inline explicit WillThrow() + : m_exceptionName("std::exception"), + m_errorMessage("Expected std::exception to be thrown, but no exception was thrown") + { + } + + inline std::string GetErrorMessage(std::function) const { return m_errorMessage; } + + inline bool operator()(std::function function) const + { + try + { + function(); + } + catch(const std::exception&) + { + return true; + } + catch(...) + { + std::stringstream stream; + stream << "Expected " << m_exceptionName << " to be thrown, but an unknown exception was thrown instead"; + m_errorMessage = stream.str(); + } + return false; + } + + private: + std::string m_exceptionName; + mutable std::string m_errorMessage; + }; + } + + namespace Will + { + /*! \brief Operand will return true if the passed predicate throws an exception of type Exception (or a child of type Exception), otherwise returns false */ + template inline Operands::WillThrow Throw() + { + return Operands::WillThrow(); + } + } +} + +#endif // UNITTEST11_WILL_THROW_HPP diff --git a/UnitTest11/detail/AndOperand.hpp b/UnitTest11/detail/AndOperand.hpp new file mode 100644 index 0000000..33eef1b --- /dev/null +++ b/UnitTest11/detail/AndOperand.hpp @@ -0,0 +1,41 @@ +#ifndef UT11_DETAIL_ANDOPERAND_HPP_INCLUDED +#define UT11_DETAIL_ANDOPERAND_HPP_INCLUDED + +#include + +namespace ut11 +{ + namespace detail + { + template struct BaseOperand; + + template struct AndOperand : public BaseOperand> + { + Op1 operand1; + Op2 operand2; + + AndOperand(const Op1& op1, const Op2& op2) + : operand1(op1), + operand2(op2) + { + } + + template bool operator()(const T& actual) const + { + return operand1(actual) && operand2(actual); + } + + template inline std::string GetErrorMessage(const T& actual) const + { + std::string errorMessage("Expected And failed: \n"); + if (!operand1(actual)) + errorMessage += operand1.GetErrorMessage(actual); + if (!operand2(actual)) + errorMessage += operand2.GetErrorMessage(actual); + return errorMessage; + } + }; + } +} + +#endif // UT11_DETAIL_ANDOPERAND_HPP_INCLUDED diff --git a/UnitTest11/detail/BaseOperand.hpp b/UnitTest11/detail/BaseOperand.hpp new file mode 100644 index 0000000..eefe494 --- /dev/null +++ b/UnitTest11/detail/BaseOperand.hpp @@ -0,0 +1,45 @@ +#ifndef UNITTEST11_DETAIL_BASEOPERAND_HPP +#define UNITTEST11_DETAIL_BASEOPERAND_HPP + +#include "AndOperand.hpp" +#include "OrOperand.hpp" +#include "NotOperand.hpp" + +#include +#include + +namespace ut11 +{ + namespace detail + { + template struct BaseOperand + { + typedef T self; + + /*! \brief Returns an operand that composes both operands and will pass if both internal operands pass */ + template AndOperand operator&&(const U& o2) const + { + return AndOperand(*static_cast(this), o2); + } + + /*! \brief Returns an operand that composes both operands and will pass if at least one of the internal operands pass */ + template OrOperand operator||(const U& o2) const + { + return OrOperand(*static_cast(this), o2); + } + + /*! \brief Returns an operand that takes the operand and will pass if the operand fails */ + NotOperand operator!() const + { + return NotOperand(*static_cast(this)); + } + }; + + template struct IsOperand + { + enum : bool { value = std::is_base_of< BaseOperand, Operand >::value }; + }; + } +} + +#endif // UNITTEST11_DETAIL_BASEOPERAND_HPP diff --git a/UnitTest11/detail/DeclareFixture.hpp b/UnitTest11/detail/DeclareFixture.hpp new file mode 100644 index 0000000..2f064e1 --- /dev/null +++ b/UnitTest11/detail/DeclareFixture.hpp @@ -0,0 +1,72 @@ +#ifndef UT11_DETAIL_DECLAREFIXTURE_HPP_INCLUDED +#define UT11_DETAIL_DECLAREFIXTURE_HPP_INCLUDED + +#include "TestFixtureAbstract.hpp" +#include "../Category.hpp" +#include "../utility/ToString.hpp" +#include + +namespace ut11 +{ + namespace detail + { + extern void PushFixture(std::shared_ptr); + + template + struct DeclareFixtureObj + { + private: + std::string m_name; + + public: + explicit DeclareFixtureObj(std::string name) + : m_name(name) + { + } + + template int operator()(ARGS && ... args) + { + std::unique_ptr fixture(new T(std::forward(args)...)); + fixture->SetName(m_name + "(" + GetString(args...)); + PushFixture(std::move(fixture)); + + return 0; + } + + template int operator()(Category category, ARGS && ... args) + { + std::unique_ptr fixture(new T(std::forward(args)...)); + fixture->SetName(m_name + "(" + GetString(args...)); + fixture->AddCategory(category); + + PushFixture(std::move(fixture)); + return 0; + } + + template int operator()(std::initializer_list categories, ARGS && ... args) + { + std::unique_ptr fixture(new T(std::forward(args)...)); + fixture->SetName(m_name + "(" + GetString(args...)); + for (auto category : categories) + fixture->AddCategory(category); + + PushFixture(std::move(fixture)); + return 0; + } + + private: + static std::string GetString() + { + return ")"; + } + + template + static std::string GetString(const V& value, const ARGS&... args) + { + return utility::ToString(value) + ", " + GetString(args...); + } + }; + } +} + +#endif // UT11_DETAIL_DECLAREFIXTURE_HPP_INCLUDED diff --git a/UnitTest11/detail/MockArgumentHandler.hpp b/UnitTest11/detail/MockArgumentHandler.hpp new file mode 100644 index 0000000..b8678fa --- /dev/null +++ b/UnitTest11/detail/MockArgumentHandler.hpp @@ -0,0 +1,71 @@ +#ifndef UNITTEST11_DETAIL_MOCKARGUMENTHANDLER_HPP +#define UNITTEST11_DETAIL_MOCKARGUMENTHANDLER_HPP + +#include "BaseOperand.hpp" +#include "../utility/AreEqual.hpp" + +#include +#include +#include + +namespace ut11 +{ + namespace detail + { + template + static inline typename std::enable_if< IsOperand::value, bool >::type CompareWithOperandOrEquality(const T& arg, const U& expectation) + { + return expectation(arg); + } + + template + static inline typename std::enable_if< !(IsOperand::value), bool >::type CompareWithOperandOrEquality(const T& arg, const U& expectation) + { + return utility::AreEqual(expectation, arg); + } + + template class MockArgumentHandler + { + public: + void AddCall(ARGS... args) + { + m_arguments.push_back( std::make_tuple( std::forward(args)... ) ); + } + + template std::size_t CountCalls(Expectations... expectations) const + { + static_assert(sizeof...(Expectations) == sizeof...(ARGS), "Expectations and Arguments must match"); + + std::size_t counter = 0; + + std::tuple expectationTuple(expectations...); + for(const std::tuple& actual : m_arguments) + { + if ( MatchTuples<0, sizeof...(ARGS)>(actual, expectationTuple) ) + ++counter; + } + return counter; + } + + std::size_t TotalCount() const { return m_arguments.size(); } + + protected: + template + typename std::enable_if< (I < Limit), bool >::type MatchTuples(const Arguments& arguments, const Expectations& expectations) const + { + return CompareWithOperandOrEquality(std::get(arguments), std::get(expectations)) && MatchTuples(arguments, expectations); + } + + template + typename std::enable_if< (I >= Limit), bool >::type MatchTuples(const Arguments&, const Expectations&) const + { + return true; + } + + private: + std::list< std::tuple > m_arguments; + }; + } +} + +#endif // UNITTEST11_DETAIL_MOCKARGUMENTHANDLER_HPP diff --git a/UnitTest11/detail/MockReturnHandler.hpp b/UnitTest11/detail/MockReturnHandler.hpp new file mode 100644 index 0000000..9d6994a --- /dev/null +++ b/UnitTest11/detail/MockReturnHandler.hpp @@ -0,0 +1,61 @@ +#ifndef UNITTEST11_DETAIL_MOCKRETURNER_HPP +#define UNITTEST11_DETAIL_MOCKRETURNER_HPP + +#include "../utility/DefaultValue.hpp" +#include + +namespace ut11 +{ + namespace detail + { + template class MockReturnHandler + { + public: + MockReturnHandler() + : m_isReturnCallbackMode(false), + m_returnCallback(), + m_returnValue(utility::DefaultValue()()) + { + } + + void SetReturn(std::function callback) + { + m_isReturnCallbackMode = true; + m_returnCallback = callback; + } + + void SetReturn(T value) + { + m_isReturnCallbackMode = false; + m_returnValue = value; + } + + T operator()(const ARGS&... args) + { + return m_isReturnCallbackMode + ? m_returnCallback(args...) + : m_returnValue; + } + + private: + bool m_isReturnCallbackMode; + std::function m_returnCallback; + T m_returnValue; + }; + + template class MockReturnHandler + { + public: + MockReturnHandler() : m_returnCallback() { } + + void SetReturn(std::function callback) { m_returnCallback = callback; } + void SetReturn() { m_returnCallback = std::function(); } + void operator()(const ARGS&... args) { if ( m_returnCallback ) m_returnCallback(args...); } + + private: + std::function m_returnCallback; + }; + } +} + +#endif // UNITTEST11_DETAIL_MOCKRETURNER_HPP diff --git a/UnitTest11/detail/MockTimesVerify.hpp b/UnitTest11/detail/MockTimesVerify.hpp new file mode 100644 index 0000000..f4a98bf --- /dev/null +++ b/UnitTest11/detail/MockTimesVerify.hpp @@ -0,0 +1,35 @@ +#ifndef UT11_DETAIL_MOCKTIMESVERIFY_HPP_INCLUDED +#define UT11_DETAIL_MOCKTIMESVERIFY_HPP_INCLUDED + +#include + +namespace ut11 +{ + namespace detail + { + template struct MockTimesVerifyer + { + private: + T& mockObj; + const Op& times; + std::size_t line; + std::string file; + + public: + MockTimesVerifyer(T& mock, const Op& times, std::size_t line, std::string file) + : mockObj(mock), + times(times), + line(line), + file(file) + { + } + + template void operator()(const ARGS&... args) + { + mockObj.VerifyTimes(line, file, times, args...); + } + }; + } +} + +#endif // UT11_DETAIL_MOCKTIMESVERIFY_HPP_INCLUDED diff --git a/UnitTest11/detail/MockVerify.hpp b/UnitTest11/detail/MockVerify.hpp new file mode 100644 index 0000000..3ad0e43 --- /dev/null +++ b/UnitTest11/detail/MockVerify.hpp @@ -0,0 +1,33 @@ +#ifndef UT11_DETAIL_MOCKVERIFY_HPP_INCLUDED +#define UT11_DETAIL_MOCKVERIFY_HPP_INCLUDED + +#include + +namespace ut11 +{ + namespace detail + { + template struct MockVerifyer + { + private: + T& mockObj; + std::size_t line; + std::string file; + + public: + MockVerifyer(T& mock, std::size_t line, std::string file) + : mockObj(mock), + line(line), + file(file) + { + } + + template void operator()(const ARGS&... args) + { + mockObj.Verify(line, file, args...); + } + }; + } +} + +#endif // UT11_DETAIL_MOCKVERIFY_HPP_INCLUDED diff --git a/UnitTest11/detail/NotOperand.hpp b/UnitTest11/detail/NotOperand.hpp new file mode 100644 index 0000000..319b67e --- /dev/null +++ b/UnitTest11/detail/NotOperand.hpp @@ -0,0 +1,36 @@ +#ifndef UT11_DETAIL_NOTOPERAND_HPP_INCLUDED +#define UT11_DETAIL_NOTOPERAND_HPP_INCLUDED + +#include + +namespace ut11 +{ + namespace detail + { + template struct BaseOperand; + + template struct NotOperand : public BaseOperand> + { + Op1 operand; + + explicit NotOperand(const Op1& op1) + : operand(op1) + { + } + + template bool operator()(const T& actual) const + { + return !operand(actual); + } + + template inline std::string GetErrorMessage(const T& actual) const + { + std::string errorMessage("Expected Not failed: \n"); + errorMessage += operand.GetErrorMessage(actual); + return errorMessage; + } + }; + } +} + +#endif // UT11_DETAIL_NOTOPERAND_HPP_INCLUDED diff --git a/UnitTest11/detail/OrOperand.hpp b/UnitTest11/detail/OrOperand.hpp new file mode 100644 index 0000000..ea6966d --- /dev/null +++ b/UnitTest11/detail/OrOperand.hpp @@ -0,0 +1,41 @@ +#ifndef UT11_DETAIL_OROPERAND_HPP_INCLUDED +#define UT11_DETAIL_OROPERAND_HPP_INCLUDED + +#include + +namespace ut11 +{ + namespace detail + { + template struct BaseOperand; + + template struct OrOperand : public BaseOperand> + { + Op1 operand1; + Op2 operand2; + + OrOperand(const Op1& op1, const Op2& op2) + : operand1(op1), + operand2(op2) + { + } + + template bool operator()(const T& actual) const + { + return operand1(actual) || operand2(actual); + } + + template inline std::string GetErrorMessage(const T& actual) const + { + std::string errorMessage("Expected Or failed: \n"); + if (!operand1(actual)) + errorMessage += operand1.GetErrorMessage(actual); + if (!operand2(actual)) + errorMessage += operand2.GetErrorMessage(actual); + return errorMessage; + } + }; + } +} + +#endif // UT11_DETAIL_OROPERAND_HPP_INCLUDED diff --git a/UnitTest11/detail/TestFailedException.hpp b/UnitTest11/detail/TestFailedException.hpp new file mode 100644 index 0000000..7d6d298 --- /dev/null +++ b/UnitTest11/detail/TestFailedException.hpp @@ -0,0 +1,40 @@ +#ifndef UNITTEST11_DETAIL_TESTFAILEDEXCEPTION_HPP +#define UNITTEST11_DETAIL_TESTFAILEDEXCEPTION_HPP + +#include + +namespace ut11 +{ + namespace detail + { + class TestFailedException + { + public: + TestFailedException() + : m_line(0), + m_file(), + m_message() + { + + } + + TestFailedException(std::size_t line, std::string file, std::string message) + : m_line(line), + m_file(file), + m_message(message) + { + } + + inline std::size_t GetLine() const { return m_line; } + inline std::string GetFile() const { return m_file; } + inline std::string GetMessage() const { return m_message; } + + private: + std::size_t m_line; + std::string m_file; + std::string m_message; + }; + } +} + +#endif // UNITTEST11_DETAIL_TESTFAILEDEXCEPTION_HPP diff --git a/UnitTest11/detail/TestFixtureAbstract.hpp b/UnitTest11/detail/TestFixtureAbstract.hpp new file mode 100644 index 0000000..8bf42e9 --- /dev/null +++ b/UnitTest11/detail/TestFixtureAbstract.hpp @@ -0,0 +1,36 @@ +#ifndef UT11_DETAIL_TESTFIXTUREABSTRACT_HPP_INCLUDED +#define UT11_DETAIL_TESTFIXTUREABSTRACT_HPP_INCLUDED + +#include "TestFixtureResults.hpp" +#include "../Category.hpp" +#include "../out/Output.hpp" + +#include +#include +#include + +namespace ut11 +{ + namespace detail + { + class TestFixtureAbstract + { + public: + virtual ~TestFixtureAbstract(); + + virtual void AddCategory(ut11::Category) = 0; + virtual std::set GetCategories() const = 0; + + virtual void Given(std::string, std::function) = 0; + virtual void When(std::string, std::function) = 0; + virtual void Then(std::string, std::function) = 0; + virtual void Finally(std::string, std::function) = 0; + + virtual std::string GetName() const = 0; + + virtual TestFixtureResults Run(out::Output&) = 0; + }; + } +} + +#endif // UT11_DETAIL_TESTFIXTUREABSTRACT_HPP_INCLUDED diff --git a/UnitTest11/detail/TestFixtureResults.hpp b/UnitTest11/detail/TestFixtureResults.hpp new file mode 100644 index 0000000..5254b96 --- /dev/null +++ b/UnitTest11/detail/TestFixtureResults.hpp @@ -0,0 +1,20 @@ +#ifndef UT11_DETAIL_TESTFIXTURERESULTS_HPP_INCLUDED +#define UT11_DETAIL_TESTFIXTURERESULTS_HPP_INCLUDED + +#include + +namespace ut11 +{ + namespace detail + { + struct TestFixtureResults + { + TestFixtureResults() : ran(0), succeeded(0) { } + + std::size_t ran; + std::size_t succeeded; + }; + } +} + +#endif // UT11_DETAIL_TESTFIXTURERESULTS_HPP_INCLUDED \ No newline at end of file diff --git a/UnitTest11/detail/TestFixtureRunner.hpp b/UnitTest11/detail/TestFixtureRunner.hpp new file mode 100644 index 0000000..e10ffd1 --- /dev/null +++ b/UnitTest11/detail/TestFixtureRunner.hpp @@ -0,0 +1,34 @@ +#ifndef UNITTEST11_DETAIL_TESTFIXTURERUNNER_HPP +#define UNITTEST11_DETAIL_TESTFIXTURERUNNER_HPP + +#include "../out/Output.hpp" +#include "../TestFixture.hpp" +#include +#include + +namespace ut11 +{ + namespace detail + { + class TestFixtureRunner + { + public: + void AddFixture(std::shared_ptr fixture); + + int Run(out::Output& output); + + int RunCategories(out::Output& output, std::vector); + + private: + std::vector> GetFixtures() const; + std::vector> GetFixturesThatMatchCategories(const std::vector& desiredCategories) const; + + static bool DoesFixtureMatchCategories(std::shared_ptr fixture, const std::vector& desiredCategories); + static TestFixtureResults RunTestFixtures(std::vector < std::shared_ptr < ut11::detail::TestFixtureAbstract >> fixtures, ut11::out::Output& output); + + std::map< std::string, std::shared_ptr > m_fixtures; + }; + } +} + +#endif // UNITTEST11_TESTFIXTURERUNNER_HPP diff --git a/UnitTest11/detail/TestStage.hpp b/UnitTest11/detail/TestStage.hpp new file mode 100644 index 0000000..3f04d90 --- /dev/null +++ b/UnitTest11/detail/TestStage.hpp @@ -0,0 +1,20 @@ +#ifndef UNITTEST11_DETAIL_TESTSTAGE_HPP +#define UNITTEST11_DETAIL_TESTSTAGE_HPP + +#include "../out/Output.hpp" + +namespace ut11 +{ + namespace detail + { + class TestStage + { + public: + virtual ~TestStage(); + + virtual bool Run(out::Output& output) = 0; + }; + } +} + +#endif // UNITTEST11_DETAIL_TESTSTAGE_HPP diff --git a/UnitTest11/detail/TestStageBuilder.hpp b/UnitTest11/detail/TestStageBuilder.hpp new file mode 100644 index 0000000..4cc3da9 --- /dev/null +++ b/UnitTest11/detail/TestStageBuilder.hpp @@ -0,0 +1,29 @@ +#ifndef UNITTEST11_DETAIL_TESTSTAGEBUILDER_HPP +#define UNITTEST11_DETAIL_TESTSTAGEBUILDER_HPP + +#include "TestStep.hpp" +#include "TestStage.hpp" + +#include +#include + +namespace ut11 +{ + namespace detail + { + class TestStageBuilder + { + public: + virtual ~TestStageBuilder(); + + virtual void PushGiven(TestStep given) = 0; + virtual void PushWhen(TestStep when) = 0; + virtual void PushThen(TestStep then) = 0; + virtual void PushFinally(TestStep finally) = 0; + virtual std::vector< std::shared_ptr > Build() = 0; + }; + } +} + + +#endif // UNITTEST11_DETAIL_TESTSTAGEBUILDER_HPP diff --git a/UnitTest11/detail/TestStageBuilderImpl.hpp b/UnitTest11/detail/TestStageBuilderImpl.hpp new file mode 100644 index 0000000..0f23f12 --- /dev/null +++ b/UnitTest11/detail/TestStageBuilderImpl.hpp @@ -0,0 +1,44 @@ +#ifndef UNITTEST11_DETAIL_TESTSTAGEBUILDERIMPL_HPP +#define UNITTEST11_DETAIL_TESTSTAGEBUILDERIMPL_HPP + +#include "TestStageImpl.hpp" +#include "TestStageBuilder.hpp" + +#include +#include + +namespace ut11 +{ + namespace detail + { + class TestStageBuilderImpl : public TestStageBuilder + { + private: + enum class TestStepType + { + Given, + When, + Then, + Finally + }; + + public: + virtual ~TestStageBuilderImpl(); + + virtual void PushGiven(TestStep given); + virtual void PushWhen(TestStep when); + virtual void PushThen(TestStep then); + virtual void PushFinally(TestStep finally); + + virtual std::vector< std::shared_ptr > Build(); + + private: + void PopulateStagesWithFinally(std::vector& finallylessStages, TestStep finally); + void MoveStagesOntoFinishedStages(std::vector&, std::vector&); + + std::vector> m_steps; + }; + } +} + +#endif // UNITTEST11_DETAIL_TESTSTAGEBUILDERIMPL_HPP diff --git a/UnitTest11/detail/TestStageImpl.hpp b/UnitTest11/detail/TestStageImpl.hpp new file mode 100644 index 0000000..1582404 --- /dev/null +++ b/UnitTest11/detail/TestStageImpl.hpp @@ -0,0 +1,30 @@ +#ifndef UNITTEST11_DETAIL_TESTSTAGEIMPL_HPP +#define UNITTEST11_DETAIL_TESTSTAGEIMPL_HPP + +#include "TestStage.hpp" +#include "TestStep.hpp" + +namespace ut11 +{ + namespace detail + { + class TestStageImpl : public TestStage + { + public: + TestStep m_given, m_when, m_then, m_finally; + + TestStageImpl(); + TestStageImpl(TestStep given, TestStep when, TestStep then, TestStep finally); + virtual ~TestStageImpl(); + + virtual bool Run(out::Output& output); + + virtual void Given(out::Output& output); + virtual void When(out::Output& output); + virtual void Then(out::Output& output); + virtual void Finally(out::Output& output); + }; + } +} + +#endif // UNITTEST11_DETAIL_TESTSTAGEIMPL_HPP diff --git a/UnitTest11/detail/TestStep.hpp b/UnitTest11/detail/TestStep.hpp new file mode 100644 index 0000000..0355963 --- /dev/null +++ b/UnitTest11/detail/TestStep.hpp @@ -0,0 +1,22 @@ +#ifndef UNITTEST11_DETAIL_TESTSTEP_HPP +#define UNITTEST11_DETAIL_TESTSTEP_HPP + +#include +#include + +namespace ut11 +{ + namespace detail + { + struct TestStep + { + TestStep() : description(), logic() { } + TestStep(std::string d, std::function l) : description(d), logic(l) { } + + std::string description; + std::function logic; + }; + } +} + +#endif // UNITTEST11_DETAIL_TESTSTEP_HPP diff --git a/UnitTest11/out/Output.hpp b/UnitTest11/out/Output.hpp new file mode 100644 index 0000000..43b19fc --- /dev/null +++ b/UnitTest11/out/Output.hpp @@ -0,0 +1,45 @@ +#ifndef UNITTEST11_OUTPUT_HPP +#define UNITTEST11_OUTPUT_HPP + +#include +#include + +namespace ut11 +{ + namespace out + { + /*! \brief An Output used to log out successful and failed Tests and Test Fixtures */ + class Output + { + public: + virtual ~Output(); + + virtual void Begin() = 0; + virtual void Finish(std::size_t ran, std::size_t succeeded) = 0; + + virtual void BeginFixture(std::string) = 0; + virtual void EndFixture(std::string) = 0; + + virtual void BeginTest() = 0; + virtual void EndTest() = 0; + + virtual void BeginGiven(std::string) = 0; + virtual void EndGiven(std::string) = 0; + + virtual void BeginWhen(std::string) = 0; + virtual void EndWhen(std::string) = 0; + + virtual void BeginThen(std::string) = 0; + virtual void EndThen(std::string) = 0; + + virtual void BeginFinally(std::string) = 0; + virtual void EndFinally(std::string) = 0; + + virtual void OnError(std::size_t line, std::string file, std::string message) = 0; + virtual void OnError(const std::exception& exception) = 0; + virtual void OnUnknownError() = 0; + }; + } +} + +#endif // UNITTEST11_OUTPUT_HPP diff --git a/UnitTest11/out/StdOutput.hpp b/UnitTest11/out/StdOutput.hpp new file mode 100644 index 0000000..2123563 --- /dev/null +++ b/UnitTest11/out/StdOutput.hpp @@ -0,0 +1,50 @@ +#ifndef UNITTEST11_STDOUTPUT_HPP +#define UNITTEST11_STDOUTPUT_HPP + +#include "Output.hpp" +#include +#include + +namespace ut11 +{ + namespace out + { + class StdOutput : public Output + { + public: + StdOutput(); + StdOutput(std::ostream&); + virtual ~StdOutput(); + + virtual void Begin(); + virtual void Finish(std::size_t ran, std::size_t succeeded); + + virtual void BeginFixture(std::string name); + virtual void BeginTest(); + virtual void BeginGiven(std::string given); + virtual void BeginWhen(std::string when); + virtual void BeginThen(std::string then); + virtual void BeginFinally(std::string finally); + + virtual void EndFixture(std::string); + virtual void EndTest(); + virtual void EndGiven(std::string); + virtual void EndWhen(std::string); + virtual void EndThen(std::string); + virtual void EndFinally(std::string); + + virtual void OnError(std::size_t line, std::string file, std::string message); + virtual void OnError(const std::exception& exception); + + virtual void OnUnknownError(); + + private: + std::ostream& m_out; + std::string m_given, m_when, m_finally; + std::chrono::system_clock::duration m_testRunTime; + std::chrono::system_clock::time_point m_testStartTime; + }; + } +} + +#endif // UNITTEST11_STDOUTPUT_HPP diff --git a/UnitTest11/utility/AreEqual.hpp b/UnitTest11/utility/AreEqual.hpp new file mode 100644 index 0000000..391fa08 --- /dev/null +++ b/UnitTest11/utility/AreEqual.hpp @@ -0,0 +1,62 @@ +#ifndef UNITTEST11_UTILITY_AREEQUAL_HPP +#define UNITTEST11_UTILITY_AREEQUAL_HPP + +#include "Meta/IsIterableContainer.hpp" + +namespace ut11 +{ + namespace utility + { + template inline bool AreEqual(const A& a, const B& b); + + /*! \brief Can be partially specialised to allow for comparing two types without providing an equality operator + * + * \tparam A The left operand of the comparison + * \tparam B The right operand of the comparison + * \tparam IsAIterable True if A is determined by metaprogramming to be an iterable type + * \tparam IsBIterable True if B is determined by metaprogramming to be an iterable type + */ + template::value, + bool IsBIterable = Meta::IsIterableContainer::value > + struct Comparison + { + inline bool operator()(const A& a, const B& b) const + { + return a == b; + } + }; + + template + struct Comparison + { + inline bool operator()(const A& a, const B& b) const + { + auto i = a.begin(); + auto j = b.begin(); + + for(; i != a.end() && j != b.end(); ++i, ++j) + { + if (!AreEqual(*i, *j)) + return false; + } + return i == a.end() && j == b.end(); + } + }; + + template<> struct Comparison + { + inline bool operator()(const std::string& a, const std::string& b) const + { + return a == b; + } + }; + + template inline bool AreEqual(const A& a, const B& b) + { + return Comparison()(a,b); + } + } +} + +#endif // AREEQUAL_HPP diff --git a/UnitTest11/utility/DefaultValue.hpp b/UnitTest11/utility/DefaultValue.hpp new file mode 100644 index 0000000..54f25f2 --- /dev/null +++ b/UnitTest11/utility/DefaultValue.hpp @@ -0,0 +1,13 @@ +#ifndef UNITTEST11_UTILITY_DEFAULTVALUE_HPP +#define UNITTEST11_UTILITY_DEFAULTVALUE_HPP + +namespace ut11 +{ + namespace utility + { + /*! \brief Can be partially specialised to specify the default value of a custom type to be used by the Mock functor for what to return by default */ + template struct DefaultValue { inline T operator()() const { return T(); } }; + } +} + +#endif // UNITTEST11_UTILITY_DEFAULTVALUE_HPP diff --git a/UnitTest11/utility/Meta/IfElseTypes.hpp b/UnitTest11/utility/Meta/IfElseTypes.hpp new file mode 100644 index 0000000..89fcb5c --- /dev/null +++ b/UnitTest11/utility/Meta/IfElseTypes.hpp @@ -0,0 +1,23 @@ +/* + * IfElseTypes.hpp + * + * Created on: 23 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_UTILITY_META_IFELSETYPES_HPP_INCLUDED +#define UT11_UTILITY_META_IFELSETYPES_HPP_INCLUDED + +namespace ut11 +{ + namespace utility + { + namespace Meta + { + template struct IfElseTypes { typedef A type; }; + template struct IfElseTypes { typedef B type; }; + } + } +} + +#endif /* UT11_UTILITY_IFELSETYPES_HPP_INCLUDED */ diff --git a/UnitTest11/utility/Meta/IsIterableContainer.hpp b/UnitTest11/utility/Meta/IsIterableContainer.hpp new file mode 100644 index 0000000..29e5c28 --- /dev/null +++ b/UnitTest11/utility/Meta/IsIterableContainer.hpp @@ -0,0 +1,39 @@ +#ifndef UNITTEST11_UTILITY_META_ISITERABLECONTAINER_HPP +#define UNITTEST11_UTILITY_META_ISITERABLECONTAINER_HPP + +#include +#include + +namespace ut11 +{ + namespace utility + { + namespace Meta + { + template + struct IsIterableContainer + { + private: + typedef typename std::remove_const::type test_type; + + template + static std::uint8_t test(U* pointer, + U const* constPointer = nullptr, + decltype(pointer->begin())* = nullptr, + decltype(pointer->end())* = nullptr, + decltype(pointer->begin())* = nullptr, + decltype(constPointer->end())* = nullptr, + typename U::iterator* = nullptr, + typename U::const_iterator* = nullptr, + typename U::value_type* = nullptr); + + template static std::uint32_t test(...); + + public: + enum : bool { value = sizeof(test(nullptr)) == sizeof(std::uint8_t) }; + }; + } + } +} + +#endif // UNITTEST11_UTILITY_META_ISITERABLECONTAINER_HPP diff --git a/UnitTest11/utility/Meta/IsIterableOfType.hpp b/UnitTest11/utility/Meta/IsIterableOfType.hpp new file mode 100644 index 0000000..bfa32b3 --- /dev/null +++ b/UnitTest11/utility/Meta/IsIterableOfType.hpp @@ -0,0 +1,37 @@ +/* + * IsIterableOfType.hpp + * + * Created on: 23 Apr 2013 + * Author: Jason + */ + +#ifndef UT11_UTILITY_META_ISITERABLEOFTYPE_HPP_INCLUDED +#define UT11_UTILITY_META_ISITERABLEOFTYPE_HPP_INCLUDED + +#include "IsIterableContainer.hpp" +#include +#include + +namespace ut11 +{ + namespace utility + { + namespace Meta + { + template::value > struct IsIterableOfType + { + typedef typename std::iterator_traits< decltype(std::declval().begin()) >::value_type Iterator; + + enum { value = std::is_same::value || std::is_base_of::value }; + }; + + template struct IsIterableOfType + { + enum { value = false }; + }; + } + } +} + + +#endif /* UT11_UTILITY_META_ISITERABLEOFTYPE_HPP_INCLUDED */ diff --git a/UnitTest11/utility/ToString.hpp b/UnitTest11/utility/ToString.hpp new file mode 100644 index 0000000..37d5bd4 --- /dev/null +++ b/UnitTest11/utility/ToString.hpp @@ -0,0 +1,130 @@ +#ifndef UNITTEST11_UTILITY_TOSTRING_HPP +#define UNITTEST11_UTILITY_TOSTRING_HPP + +#include "Meta/IsIterableContainer.hpp" +#include "Meta/IfElseTypes.hpp" + +#include +#include +#include + +namespace ut11 +{ + namespace utility + { + template inline std::string ToString(const V& value); + + namespace detail + { + template() << std::declval())> + std::true_type IsStreamWritable(const T&) + { + return std::true_type(); + } + + template + std::false_type IsStreamWritable(const T&, Ignored const&..., ...) + { + return std::false_type(); + } + + template struct ParseNonIterableToString + { + inline std::string operator()(const V& value) const + { + return ToString(value, IsStreamWritable(value)); + } + + inline std::string ToString(const V& value, std::true_type) const + { + std::stringstream stream; + stream << value; + return stream.str(); + } + + inline std::string ToString(const V& value, std::false_type) const + { + std::stringstream stream; + stream << "[" << typeid(V).name() << "]"; + return stream.str(); + } + }; + + template struct ParseIterableToString + { + inline std::string operator()(const V& value) const + { + std::stringstream stream; + stream << "{ "; + for (const auto& arg : value) + stream << ToString(arg) << " "; + stream << "}"; + return stream.str(); + } + }; + } + + /*! \brief Can be partially specialised to parse non-streamables to strings without making the type streamable */ + template struct ParseToString + { + inline std::string operator()(const V& value) const + { + return typename Meta::IfElseTypes< Meta::IsIterableContainer::value, detail::ParseIterableToString, detail::ParseNonIterableToString >::type()(value); + } + }; + + template<> struct ParseToString + { + inline std::string operator()(const std::string& value) const + { + return value; + } + }; + + + template<> struct ParseToString< void* > + { + inline std::string operator()(void* value) const + { + return value ? std::string("void_pointer:") + detail::ParseNonIterableToString()(value) : "nullptr"; + } + }; + template struct ParseToString< T* > + { + inline std::string operator()(T* value) const + { + return value ? std::string("pointer:") + ParseToString()(*value) : "nullptr"; + } + }; + + template struct ParseToString< std::unique_ptr > + { + inline std::string operator()(const std::unique_ptr& value) const + { + return value ? std::string("unique_ptr:") + ParseToString()(*value) : "nullptr"; + } + }; + + template<> struct ParseToString< std::shared_ptr > + { + inline std::string operator()(const std::shared_ptr& value) const + { + return value ? std::string("shared_ptr:") + detail::ParseNonIterableToString()(value.get()) : "nullptr"; + } + }; + template struct ParseToString< std::shared_ptr > + { + inline std::string operator()(const std::shared_ptr& value) const + { + return value ? std::string("shared_ptr:") + ParseToString()(*value) : "nullptr"; + } + }; + + template inline std::string ToString(const V& value) + { + return ParseToString()(value); + } + } +} + +#endif // UNITTEST11_UTILITY_TOSTRING_HPP diff --git a/biicode.conf b/biicode.conf new file mode 100644 index 0000000..93a3b07 --- /dev/null +++ b/biicode.conf @@ -0,0 +1,19 @@ +# Biicode configuration file + +[requirements] + +[parent] + MorleyDev/unittest11: 1 +[paths] + ./ + +[dependencies] + +[mains] + !tests/main.cpp + +[hooks] + +[includes] + +[data] diff --git a/configure b/configure index b720946..c8df381 100755 --- a/configure +++ b/configure @@ -1,13 +1,13 @@ -if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then - if [ $# -gt 0 ]; then - cmake . -DCMAKE_MAKE_PROGRAM=make -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=$0 - else - cmake . -DCMAKE_MAKE_PROGRAM=make -G"MinGW Makefiles" - fi -else - if [ $# -gt 0 ]; then - cmake . -DCMAKE_BUILD_TYPE=$0 - else - cmake . - fi -fi +if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then + if [ $# -gt 0 ]; then + cmake . -DCMAKE_MAKE_PROGRAM=make -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=$0 + else + cmake . -DCMAKE_MAKE_PROGRAM=make -G"MinGW Makefiles" + fi +else + if [ $# -gt 0 ]; then + cmake . -DCMAKE_BUILD_TYPE=$0 + else + cmake . + fi +fi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 69b8887..1788a9d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,14 +1,14 @@ -include_directories(${UNITTEST11_SOURCE_DIR}/include) - -include(files.cmake) - -add_library(unittest11 ${UNITTEST11_SRC_FILES}) -set_target_properties(unittest11 PROPERTIES DEBUG_POSTFIX "-d") - -install (TARGETS unittest11 DESTINATION lib) - -foreach(HEADER ${UNITTEST11_INCLUDE_FILES}) -string(REPLACE "${UNITTEST11_SOURCE_DIR}/include" "" DIR ${HEADER}) -string(REGEX MATCH "(.*)[/\\]" DIR2 ${DIR}) -install(FILES ${HEADER} DESTINATION include/${DIR2}) -endforeach(HEADER) +include_directories(${UNITTEST11_SOURCE_DIR}) + +include(files.cmake) + +add_library(unittest11 ${UNITTEST11_SRC_FILES}) +set_target_properties(unittest11 PROPERTIES DEBUG_POSTFIX "-d") + +install (TARGETS unittest11 DESTINATION lib) + +foreach(HEADER ${UNITTEST11_INCLUDE_FILES}) + string(REPLACE "${UNITTEST11_SOURCE_DIR}/include" "" DIR ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" DIR2 ${DIR}) + install(FILES ${HEADER} DESTINATION include/${DIR2}) +endforeach(HEADER) diff --git a/src/files.cmake b/src/files.cmake index 4872f69..89544d0 100644 --- a/src/files.cmake +++ b/src/files.cmake @@ -1,76 +1,76 @@ -SET (UNITTEST11_INCLUDE_FILES ${UNITTEST11_SOURCE_DIR}/include/UnitTest11.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Category.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Core.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Macros.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Mock.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Run.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/TestFixture.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Assert/Fail.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Assert/That.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/AndOperand.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/BaseOperand.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/DeclareFixture.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/MockArgumentHandler.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/MockReturnHandler.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/MockTimesVerify.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/MockVerify.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/NotOperand.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/OrOperand.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestFailedException.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestFixtureAbstract.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestFixtureResults.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestFixtureRunner.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestStage.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestStageBuilder.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestStageBuilderImpl.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestStageImpl.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/detail/TestStep.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Any.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Between.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Empty.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/EqualTo.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/False.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/GreaterThan.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Infinity.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/LessThan.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/NaN.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Null.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/True.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Zero.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Iterable/EquivalentTo.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Iterable/Of.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Iterable/Containing/Item.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/Iterable/Containing/Subset.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/String/BeginningWith.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/String/Containing.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Is/String/EndingWith.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/out/Output.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/out/StdOutput.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/utility/AreEqual.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/utility/DefaultValue.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/utility/ToString.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/utility/Meta/IfElseTypes.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/utility/Meta/IsIterableContainer.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/utility/Meta/IsIterableOfType.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Will/Pass.hpp - ${UNITTEST11_SOURCE_DIR}/include/UnitTest11/Will/Throw.hpp) - -SET (UNITTEST11_SRC_FILES ${UNITTEST11_SOURCE_DIR}/src/Run.cpp - ${UNITTEST11_SOURCE_DIR}/src/TestFixture.cpp - ${UNITTEST11_SOURCE_DIR}/src/Assert/Fail.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/DeclareFixture.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/GetRunner.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/TestFixtureRunner.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/TestStage.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/TestStageBuilder.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/TestStageBuilderImpl.cpp - ${UNITTEST11_SOURCE_DIR}/src/detail/TestStageImpl.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/Empty.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/False.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/Infinity.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/NaN.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/Null.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/True.cpp - ${UNITTEST11_SOURCE_DIR}/src/Is/Zero.cpp - ${UNITTEST11_SOURCE_DIR}/src/out/Output.cpp - ${UNITTEST11_SOURCE_DIR}/src/out/StdOutput.cpp) +SET (UNITTEST11_INCLUDE_FILES ${UNITTEST11_SOURCE_DIR}/UnitTest11.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Category.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Core.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Macros.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Mock.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Run.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/TestFixture.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Assert/Fail.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Assert/That.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/AndOperand.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/BaseOperand.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/DeclareFixture.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/MockArgumentHandler.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/MockReturnHandler.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/MockTimesVerify.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/MockVerify.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/NotOperand.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/OrOperand.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestFailedException.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestFixtureAbstract.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestFixtureResults.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestFixtureRunner.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestStage.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestStageBuilder.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestStageBuilderImpl.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestStageImpl.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/detail/TestStep.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Any.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Between.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Empty.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/EqualTo.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/False.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/GreaterThan.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Infinity.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/LessThan.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/NaN.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Null.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/True.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Zero.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Iterable/EquivalentTo.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Iterable/Of.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Iterable/Containing/Item.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/Iterable/Containing/Subset.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/String/BeginningWith.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/String/Containing.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Is/String/EndingWith.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/out/Output.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/out/StdOutput.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/utility/AreEqual.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/utility/DefaultValue.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/utility/ToString.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/utility/Meta/IfElseTypes.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/utility/Meta/IsIterableContainer.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/utility/Meta/IsIterableOfType.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Will/Pass.hpp + ${UNITTEST11_SOURCE_DIR}/UnitTest11/Will/Throw.hpp) + +SET (UNITTEST11_SRC_FILES ${UNITTEST11_SOURCE_DIR}/src/Run.cpp + ${UNITTEST11_SOURCE_DIR}/src/TestFixture.cpp + ${UNITTEST11_SOURCE_DIR}/src/Assert/Fail.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/DeclareFixture.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/GetRunner.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/TestFixtureRunner.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/TestStage.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/TestStageBuilder.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/TestStageBuilderImpl.cpp + ${UNITTEST11_SOURCE_DIR}/src/detail/TestStageImpl.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/Empty.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/False.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/Infinity.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/NaN.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/Null.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/True.cpp + ${UNITTEST11_SOURCE_DIR}/src/Is/Zero.cpp + ${UNITTEST11_SOURCE_DIR}/src/out/Output.cpp + ${UNITTEST11_SOURCE_DIR}/src/out/StdOutput.cpp) diff --git a/src/out/StdOutput.cpp b/src/out/StdOutput.cpp index 06c9a4e..548c03a 100644 --- a/src/out/StdOutput.cpp +++ b/src/out/StdOutput.cpp @@ -1,145 +1,145 @@ -/* - * StdOutput.cpp - * - * Created on: 22 May 2013 - * Author: Jason - */ - -#include -#include - -ut11::out::StdOutput::StdOutput() - : m_out(std::cout) -{ -} - -ut11::out::StdOutput::StdOutput(std::ostream& out) - : m_out(out) -{ -} - -ut11::out::StdOutput::~StdOutput() -{ -} - -void ut11::out::StdOutput::Begin() -{ -} - -void ut11::out::StdOutput::BeginFixture(std::string name) -{ - m_out << "Fixture: " << name; - m_given = ""; - m_when = ""; - m_finally = ""; -} - -void ut11::out::StdOutput::EndFixture(std::string) -{ - if (m_finally != "") - m_out << "\n\tFinally: " << m_finally; - m_out << std::endl; -} - -void ut11::out::StdOutput::BeginTest() -{ - m_testStartTime = std::chrono::system_clock::now(); - m_testRunTime = std::chrono::system_clock::duration(0); -} - -void ut11::out::StdOutput::EndTest() -{ - m_out << " [" << std::chrono::duration_cast>(m_testRunTime).count() << "s]"; -} - -void ut11::out::StdOutput::BeginGiven(std::string given) -{ - m_testStartTime = std::chrono::system_clock::now(); - - if (m_given == given) - return; - - if ( m_finally != "" ) - m_out << "\n\tFinally: " << m_finally; - - m_given = given; - m_when = ""; - m_out << "\n\tGiven: " << given; - - m_testStartTime = std::chrono::system_clock::now(); -} - -void ut11::out::StdOutput::EndGiven(std::string) -{ - m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; -} - -void ut11::out::StdOutput::BeginWhen(std::string when) -{ - m_testStartTime = std::chrono::system_clock::now(); - - if (m_when == when) - return; - - m_when = when; - m_out << "\n\t\tWhen: " << when; - - m_testStartTime = std::chrono::system_clock::now(); -} - -void ut11::out::StdOutput::EndWhen(std::string) -{ - m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; -} - -void ut11::out::StdOutput::BeginThen(std::string then) -{ - m_out << "\n\t\t\tThen: " << then; - - m_testStartTime = std::chrono::system_clock::now(); -} - -void ut11::out::StdOutput::EndThen(std::string) -{ - m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; -} - -void ut11::out::StdOutput::BeginFinally(std::string finally) -{ - m_finally = finally; - - m_testStartTime = std::chrono::system_clock::now(); -} - -void ut11::out::StdOutput::EndFinally(std::string) -{ - m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; -} - -void ut11::out::StdOutput::Finish(std::size_t ran, std::size_t succeeded) -{ - m_out << "\nFinished!\nRan: " << ran - << "\nSucceeded: " << succeeded - << std::endl; -} - -void ut11::out::StdOutput::OnError(const std::exception& exception) -{ - m_out << "\n\tFailed: std::exception was thrown [what(): " << exception.what() << "]"; -} - -void ut11::out::StdOutput::OnError(std::size_t line, std::string file, std::string message) -{ - if (m_finally != "") - { - m_out << "\n\tFinally: " << m_finally; - m_finally = ""; - } - - m_out << "\n\tFailed: [" << line << ":" << file << "] " << message; -} - -void ut11::out::StdOutput::OnUnknownError() -{ - m_out << "\n\tFailed: Unknown Error"; -} +/* + * StdOutput.cpp + * + * Created on: 22 May 2013 + * Author: Jason + */ + +#include +#include + +ut11::out::StdOutput::StdOutput() + : m_out(std::cout) +{ +} + +ut11::out::StdOutput::StdOutput(std::ostream& out) + : m_out(out) +{ +} + +ut11::out::StdOutput::~StdOutput() +{ +} + +void ut11::out::StdOutput::Begin() +{ +} + +void ut11::out::StdOutput::BeginFixture(std::string name) +{ + m_out << "Fixture: " << name; + m_given = ""; + m_when = ""; + m_finally = ""; +} + +void ut11::out::StdOutput::EndFixture(std::string) +{ + if (m_finally != "") + m_out << "\n\tFinally: " << m_finally; + m_out << std::endl; +} + +void ut11::out::StdOutput::BeginTest() +{ + m_testStartTime = std::chrono::system_clock::now(); + m_testRunTime = std::chrono::system_clock::duration(0); +} + +void ut11::out::StdOutput::EndTest() +{ + m_out << " [" << std::chrono::duration_cast>(m_testRunTime).count() << "s]"; +} + +void ut11::out::StdOutput::BeginGiven(std::string given) +{ + m_testStartTime = std::chrono::system_clock::now(); + + if (m_given == given) + return; + + if ( m_finally != "" ) + m_out << "\n\tFinally: " << m_finally; + + m_given = given; + m_when = ""; + m_out << "\n\tGiven: " << given; + + m_testStartTime = std::chrono::system_clock::now(); +} + +void ut11::out::StdOutput::EndGiven(std::string) +{ + m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; +} + +void ut11::out::StdOutput::BeginWhen(std::string when) +{ + m_testStartTime = std::chrono::system_clock::now(); + + if (m_when == when) + return; + + m_when = when; + m_out << "\n\t\tWhen: " << when; + + m_testStartTime = std::chrono::system_clock::now(); +} + +void ut11::out::StdOutput::EndWhen(std::string) +{ + m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; +} + +void ut11::out::StdOutput::BeginThen(std::string then) +{ + m_out << "\n\t\t\tThen: " << then; + + m_testStartTime = std::chrono::system_clock::now(); +} + +void ut11::out::StdOutput::EndThen(std::string) +{ + m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; +} + +void ut11::out::StdOutput::BeginFinally(std::string finally) +{ + m_finally = finally; + + m_testStartTime = std::chrono::system_clock::now(); +} + +void ut11::out::StdOutput::EndFinally(std::string) +{ + m_testRunTime += std::chrono::system_clock::now() - m_testStartTime; +} + +void ut11::out::StdOutput::Finish(std::size_t ran, std::size_t succeeded) +{ + m_out << "\nFinished!\nRan: " << ran + << "\nSucceeded: " << succeeded + << std::endl; +} + +void ut11::out::StdOutput::OnError(const std::exception& exception) +{ + m_out << "\n\tFailed: std::exception was thrown [what(): " << exception.what() << "]"; +} + +void ut11::out::StdOutput::OnError(std::size_t line, std::string file, std::string message) +{ + if (m_finally != "") + { + m_out << "\n\tFinally: " << m_finally; + m_finally = ""; + } + + m_out << "\n\tFailed: [" << line << ":" << file << "] " << message; +} + +void ut11::out::StdOutput::OnUnknownError() +{ + m_out << "\n\tFailed: Unknown Error"; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2394f76..ac96dc7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,9 @@ -include_directories(${UNITTEST11_SOURCE_DIR}/include) - -include(files.cmake) - -add_executable(unittest11_tests ${UNITTEST11_TESTS_SRC_FILES}) -target_link_libraries(unittest11_tests unittest11) - -add_test(units unittest11_tests category=unit) -add_test(examples unittest11_tests category=example) +include_directories(${UNITTEST11_SOURCE_DIR}/include) + +include(files.cmake) + +add_executable(unittest11_tests ${UNITTEST11_TESTS_SRC_FILES}) +target_link_libraries(unittest11_tests unittest11) + +add_test(units unittest11_tests category=unit) +add_test(examples unittest11_tests category=example) diff --git a/tests/Examples/EntityComponentStore.cpp b/tests/Examples/EntityComponentStore.cpp index 9c8fdfb..59855dd 100644 --- a/tests/Examples/EntityComponentStore.cpp +++ b/tests/Examples/EntityComponentStore.cpp @@ -1,201 +1,201 @@ -#include -#include -#include -#include -#include -#include -#include - -namespace ecs -{ - struct EntityNotFoundException : public std::exception - { - EntityNotFoundException(std::string description) throw() : description(description) { } - ~EntityNotFoundException() throw () { } - - virtual const char* what() const throw() - { - return description.c_str(); - } - - private: - std::string description; - }; - - struct ComponentNotFoundException : public std::exception - { - ComponentNotFoundException(std::string description) throw() : description(description) { } - ~ComponentNotFoundException() throw () { } - - virtual const char* what() const throw() - { - return description.c_str(); - } - - private: - std::string description; - }; - - template class EntityComponentStore - { - private: - static void ProcessToStringStream(std::ostream& stream) { return; } - - template static void ProcessToStringStream(std::ostream& stream, T&& arg, ARGS&&... args) - { - ProcessToStringStream(stream << arg, std::forward(args)...); - } - - template static std::string CreateString(ARGS&&... args) - { - std::stringstream stream; - ProcessToStringStream(stream, std::forward(args)...); - return stream.str(); - } - - public: - inline void addEntity(TEntityId id) - { - entities.push_back(id); - entityComponentMap.insert(std::make_pair(id, std::map>())); - } - - inline std::vector getAllEntities() const { return entities; } - - template inline void addComponent(TEntityId id, TComponent component) - { - auto componentName = GetNameOfComponent(); - - componentEntityMap.insert(std::make_pair(componentName, id)); - entityComponentMap[id].insert(std::make_pair(componentName, MakeComponentPtr(component))); - } - - template inline std::vector getAllEntitiesFor() const - { - std::vector result; - - auto name = GetNameOfComponent(); - auto range = componentEntityMap.equal_range(name); - for (auto i = range.first; i != range.second; ++i) - result.push_back(i->second); - - return result; - } - - template inline TComponent getComponentOfEntity(TEntityId entityId) const - { - auto componentsOfEntity = entityComponentMap.find(entityId); - if (componentsOfEntity == entityComponentMap.end()) - throw EntityNotFoundException(CreateString(entityId, " does not exist in store")); - - auto componentName = GetNameOfComponent(); - auto componentIt = componentsOfEntity->second.find(componentName); - if (componentIt == componentsOfEntity->second.end()) - throw ComponentNotFoundException(CreateString(componentName, " does not exist on ", entityId)); - - return *std::static_pointer_cast(componentIt->second); - } - - private: - typedef std::string TypeInfo; - - template inline static std::shared_ptr MakeComponentPtr(TComponent component) - { - return std::static_pointer_cast(std::make_shared(component)); - } - - template inline static TypeInfo GetNameOfComponent() - { - return TypeInfo( typeid(TComponent).name() ); - } - - std::vector entities; - std::map>> entityComponentMap; - std::multimap componentEntityMap; - }; -} - -#include - -class EntityComponentStoreTests : public ut11::TestFixture -{ -private: - ecs::EntityComponentStore m_entityComponentStore; - std::vector m_entities; - std::vector m_actualEntities; - std::vector m_entitiesWithStringComponent; - std::vector m_entitiesWithIntComponent; - - std::string m_expectedStringComponentValue; - int m_expectedIntComponentValue; - -public: - virtual void Run() - { - Given("an entity component store with added entities and with components", [&]() - { - m_entityComponentStore = ecs::EntityComponentStore(); - m_actualEntities = std::vector(); - - m_entities = { 1, 2, 3, 4, 5 }; - for (auto entity : m_entities) - m_entityComponentStore.addEntity(entity); - - m_entitiesWithStringComponent.push_back(m_entities[2]); - m_entitiesWithIntComponent.push_back(m_entities[2]); - m_entitiesWithIntComponent.push_back(m_entities[3]); - - m_expectedStringComponentValue = std::string("test_component1"); - m_expectedIntComponentValue = 7; - - for (auto entity : m_entitiesWithStringComponent) - m_entityComponentStore.addComponent(entity, m_expectedStringComponentValue); - - for (auto entity : m_entitiesWithIntComponent) - m_entityComponentStore.addComponent(entity, m_expectedIntComponentValue); - }); - Then("getting the string component of an entity gives the expected value", [&]() - { - std::string component = m_entityComponentStore.getComponentOfEntity(m_entitiesWithStringComponent[0]); - AssertThat(component, ut11::Is::EqualTo(m_expectedStringComponentValue)); - }); - Then("getting the int component of an entity gives the expected value", [&]() - { - int component = m_entityComponentStore.getComponentOfEntity(m_entitiesWithIntComponent[0]); - AssertThat(component, ut11::Is::EqualTo(m_expectedIntComponentValue)); - }); - Then("getting a component of an entity that does not exist throws the expected exception", [&]() - { - AssertThat([&]() { m_entityComponentStore.getComponentOfEntity(100); }, ut11::Will::Throw()); - }); - Then("getting a component of an entity that does not have that component throws the expected exception", [&]() - { - AssertThat([&]() { m_entityComponentStore.getComponentOfEntity(m_entities[4]); }, ut11::Will::Throw()); - }); - When("getting all entities", [&]() - { - m_actualEntities = m_entityComponentStore.getAllEntities(); - }); - Then("the expected entities are returned", [&]() - { - AssertThat(m_actualEntities, ut11::Is::Iterable::EquivalentTo(m_entities)); - }); - When("getting all entities with string components", [&]() - { - m_actualEntities = m_entityComponentStore.getAllEntitiesFor(); - }); - Then("the expected entities are returned", [&]() - { - AssertThat(m_actualEntities, ut11::Is::Iterable::EquivalentTo(m_entitiesWithStringComponent)); - }); - When("getting all entities with int components", [&]() - { - m_actualEntities = m_entityComponentStore.getAllEntitiesFor(); - }); - Then("the expected entities are returned", [&]() - { - AssertThat(m_actualEntities, ut11::Is::Iterable::EquivalentTo(m_entitiesWithIntComponent)); - }); - } -}; -DeclareFixture(EntityComponentStoreTests)(ut11::Category("example")); +#include +#include +#include +#include +#include +#include +#include + +namespace ecs +{ + struct EntityNotFoundException : public std::exception + { + EntityNotFoundException(std::string description) throw() : description(description) { } + ~EntityNotFoundException() throw () { } + + virtual const char* what() const throw() + { + return description.c_str(); + } + + private: + std::string description; + }; + + struct ComponentNotFoundException : public std::exception + { + ComponentNotFoundException(std::string description) throw() : description(description) { } + ~ComponentNotFoundException() throw () { } + + virtual const char* what() const throw() + { + return description.c_str(); + } + + private: + std::string description; + }; + + template class EntityComponentStore + { + private: + static void ProcessToStringStream(std::ostream& stream) { return; } + + template static void ProcessToStringStream(std::ostream& stream, T&& arg, ARGS&&... args) + { + ProcessToStringStream(stream << arg, std::forward(args)...); + } + + template static std::string CreateString(ARGS&&... args) + { + std::stringstream stream; + ProcessToStringStream(stream, std::forward(args)...); + return stream.str(); + } + + public: + inline void addEntity(TEntityId id) + { + entities.push_back(id); + entityComponentMap.insert(std::make_pair(id, std::map>())); + } + + inline std::vector getAllEntities() const { return entities; } + + template inline void addComponent(TEntityId id, TComponent component) + { + auto componentName = GetNameOfComponent(); + + componentEntityMap.insert(std::make_pair(componentName, id)); + entityComponentMap[id].insert(std::make_pair(componentName, MakeComponentPtr(component))); + } + + template inline std::vector getAllEntitiesFor() const + { + std::vector result; + + auto name = GetNameOfComponent(); + auto range = componentEntityMap.equal_range(name); + for (auto i = range.first; i != range.second; ++i) + result.push_back(i->second); + + return result; + } + + template inline TComponent getComponentOfEntity(TEntityId entityId) const + { + auto componentsOfEntity = entityComponentMap.find(entityId); + if (componentsOfEntity == entityComponentMap.end()) + throw EntityNotFoundException(CreateString(entityId, " does not exist in store")); + + auto componentName = GetNameOfComponent(); + auto componentIt = componentsOfEntity->second.find(componentName); + if (componentIt == componentsOfEntity->second.end()) + throw ComponentNotFoundException(CreateString(componentName, " does not exist on ", entityId)); + + return *std::static_pointer_cast(componentIt->second); + } + + private: + typedef std::string TypeInfo; + + template inline static std::shared_ptr MakeComponentPtr(TComponent component) + { + return std::static_pointer_cast(std::make_shared(component)); + } + + template inline static TypeInfo GetNameOfComponent() + { + return TypeInfo( typeid(TComponent).name() ); + } + + std::vector entities; + std::map>> entityComponentMap; + std::multimap componentEntityMap; + }; +} + +#include + +class EntityComponentStoreTests : public ut11::TestFixture +{ +private: + ecs::EntityComponentStore m_entityComponentStore; + std::vector m_entities; + std::vector m_actualEntities; + std::vector m_entitiesWithStringComponent; + std::vector m_entitiesWithIntComponent; + + std::string m_expectedStringComponentValue; + int m_expectedIntComponentValue; + +public: + virtual void Run() + { + Given("an entity component store with added entities and with components", [&]() + { + m_entityComponentStore = ecs::EntityComponentStore(); + m_actualEntities = std::vector(); + + m_entities = { 1, 2, 3, 4, 5 }; + for (auto entity : m_entities) + m_entityComponentStore.addEntity(entity); + + m_entitiesWithStringComponent.push_back(m_entities[2]); + m_entitiesWithIntComponent.push_back(m_entities[2]); + m_entitiesWithIntComponent.push_back(m_entities[3]); + + m_expectedStringComponentValue = std::string("test_component1"); + m_expectedIntComponentValue = 7; + + for (auto entity : m_entitiesWithStringComponent) + m_entityComponentStore.addComponent(entity, m_expectedStringComponentValue); + + for (auto entity : m_entitiesWithIntComponent) + m_entityComponentStore.addComponent(entity, m_expectedIntComponentValue); + }); + Then("getting the string component of an entity gives the expected value", [&]() + { + std::string component = m_entityComponentStore.getComponentOfEntity(m_entitiesWithStringComponent[0]); + AssertThat(component, ut11::Is::EqualTo(m_expectedStringComponentValue)); + }); + Then("getting the int component of an entity gives the expected value", [&]() + { + int component = m_entityComponentStore.getComponentOfEntity(m_entitiesWithIntComponent[0]); + AssertThat(component, ut11::Is::EqualTo(m_expectedIntComponentValue)); + }); + Then("getting a component of an entity that does not exist throws the expected exception", [&]() + { + AssertThat([&]() { m_entityComponentStore.getComponentOfEntity(100); }, ut11::Will::Throw()); + }); + Then("getting a component of an entity that does not have that component throws the expected exception", [&]() + { + AssertThat([&]() { m_entityComponentStore.getComponentOfEntity(m_entities[4]); }, ut11::Will::Throw()); + }); + When("getting all entities", [&]() + { + m_actualEntities = m_entityComponentStore.getAllEntities(); + }); + Then("the expected entities are returned", [&]() + { + AssertThat(m_actualEntities, ut11::Is::Iterable::EquivalentTo(m_entities)); + }); + When("getting all entities with string components", [&]() + { + m_actualEntities = m_entityComponentStore.getAllEntitiesFor(); + }); + Then("the expected entities are returned", [&]() + { + AssertThat(m_actualEntities, ut11::Is::Iterable::EquivalentTo(m_entitiesWithStringComponent)); + }); + When("getting all entities with int components", [&]() + { + m_actualEntities = m_entityComponentStore.getAllEntitiesFor(); + }); + Then("the expected entities are returned", [&]() + { + AssertThat(m_actualEntities, ut11::Is::Iterable::EquivalentTo(m_entitiesWithIntComponent)); + }); + } +}; +DeclareFixture(EntityComponentStoreTests)(ut11::Category("example")); diff --git a/tests/files.cmake b/tests/files.cmake index 3ef3726..d2b55c2 100644 --- a/tests/files.cmake +++ b/tests/files.cmake @@ -1,38 +1,38 @@ -SET(UNITTEST11_TESTS_SRC_FILES main.cpp - Examples/EntityComponentStore.cpp - Examples/EventDispatcher.cpp - Examples/Minesweeper.cpp - Unit/MockTests.cpp - Unit/TestFixtureTests.cpp - Unit/Assert/FailTests.cpp - Unit/Assert/ThatTests.cpp - Unit/detail/LogicalOperandsTests.cpp - Unit/detail/MockArgumentHandlerTests.cpp - Unit/detail/MockReturnHandlerTests.cpp - Unit/detail/OperandTests.cpp - Unit/detail/TestFixtureRunnerTests.cpp - Unit/detail/TestStageBuilderTests.cpp - Unit/detail/TestStageTests.cpp - Unit/Is/AnyTests.cpp - Unit/Is/BetweenTests.cpp - Unit/Is/EmptyTests.cpp - Unit/Is/EqualToTests.cpp - Unit/Is/FalseTests.cpp - Unit/Is/GreaterThanTests.cpp - Unit/Is/InfinityTests.cpp - Unit/Is/LessThanTests.cpp - Unit/Is/NaNTests.cpp - Unit/Is/NullTests.cpp - Unit/Is/TrueTests.cpp - Unit/Is/ZeroTests.cpp - Unit/Is/Iterable/EquivalentToTests.cpp - Unit/Is/Iterable/OfTests.cpp - Unit/Is/Iterable/Containing/ItemTests.cpp - Unit/Is/Iterable/Containing/SubsetTests.cpp - Unit/Is/String/BeginningWithTests.cpp - Unit/Is/String/ContainingTests.cpp - Unit/Is/String/EndingWithTests.cpp - Unit/out/StdOutputTests.cpp - Unit/Utility/ToStringTests.cpp - Unit/Will/PassTests.cpp - Unit/Will/ThrowTests.cpp) +SET(UNITTEST11_TESTS_SRC_FILES main.cpp + Examples/EntityComponentStore.cpp + Examples/EventDispatcher.cpp + Examples/Minesweeper.cpp + Unit/MockTests.cpp + Unit/TestFixtureTests.cpp + Unit/Assert/FailTests.cpp + Unit/Assert/ThatTests.cpp + Unit/detail/LogicalOperandsTests.cpp + Unit/detail/MockArgumentHandlerTests.cpp + Unit/detail/MockReturnHandlerTests.cpp + Unit/detail/OperandTests.cpp + Unit/detail/TestFixtureRunnerTests.cpp + Unit/detail/TestStageBuilderTests.cpp + Unit/detail/TestStageTests.cpp + Unit/Is/AnyTests.cpp + Unit/Is/BetweenTests.cpp + Unit/Is/EmptyTests.cpp + Unit/Is/EqualToTests.cpp + Unit/Is/FalseTests.cpp + Unit/Is/GreaterThanTests.cpp + Unit/Is/InfinityTests.cpp + Unit/Is/LessThanTests.cpp + Unit/Is/NaNTests.cpp + Unit/Is/NullTests.cpp + Unit/Is/TrueTests.cpp + Unit/Is/ZeroTests.cpp + Unit/Is/Iterable/EquivalentToTests.cpp + Unit/Is/Iterable/OfTests.cpp + Unit/Is/Iterable/Containing/ItemTests.cpp + Unit/Is/Iterable/Containing/SubsetTests.cpp + Unit/Is/String/BeginningWithTests.cpp + Unit/Is/String/ContainingTests.cpp + Unit/Is/String/EndingWithTests.cpp + Unit/out/StdOutputTests.cpp + Unit/Utility/ToStringTests.cpp + Unit/Will/PassTests.cpp + Unit/Will/ThrowTests.cpp)