light/modules/test/public/expects.hpp

208 lines
4.1 KiB
C++
Raw Normal View History

#pragma once
#include <concepts>
#include <format>
#include <source_location>
namespace lt::test {
template<typename T>
concept Printable = requires(std::ostream &stream, T value) {
{ stream << value } -> std::same_as<std::ostream &>;
} || requires(std::ostream &stream, T value) {
{ stream << std::to_underlying<T>(value) } -> std::same_as<std::ostream &>;
};
template<typename T>
concept Testable = Printable<T> && std::equality_comparable<T>;
constexpr void expect_unreachable(
std::source_location source_location = std::source_location::current()
)
{
throw std::runtime_error {
std::format(
"Failed unreachable expectation:\n"
"\tlocation: {}:{}",
source_location.file_name(),
source_location.line()
),
};
};
constexpr void expect_throw(
std::invocable auto invocable,
std::source_location source_location = std::source_location::current()
)
{
try
{
invocable();
}
catch (const std::exception &exp)
{
return;
}
throw std::runtime_error {
std::format(
"Failed throwing expectation:\n"
"\tlocation: {}:{}",
source_location.file_name(),
source_location.line()
),
};
}
constexpr void expect_eq(
Testable auto lhs,
Testable auto rhs,
std::source_location source_location = std::source_location::current()
)
{
if constexpr (std::is_enum_v<decltype(lhs)>)
{
if (lhs != rhs)
{
throw std::runtime_error {
std::format(
"Failed equality expectation:\n"
"\tactual: {}\n"
"\texpected: {}\n"
"\tlocation: {}:{}",
std::to_underlying<decltype(lhs)>(lhs),
std::to_underlying<decltype(rhs)>(rhs),
source_location.file_name(),
source_location.line()
),
};
}
}
else if (lhs != rhs)
{
throw std::runtime_error {
std::format(
"Failed equality expectation:\n"
"\tactual: {}\n"
"\texpected: {}\n"
"\tlocation: {}:{}",
lhs,
rhs,
source_location.file_name(),
source_location.line()
),
};
}
}
constexpr void expect_ne(
Testable auto lhs,
Testable auto rhs,
std::source_location source_location = std::source_location::current()
)
{
if (lhs == rhs)
{
throw std::runtime_error {
std::format(
"Failed un-equality expectation:\n"
"\tactual: {}\n"
"\texpected: {}\n"
"\tlocation: {}:{}",
lhs,
rhs,
source_location.file_name(),
source_location.line()
),
};
}
}
constexpr void expect_true(
bool expression,
std::source_location source_location = std::source_location::current()
)
{
if (!expression)
{
throw std::runtime_error {
std::format(
"Failed true expectation:\n"
"\tactual: {}\n"
"\texpected: true\n"
"\tlocation: {}:{}",
expression,
source_location.file_name(),
source_location.line()
),
};
}
}
constexpr void expect_false(
bool expression,
std::source_location source_location = std::source_location::current()
)
{
if (expression)
{
throw std::runtime_error {
std::format(
"Failed false expectation:\n"
"\tactual: {}\n"
"\texpected: true\n"
"\tlocation: {}:{}",
expression,
source_location.file_name(),
source_location.line()
),
};
}
}
constexpr void expect_not_nullptr(
auto *pointer,
std::source_location source_location = std::source_location::current()
)
{
if (pointer == nullptr)
{
throw std::runtime_error {
std::format(
"Failed true expectation:\n"
"\tactual: nullptr\n"
"\texpected: not nullptr\n"
"\tlocation: {}:{}",
source_location.file_name(),
source_location.line()
),
};
}
}
constexpr void expect_le(
Testable auto lhs,
Testable auto rhs,
std::source_location source_location = std::source_location::current()
)
{
if (lhs > rhs)
{
throw std::runtime_error {
std::format(
"Failed false expectation:\n"
"\tactual: {}\n"
"\texpected: >= {}\n"
"\tlocation: {}:{}",
lhs,
rhs,
source_location.file_name(),
source_location.line()
),
};
}
}
} // namespace lt::test