wip
Some checks are pending
continuous-integration/drone/pr Build is running

This commit is contained in:
light7734 2025-10-21 15:37:33 +03:30
parent f1a91c9b81
commit 4ce413a1d7
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
3 changed files with 147 additions and 1 deletions

View file

@ -4,4 +4,4 @@ add_library_module(fuzz_test test.cpp fuzz.cpp)
target_link_libraries(test PUBLIC tbb logger)
target_link_libraries(fuzz_test PUBLIC tbb logger)
add_test_module(test test.test.cpp)
add_test_module(test test.test.cpp mock.test.cpp)

View file

@ -0,0 +1,52 @@
#include <test/mock.hpp>
#include <test/test.hpp>
using namespace lt::test;
using namespace lt::test::mock;
class ExpensiveClass
{
private:
public:
virtual int expensive(std::string str, std::optional<int> opt)
{
return 0;
}
};
class MockClass: public ExpensiveClass
{
public:
int expensive(std::string str, std::optional<int> opt) override
{
return expensive_mock(str, opt);
};
Mock<int(std::string, std::optional<int>)> expensive_mock {};
};
class ExpensiveUser
{
public:
ExpensiveUser(ExpensiveClass &dependency)
{
dependency.expensive("", 10);
}
};
// problem #1: matcher functions should construct an invokable object to test against the indexed
// argument.
Suite raii = "mock_raii"_suite = [] {
Case { "happy path won't throw" } = [] {
auto a = std::function<int(int)> {};
auto expensive = MockClass {};
auto side_effect = false;
expensive.expensive_mock.expect("test", std::nullopt)
.apply([&](auto str, auto opt) { side_effect = true; })
.returns(69);
auto user = ExpensiveUser { expensive };
};
};

View file

@ -0,0 +1,94 @@
#pragma once
namespace lt::test {
template<typename _Signature>
class Mock;
template<typename Return_Type, typename... Arg_Types>
class Mock<Return_Type(Arg_Types...)>
{
public:
auto at_least() -> Mock &
{
return *this;
}
auto operator&&(Mock &mock) -> Mock &
{
return mock;
}
auto operator()(Arg_Types... arguments) -> Return_Type
{
++m_call_index;
for (auto &side_effect : m_side_effects)
{
side_effect(std::forward<Arg_Types>(arguments)...);
}
if (m_return_func)
{
return m_return_func(std::forward<Arg_Types>(arguments)...);
}
return m_return_value;
}
/** With any arguments. */
template<uint32_t counter = 1>
auto expect() -> Mock &
{
m_expected_counter = counter;
return *this;
}
auto apply(std::function<void(Arg_Types...)> side_effect) -> Mock &
{
m_side_effects.emplace_back(std::move(side_effect));
return *this;
}
/** Returns a fixed value. */
auto returns(Return_Type value) -> Mock &
{
m_return_value = value;
return *this;
}
/** Returns a value based on input. */
auto returns(std::function<Return_Type(Arg_Types...)> func) -> Mock &
{
m_return_func = std::move(func);
return *this;
}
private:
Return_Type m_return_value {};
std::function<Return_Type(Arg_Types...)> m_return_func {};
std::vector<std::function<void(Arg_Types...)>> m_side_effects {};
uint32_t m_call_index = 0;
std::vector<std::pair<std::tuple<Arg_Types...>, uint32_t>> m_expected_args;
uint32_t m_expected_counter {};
};
namespace mock::range {
[[nodiscard]] auto is_empty() -> bool
{
return false;
}
}; // namespace mock::range
[[nodiscard]] auto eq(auto rhs) -> bool
{
return false;
}
} // namespace lt::test