210 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #pragma once
 | |
| 
 | |
| #include <concepts>
 | |
| #include <format>
 | |
| #include <source_location>
 | |
| 
 | |
| namespace lt::test {
 | |
| 
 | |
| template<typename T>
 | |
| concept Formattable = requires(T &v, std::format_context ctx) {
 | |
| 	std::formatter<std::remove_cvref_t<T>>().format(v, ctx);
 | |
| };
 | |
| 
 | |
| template<typename T>
 | |
| concept Printable = Formattable<T> || 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
 |