diff --git a/polymorphism/include/polymorphism/consume_class_that_adheres_to_concept.hpp b/polymorphism/include/polymorphism/consume_class_that_adheres_to_concept.hpp index 4a7f695..fe09c36 100644 --- a/polymorphism/include/polymorphism/consume_class_that_adheres_to_concept.hpp +++ b/polymorphism/include/polymorphism/consume_class_that_adheres_to_concept.hpp @@ -1,5 +1,5 @@ -#ifndef POYMORPHISM_CONSUME_CLASS_THAT_ADHERES_TO_CONCEPT_HPP -#define POYMORPHISM_CONSUME_CLASS_THAT_ADHERES_TO_CONCEPT_HPP +#ifndef POLYMORPHISM_CONSUME_CLASS_THAT_ADHERES_TO_CONCEPT_HPP +#define POLYMORPHISM_CONSUME_CLASS_THAT_ADHERES_TO_CONCEPT_HPP #include @@ -12,4 +12,4 @@ std::string consume(has_super_cool_features auto& s); } // namespace modern -#endif // POYMORPHISM_CONSUME_CLASS_THAT_ADHERES_TO_CONCEPT_HPP \ No newline at end of file +#endif // POLYMORPHISM_CONSUME_CLASS_THAT_ADHERES_TO_CONCEPT_HPP \ No newline at end of file diff --git a/polymorphism/test/CMakeLists.txt b/polymorphism/test/CMakeLists.txt index d351f0c..c40aef7 100644 --- a/polymorphism/test/CMakeLists.txt +++ b/polymorphism/test/CMakeLists.txt @@ -15,17 +15,24 @@ add_library(polymorphism_lib ) target_compile_features(polymorphism_lib PUBLIC cxx_std_23) -target_include_directories(polymorphism_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include) -target_include_directories(polymorphism_lib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) +target_include_directories(polymorphism_lib + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src) add_executable(test_consume - test_consume.cpp + src/test_consume.cpp + src/mocking.cpp ) target_compile_features(test_consume PUBLIC cxx_std_23) - -target_include_directories(test_consume PUBLIC ../include) -target_include_directories(test_consume PUBLIC "${ut_SOURCE_DIR}") +target_include_directories(test_consume + PRIVATE + # Library includes + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../src + # Test includes + ${CMAKE_CURRENT_SOURCE_DIR}/include + "${ut_SOURCE_DIR}") target_link_libraries(test_consume PRIVATE polymorphism_lib) diff --git a/polymorphism/test/include/test_polymorphism/mocking.hpp b/polymorphism/test/include/test_polymorphism/mocking.hpp new file mode 100644 index 0000000..d93f1f7 --- /dev/null +++ b/polymorphism/test/include/test_polymorphism/mocking.hpp @@ -0,0 +1,45 @@ +#ifndef POLYMORPHISM_MOCKING_HPP +#define POLYMORPHISM_MOCKING_HPP + +#include +#include +#include +#include + +namespace mocking { + +struct Mock { + std::list collectedSetArguments; + mutable std::atomic numberOfCallsToCoolFeature { 0 }; + + /** + * @brief Returns the last set value or a default value if none exists. + * @note Thread-safe. Multiple concurrent calls are safe. + * @return The last set string or "" if no strings were set + */ + std::string coolFeature() const + { + ++numberOfCallsToCoolFeature; + + return collectedSetArguments.empty() + ? "" + : collectedSetArguments.back(); + } + + /** + * @brief Stores a string value for later retrieval by coolFeature + * @param s The string to store (must not be empty) + * @throws std::invalid_argument if the string is empty + */ + void set(std::string s) + { + if (s.empty()) { + throw std::invalid_argument("Empty strings are not allowed"); + } + collectedSetArguments.emplace_back(std::move(s)); + } +}; + +} // namespace mocking + +#endif // POLYMORPHISM_MOCKING_HPP \ No newline at end of file diff --git a/polymorphism/test/src/mocking.cpp b/polymorphism/test/src/mocking.cpp new file mode 100644 index 0000000..9089aeb --- /dev/null +++ b/polymorphism/test/src/mocking.cpp @@ -0,0 +1,7 @@ +#include +#include + +#include + +// explicit instantiation of consume() for Mock +template std::string modern::consume(mocking::Mock&); diff --git a/polymorphism/test/test_consume.cpp b/polymorphism/test/src/test_consume.cpp similarity index 57% rename from polymorphism/test/test_consume.cpp rename to polymorphism/test/src/test_consume.cpp index 1d7f51b..29ad7b7 100644 --- a/polymorphism/test/test_consume.cpp +++ b/polymorphism/test/src/test_consume.cpp @@ -5,6 +5,8 @@ #include #include +#include + int main() { using namespace boost::ut; @@ -43,4 +45,31 @@ int main() }; }; }; + + "[modern mock]"_test = [] { + static constexpr auto EXPECTED_COOLFEATURE_CALLS = 2; // coolFeature() is called: + // 1. During initial value check (line 56) + // 2. During side effect verification (line 70) + given("I have a an mock that adheres to a concept") = [] { + mocking::Mock impl; + + expect(""s == impl.coolFeature()); + + when("I pass it to a function that expects an argument that fulfils the constraints") = [&] { + auto result = modern::consume(impl); + + then("set() should be called twice") = [&] { + expect(EXPECTED_COOLFEATURE_CALLS == impl.numberOfCallsToCoolFeature); + }; + + then("the answer to all questions should be given") = [=] { + expect("The answer to all questions is 42"s == result); + }; + + then("the state of the argument should be modified as a side effect") = [&] { + expect("42"s == impl.coolFeature()); + }; + }; + }; + }; }