144 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #pragma once
 | |
| 
 | |
| #include <concepts>
 | |
| #include <test/expects.hpp>
 | |
| 
 | |
| namespace lt::test {
 | |
| 
 | |
| namespace details {
 | |
| 
 | |
| class Registry
 | |
| {
 | |
| public:
 | |
| 	using FuzzFunction = int32_t (*)(const uint8_t *, size_t);
 | |
| 	using SuiteFunction = void (*)();
 | |
| 
 | |
| 	static void register_suite(SuiteFunction suite)
 | |
| 	{
 | |
| 		instance().m_suites.emplace_back(suite);
 | |
| 	}
 | |
| 
 | |
| 	static void register_fuzz_harness(FuzzFunction suite)
 | |
| 	{
 | |
| 		if (instance().m_fuzz_harness)
 | |
| 		{
 | |
| 			throw std::logic_error {
 | |
| 				"Attempting to register fuzz harness while one is already registered",
 | |
| 			};
 | |
| 		}
 | |
| 
 | |
| 		instance().m_fuzz_harness = suite;
 | |
| 	}
 | |
| 
 | |
| 	static auto run_all() -> int32_t
 | |
| 	{
 | |
| 		for (auto &test : instance().m_suites)
 | |
| 		{
 | |
| 			test();
 | |
| 		}
 | |
| 
 | |
| 		std::cout << "Ran " << instance().m_failed_count + instance().m_pasesed_count << " tests:\n"
 | |
| 		          << "\tpassed: " << instance().m_pasesed_count << '\n'
 | |
| 		          << "\tfailed: " << instance().m_failed_count << '\n';
 | |
| 		std::cout << "________________________________________________________________\n\n\n";
 | |
| 
 | |
| 		return instance().m_failed_count;
 | |
| 	}
 | |
| 
 | |
| 	static auto process_fuzz_input(const uint8_t *data, size_t size) -> int32_t
 | |
| 	{
 | |
| 		if (!instance().m_fuzz_harness)
 | |
| 		{
 | |
| 			throw std::logic_error {
 | |
| 				"Attempting to process fuzz input with no active harness",
 | |
| 			};
 | |
| 		}
 | |
| 
 | |
| 		return instance().m_fuzz_harness(data, size);
 | |
| 	}
 | |
| 
 | |
| 	static void increment_passed_count()
 | |
| 	{
 | |
| 		++instance().m_pasesed_count;
 | |
| 	}
 | |
| 
 | |
| 	static void increment_failed_count()
 | |
| 	{
 | |
| 		++instance().m_failed_count;
 | |
| 	}
 | |
| 
 | |
| private:
 | |
| 	Registry()
 | |
| 	{
 | |
| 		std::cout << "________________________________________________________________\n";
 | |
| 	}
 | |
| 
 | |
| 	[[nodiscard]] static auto instance() -> Registry &
 | |
| 	{
 | |
| 		static auto registry = Registry {};
 | |
| 		return registry;
 | |
| 	}
 | |
| 
 | |
| 	std::vector<SuiteFunction> m_suites;
 | |
| 
 | |
| 	FuzzFunction m_fuzz_harness {};
 | |
| 
 | |
| 	int32_t m_pasesed_count {};
 | |
| 	int32_t m_failed_count {};
 | |
| };
 | |
| 
 | |
| 
 | |
| } // namespace details
 | |
| 
 | |
| struct Case
 | |
| {
 | |
| 	auto operator=(std::invocable auto test) -> void // NOLINT
 | |
| 	{
 | |
| 		std::cout << "[Running-----------] --> ";
 | |
| 		std::cout << name << '\n';
 | |
| 
 | |
| 		try
 | |
| 		{
 | |
| 			test();
 | |
| 		}
 | |
| 		catch (const std::exception &exp)
 | |
| 		{
 | |
| 			std::cout << exp.what() << "\n";
 | |
| 			std::cout << "[-----------FAIL !!]" << "\n\n";
 | |
| 			details::Registry::increment_failed_count();
 | |
| 			return; // TODO(Light): Should we run the remaining tests after a failure?
 | |
| 		}
 | |
| 
 | |
| 		details::Registry::increment_passed_count();
 | |
| 		std::cout << "[--------SUCCESS :D]" << "\n\n";
 | |
| 	}
 | |
| 
 | |
| 	std::string_view name;
 | |
| };
 | |
| 
 | |
| struct TestSuite
 | |
| {
 | |
| 	template<class TSuite>
 | |
| 	constexpr TestSuite(TSuite body)
 | |
| 	{
 | |
| #ifndef LIGHT_SKIP_TESTS
 | |
| 		details::Registry::register_suite(+body);
 | |
| #endif
 | |
| 	}
 | |
| };
 | |
| 
 | |
| struct TestFuzzHarness
 | |
| {
 | |
| 	template<class TestFuzzHarnessBody>
 | |
| 	constexpr TestFuzzHarness(TestFuzzHarnessBody body)
 | |
| 	{
 | |
| #ifndef LIGHT_SKIP_FUZZ_TESTS
 | |
| 		details::Registry::register_fuzz_harness(+body);
 | |
| #endif
 | |
| 	}
 | |
| };
 | |
| 
 | |
| using Suite = const TestSuite;
 | |
| using FuzzHarness = const TestFuzzHarness;
 | |
| 
 | |
| } // namespace lt::test
 |