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