forked from Alepha/Alepha
180 lines
3.4 KiB
C++
180 lines
3.4 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
|
|
#pragma once
|
|
|
|
#include <Alepha/Alepha.h>
|
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <functional>
|
|
#include <memory>
|
|
|
|
#include <Alepha/Console.h>
|
|
#include <Alepha/types.h>
|
|
|
|
#include <Alepha/Utility/evaluation_helpers.h>
|
|
#include <Alepha/Utility/StaticValue.h>
|
|
|
|
#include "colors.h"
|
|
|
|
namespace Alepha::Hydrogen::Testing
|
|
{
|
|
inline namespace exports { inline namespace test_m {} }
|
|
|
|
namespace detail::test_m
|
|
{
|
|
inline namespace exports {}
|
|
|
|
namespace C
|
|
{
|
|
const bool debug= false;
|
|
const bool debugTestRegistration= false or C::debug;
|
|
const bool debugTestRun= false or C::debug;
|
|
|
|
using namespace detail::colors_m::C::Colors;
|
|
}
|
|
|
|
using namespace std::literals::string_literals;
|
|
using namespace Utility::exports::evaluation_helpers_m;
|
|
using namespace Utility::exports::StaticValue_m;
|
|
|
|
struct TestName
|
|
{
|
|
std::string name;
|
|
bool disabled= false;
|
|
|
|
[[nodiscard]] TestName
|
|
operator -() const
|
|
{
|
|
auto rv= *this;
|
|
|
|
rv.disabled= true;
|
|
|
|
return rv;
|
|
}
|
|
};
|
|
|
|
namespace exports
|
|
{
|
|
struct TestFailure;
|
|
|
|
inline namespace literals
|
|
{
|
|
[[nodiscard]] inline auto
|
|
operator""_test( const char name[], std::size_t amount )
|
|
{
|
|
return TestName{ std::string{ name, name + amount } };
|
|
}
|
|
}
|
|
}
|
|
|
|
inline namespace impl
|
|
{
|
|
// It is okay to discard this result, if making tests in an enroll block.
|
|
struct TestRegistration {};
|
|
TestRegistration operator <= ( TestName name, std::function< void () > test );
|
|
}
|
|
|
|
struct exports::TestFailure
|
|
{
|
|
int failureCount= -1;
|
|
std::string message_;
|
|
|
|
explicit TestFailure( const int failureCount )
|
|
: failureCount( failureCount ) {}
|
|
};
|
|
|
|
template< Integral Integer >
|
|
inline auto
|
|
operator <= ( TestName name, std::function< Integer () > test )
|
|
{
|
|
if constexpr( std::is_same_v< Integer, bool > )
|
|
{
|
|
auto wrapper= [test]
|
|
{
|
|
if( not test() )
|
|
{
|
|
throw TestFailure{ 1 };
|
|
}
|
|
};
|
|
|
|
return name <= wrapper;
|
|
}
|
|
else
|
|
{
|
|
auto wrapper= [test]
|
|
{
|
|
const int failures= test();
|
|
if( failures > 0 ) throw TestFailure{ failures };
|
|
};
|
|
|
|
return name <= wrapper;
|
|
}
|
|
}
|
|
|
|
namespace exports
|
|
{
|
|
struct TestStateCore
|
|
{
|
|
public:
|
|
std::vector< std::string > failures;
|
|
|
|
public:
|
|
void
|
|
expect( const bool state, const std::string test= "" )
|
|
{
|
|
if( not state ) failures.push_back( test );
|
|
}
|
|
|
|
void
|
|
demand( const bool state, const std::string test= "" )
|
|
{
|
|
if( not state ) throw TestFailure( failures.size() + 1 );
|
|
}
|
|
};
|
|
|
|
using TestState= TestStateCore &;
|
|
}
|
|
|
|
inline auto
|
|
operator <= ( TestName name, std::function< void ( TestState ) > test )
|
|
{
|
|
auto wrapper= [test]
|
|
{
|
|
TestStateCore state;
|
|
test( state );
|
|
return state.failures.size();
|
|
};
|
|
return name <= std::function{ wrapper };
|
|
};
|
|
|
|
template< typename TestFunc >
|
|
inline auto
|
|
operator <= ( TestName name, TestFunc test )
|
|
{
|
|
return name <= std::function{ test };
|
|
}
|
|
|
|
namespace exports
|
|
{
|
|
[[nodiscard]] int runAllTests( const std::vector< std::string > selections= {} );
|
|
|
|
[[nodiscard]] int runAllTests( const argcnt_t argcnt, const argvec_t argvec );
|
|
}
|
|
}
|
|
|
|
namespace exports::test_m
|
|
{
|
|
using namespace detail::test_m::exports;
|
|
}
|
|
|
|
namespace exports::inline literals::inline test_literals
|
|
{
|
|
using namespace detail::test_m::exports::literals;
|
|
}
|
|
}
|