forked from Alepha/Alepha
Starting out Alepha from scratch, as a C++17 effort.
This one is going to be prepped for GitHub private, from the get go. This initial commit has some evaluation helpers and the unit testing infrastructure. `TableTest` will come next.
This commit is contained in:
8
Alepha.h
Normal file
8
Alepha.h
Normal file
@ -0,0 +1,8 @@
|
||||
static_assert( __cplusplus > 201700, "C++17 Required" );
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Alepha
|
||||
{
|
||||
inline namespace Hydrogen {}
|
||||
}
|
3
Testing/Makefile
Normal file
3
Testing/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
CXXFLAGS+= -std=c++17 -I ../
|
||||
|
||||
all: test
|
28
Testing/test.cc
Normal file
28
Testing/test.cc
Normal file
@ -0,0 +1,28 @@
|
||||
#include <Alepha/Testing/test.h>
|
||||
#include <Alepha/Utility/evaluation.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace UnitTest= Alepha::Testing::exports::testing;
|
||||
}
|
||||
|
||||
int
|
||||
main( const int argcnt, const char *const *const argvec )
|
||||
{
|
||||
return UnitTest::runAllTests( argcnt, argvec );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace UnitTest::literals;
|
||||
using namespace Alepha::Utility::exports::evaluation;
|
||||
|
||||
auto registration= enroll <=[]
|
||||
{
|
||||
"enroll.basic.success"_test <=[]{};
|
||||
-"enroll.basic.failure"_test <=[]{ throw 0; };
|
||||
};
|
||||
|
||||
auto named1= "named.basic.success"_test <= []{};
|
||||
auto named2= -"named.basic.failure"_test <=[]{ return 1; };
|
||||
}
|
165
Testing/test.h
Normal file
165
Testing/test.h
Normal file
@ -0,0 +1,165 @@
|
||||
static_assert( __cplusplus > 201700, "C++17 Required" );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace Alepha::Hydrogen::Testing
|
||||
{
|
||||
inline namespace exports { inline namespace testing {} }
|
||||
|
||||
namespace detail::testing
|
||||
{
|
||||
inline namespace exports {}
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
namespace C
|
||||
{
|
||||
const std::string csi= "\e[";
|
||||
const std::string green= C::csi + "32m";
|
||||
const std::string red= C::csi + "31m";
|
||||
const std::string normal= C::csi + "0m";
|
||||
}
|
||||
|
||||
struct TestName
|
||||
{
|
||||
std::string name;
|
||||
bool disabled= false;
|
||||
|
||||
[[nodiscard]] TestName
|
||||
operator -() const
|
||||
{
|
||||
auto rv= *this;
|
||||
|
||||
rv.disabled= true;
|
||||
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
namespace exports
|
||||
{
|
||||
struct TestFailureException;
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
[[nodiscard]] inline auto
|
||||
operator""_test( const char name[], std::size_t amount )
|
||||
{
|
||||
return TestName{ std::string{ name, name + amount } };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline auto &
|
||||
registry()
|
||||
{
|
||||
static std::vector< std::tuple< std::string, bool, std::function< void() > > > registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
// It is okay to discard this, if making tests in an enroll block.
|
||||
inline auto
|
||||
operator <= ( TestName name, std::function< void () > test )
|
||||
{
|
||||
struct TestRegistration {} rv;
|
||||
|
||||
registry().emplace_back( name.name, name.disabled, test );
|
||||
assert( not registry().empty() );
|
||||
assert( std::get< 1 >( registry().back() ) == name.disabled );
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
||||
struct exports::TestFailureException
|
||||
{
|
||||
int failureCount= -1;
|
||||
};
|
||||
|
||||
inline auto
|
||||
operator <= ( TestName name, std::function< int () > test )
|
||||
{
|
||||
auto wrapper= [test]
|
||||
{
|
||||
const int failures= test();
|
||||
if( failures > 0 ) throw TestFailureException{ failures };
|
||||
};
|
||||
|
||||
return name <= wrapper;
|
||||
}
|
||||
|
||||
template< typename TestFunc >
|
||||
inline auto
|
||||
operator <= ( TestName name, TestFunc test )
|
||||
{
|
||||
return name <= std::function{ test };
|
||||
}
|
||||
|
||||
namespace exports
|
||||
{
|
||||
[[nodiscard]] inline int
|
||||
runAllTests( const std::vector< std::string > selections= {} )
|
||||
{
|
||||
bool failed= false;
|
||||
const auto selected= [ selections ]( const std::string test )
|
||||
{
|
||||
for( const auto &selection: selections )
|
||||
{
|
||||
if( test.find( selection ) != std::string::npos ) return true;
|
||||
}
|
||||
return empty( selections );
|
||||
};
|
||||
|
||||
const auto explicitlyNamed= [ selections ]( const std::string s )
|
||||
{
|
||||
return std::find( begin( selections ), end( selections ), s ) != end( selections );
|
||||
};
|
||||
|
||||
for( const auto &[ name, disabled, test ]: registry() )
|
||||
try
|
||||
{
|
||||
if( explicitlyNamed( name ) or not disabled and selected( name ) )
|
||||
{
|
||||
test();
|
||||
std::cout << C::green << "SUCCESS" << C::normal << ": " << name << std::endl;
|
||||
}
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
try
|
||||
{
|
||||
failed= true;
|
||||
std::cout << C::red << "FAILURE" << C::normal << ": " << name;
|
||||
throw;
|
||||
}
|
||||
catch( const TestFailureException &fail ) { std::cout << " -- " << fail.failureCount << " failures."; }
|
||||
catch( ... ) { std::cout << " -- unknown failure count"; }
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return failed ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline int
|
||||
runAllTests( const unsigned argcnt, const char *const *const argvec )
|
||||
{
|
||||
return runAllTests( { argvec + 1, argvec + argcnt } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace exports::testing
|
||||
{
|
||||
using namespace detail::testing::exports;
|
||||
}
|
||||
}
|
48
Utility/evaluation.h
Normal file
48
Utility/evaluation.h
Normal file
@ -0,0 +1,48 @@
|
||||
static_assert( __cplusplus > 201700, "C++17 Required" );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace Alepha::Hydrogen::Utility
|
||||
{
|
||||
inline namespace exports { inline namespace evaluation {} }
|
||||
|
||||
namespace detail::evaluation
|
||||
{
|
||||
struct evaluate_t {};
|
||||
struct enroll_t {};
|
||||
|
||||
inline namespace exports
|
||||
{
|
||||
inline constexpr evaluate_t evaluate;
|
||||
inline constexpr enroll_t enroll;
|
||||
}
|
||||
|
||||
template< typename Function >
|
||||
decltype( auto )
|
||||
operator <=( evaluate_t, Function &&init )
|
||||
{
|
||||
return std::forward< Function >( init )();
|
||||
}
|
||||
|
||||
template< typename Init >
|
||||
auto
|
||||
operator <=( enroll_t, Init init )
|
||||
{
|
||||
struct {} registration;
|
||||
|
||||
(void) ( evaluate <=init );
|
||||
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
|
||||
namespace exports::evaluation
|
||||
{
|
||||
using namespace detail::evaluation::exports;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user