Add missing virtual distructors
This commit is contained in:
		| @@ -9,9 +9,6 @@ find_package(Boost COMPONENTS program_options REQUIRED) | ||||
| find_package(FLEX) | ||||
| include_directories(${Boost_INCLUDE_DIR}) | ||||
|  | ||||
| add_executable(tester tests/tester.cpp include/elna/tester.hpp) | ||||
| target_include_directories(tester PRIVATE include) | ||||
|  | ||||
| FLEX_TARGET(scanner source/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp) | ||||
|  | ||||
| add_executable(elna cli/main.cpp | ||||
|   | ||||
| @@ -153,6 +153,7 @@ namespace elna::source | ||||
|         explicit node(const position position); | ||||
|  | ||||
|     public: | ||||
|         virtual ~node() noexcept = default; | ||||
|         virtual void accept(parser_visitor *) = 0; | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -41,6 +41,8 @@ namespace elna::source | ||||
|         error(const std::filesystem::path& path, const position position); | ||||
|  | ||||
|     public: | ||||
|         virtual ~error() noexcept = default; | ||||
|  | ||||
|         /// Error text. | ||||
|         virtual std::string what() const = 0; | ||||
|  | ||||
|   | ||||
| @@ -1,44 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <filesystem> | ||||
|  | ||||
| #define BOOST_PROCESS_USE_STD_FS | ||||
|  | ||||
| #include <boost/asio.hpp> | ||||
| #include <boost/process.hpp> | ||||
| #include <boost/process/v2.hpp> | ||||
|  | ||||
| namespace elna | ||||
| { | ||||
|     enum class test_status | ||||
|     { | ||||
|         successful, | ||||
|         compile_failed, | ||||
|         expectation_failed, | ||||
|     }; | ||||
|  | ||||
|     class test_results final | ||||
|     { | ||||
|         std::uint32_t m_total{ 0 }; | ||||
|         std::uint32_t m_passed{ 0 }; | ||||
|  | ||||
|     public: | ||||
|         test_results() = default; | ||||
|  | ||||
|         std::uint32_t total() const noexcept; | ||||
|         std::uint32_t passed() const noexcept; | ||||
|         std::uint32_t failed() const noexcept; | ||||
|  | ||||
|         int exit_code() const noexcept; | ||||
|         void add_exit_code(const test_status result) noexcept; | ||||
|     }; | ||||
|  | ||||
|     boost::process::v2::process_stdio get_output_streams(const std::uint8_t stream_number, | ||||
|             boost::asio::readable_pipe& read_pipe); | ||||
|     int run_for_output(boost::asio::io_context& context, const std::uint8_t stream_number, | ||||
|             const std::filesystem::path& binary, std::initializer_list<boost::string_view> arguments); | ||||
|     test_status build_test(boost::asio::io_context& context, const std::filesystem::directory_entry& test_entry); | ||||
|     void run_test(boost::asio::io_context& context, const std::filesystem::path& test_entry); | ||||
|     void print_result(const std::filesystem::path& test_entry, const test_status& result); | ||||
| } | ||||
| @@ -43,8 +43,8 @@ namespace elna::source | ||||
|     void intermediate_code::clear() | ||||
|     { | ||||
|         this->instructions.clear(); | ||||
|         std::uint32_t variable_counter = 1; | ||||
|         std::uint32_t label_counter = 0; | ||||
|         this->m_variable_counter = 1; | ||||
|         this->m_label_counter = 0; | ||||
|     } | ||||
|  | ||||
|     std::vector<quadruple>::iterator intermediate_code::begin() | ||||
|   | ||||
							
								
								
									
										319
									
								
								tests/tester.cpp
									
									
									
									
									
								
							
							
						
						
									
										319
									
								
								tests/tester.cpp
									
									
									
									
									
								
							| @@ -1,319 +0,0 @@ | ||||
| #include "elna/tester.hpp" | ||||
|  | ||||
| #include <filesystem> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <boost/process/env.hpp> | ||||
|  | ||||
| namespace elna | ||||
| { | ||||
|     std::uint32_t test_results::total() const noexcept | ||||
|     { | ||||
|         return m_total; | ||||
|     } | ||||
|  | ||||
|     std::uint32_t test_results::passed() const noexcept | ||||
|     { | ||||
|         return m_passed; | ||||
|     } | ||||
|  | ||||
|     std::uint32_t test_results::failed() const noexcept | ||||
|     { | ||||
|         return m_total - m_passed; | ||||
|     } | ||||
|  | ||||
|     int test_results::exit_code() const noexcept | ||||
|     { | ||||
|         return m_total == m_passed ? EXIT_SUCCESS : EXIT_FAILURE; | ||||
|     } | ||||
|  | ||||
|     void test_results::add_exit_code(const test_status status) noexcept | ||||
|     { | ||||
|         ++m_total; | ||||
|         if (status == test_status::successful) | ||||
|         { | ||||
|             ++m_passed; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static std::filesystem::path in_build_directory() | ||||
|     { | ||||
|         return "build/riscv"; | ||||
|     } | ||||
|  | ||||
|     static std::string in_build_directory(const std::filesystem::path& path) | ||||
|     { | ||||
|         return in_build_directory() / path; | ||||
|     } | ||||
|  | ||||
|     static std::filesystem::path in_actual_directory() | ||||
|     { | ||||
|         return "build/tests"; | ||||
|     } | ||||
|  | ||||
|     static std::filesystem::path in_root_directory() | ||||
|     { | ||||
|         return "build/root"; | ||||
|     } | ||||
|  | ||||
|     static std::filesystem::path in_root_directory(const std::filesystem::path& path) | ||||
|     { | ||||
|         return in_root_directory() / path; | ||||
|     } | ||||
|  | ||||
|     boost::process::v2::process_stdio get_output_streams(const std::uint8_t stream_number, | ||||
|             boost::asio::readable_pipe& read_pipe) | ||||
|     { | ||||
|         if (stream_number == 1) | ||||
|         { | ||||
|             return boost::process::v2::process_stdio{ nullptr, read_pipe }; | ||||
|         } | ||||
|         if (stream_number == 2) | ||||
|         { | ||||
|             return boost::process::v2::process_stdio{ nullptr, {}, read_pipe }; | ||||
|         } | ||||
|         return boost::process::v2::process_stdio{ nullptr, read_pipe, read_pipe }; | ||||
|     } | ||||
|  | ||||
|     int run_for_output(boost::asio::io_context& context, const std::filesystem::path& log_path, | ||||
|             const std::filesystem::path& binary, std::initializer_list<boost::string_view> arguments) | ||||
|     { | ||||
|         boost::asio::readable_pipe read_pipe{ context }; | ||||
|         std::string output; | ||||
|         boost::asio::dynamic_string_buffer buffer = boost::asio::dynamic_buffer(output); | ||||
|         boost::system::error_code ec; | ||||
|  | ||||
|         boost::process::v2::process_stdio process_stdio; | ||||
|         boost::process::v2::process elna_child(context, binary, arguments, | ||||
|                 boost::process::v2::process_stdio{ nullptr, read_pipe, 1 }); | ||||
|         std::ofstream log_file{ log_path }; | ||||
|         do | ||||
|         { | ||||
|             std::size_t transferred = read_pipe.read_some(buffer.prepare(512), ec); | ||||
|  | ||||
|             if (transferred == 0) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             buffer.commit(transferred); | ||||
|             log_file.write(boost::asio::buffer_cast<const char *>(buffer.data()), buffer.size()); | ||||
|             buffer.consume(transferred); | ||||
|         } | ||||
|         while (ec == boost::system::errc::success); | ||||
|  | ||||
|         return elna_child.wait(); | ||||
|     } | ||||
|  | ||||
|     test_status build_test(boost::asio::io_context& context, const std::filesystem::directory_entry& test_entry) | ||||
|     { | ||||
|         const std::filesystem::path test_filename = test_entry.path().filename(); | ||||
|  | ||||
|         std::filesystem::path test_binary = in_root_directory("tests" / test_filename); | ||||
|         std::filesystem::path test_object = in_build_directory(test_filename); | ||||
|         std::filesystem::path test_log = in_build_directory(test_filename); | ||||
|         test_binary.replace_extension(); | ||||
|         test_object.replace_extension(".o"); | ||||
|         test_log.replace_extension(".log"); | ||||
|  | ||||
|         std::filesystem::remove(test_binary); | ||||
|         std::filesystem::remove(test_object); | ||||
|  | ||||
|         auto result_code = run_for_output(context, test_log, "./build/bin/elna", | ||||
|                 { "-o", test_object.string(), test_entry.path().string() }); | ||||
|         if (result_code != 0) | ||||
|         { | ||||
|             return test_status::compile_failed; | ||||
|         } | ||||
|         test_status result = result_code == 0 ? test_status::successful : test_status::compile_failed; | ||||
|         std::vector<std::filesystem::path> environment; | ||||
|         std::vector<std::string> linker_arguments = { "-o", test_binary.string() }; | ||||
|  | ||||
|         linker_arguments.push_back(test_object.string()); | ||||
|  | ||||
|         boost::process::v2::execute(boost::process::v2::process(context, boost::process::search_path("ld"), | ||||
|                     linker_arguments | ||||
|         )); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     static test_status check_expectation(const std::filesystem::path& expectation_path, | ||||
|             const std::filesystem::path& actual_directory) | ||||
|     { | ||||
|         std::filesystem::path log_filename = expectation_path.filename(); | ||||
|         log_filename.replace_extension(".log"); | ||||
|  | ||||
|         std::filesystem::path test_log = actual_directory / log_filename; | ||||
|  | ||||
|         test_log.replace_extension(".log"); | ||||
|         boost::process::child diff( | ||||
|                 boost::process::search_path("diff"), "-Nur", "--color", | ||||
|                 expectation_path, test_log | ||||
|         ); | ||||
|         diff.wait(); | ||||
|  | ||||
|         if (diff.exit_code() == 0) | ||||
|         { | ||||
|             return test_status::successful; | ||||
|         } | ||||
|         return test_status::expectation_failed; | ||||
|     } | ||||
|  | ||||
|     void run_test(boost::asio::io_context& context, const std::filesystem::path& test_binary) | ||||
|     { | ||||
|         std::filesystem::path test_log = test_binary; | ||||
|         test_log.replace_extension(".log"); | ||||
|  | ||||
|         run_for_output(context, test_log, boost::process::search_path("qemu-riscv32"), | ||||
|                 { test_binary.string() }); | ||||
|     } | ||||
|  | ||||
|     static void cpio_archive(boost::asio::io_context& context) | ||||
|     { | ||||
|         boost::asio::readable_pipe read_pipe{ context }; | ||||
|         boost::asio::writable_pipe write_pipe{ context }; | ||||
|         std::string output; | ||||
|         boost::asio::dynamic_string_buffer buffer = boost::asio::dynamic_buffer(output); | ||||
|         boost::system::error_code ec; | ||||
|         std::ofstream archive_output{ "build/root.cpio", std::ios::binary }; | ||||
|         boost::process::v2::process_stdio process_stdio; | ||||
|         auto current_path = std::filesystem::current_path(); | ||||
|  | ||||
|         std::filesystem::current_path(in_root_directory()); | ||||
|         boost::process::v2::process cpio_child(context, boost::process::search_path("cpio"), | ||||
|                 { "-o", "--format=newc" }, | ||||
|                 boost::process::v2::process_stdio{ write_pipe, read_pipe, nullptr }); | ||||
|  | ||||
|         for (const auto& entry : std::filesystem::recursive_directory_iterator(".")) | ||||
|         { | ||||
|             auto entry_path = entry.path().string() + "\n"; | ||||
|             auto entry_iterator = std::cbegin(entry_path); | ||||
|             std::size_t written{ 0 }; | ||||
|  | ||||
|             while (entry_iterator != std::cend(entry_path)) | ||||
|             { | ||||
|                 std::size_t written = write_pipe.write_some(boost::asio::buffer(entry_iterator.base(), | ||||
|                             std::distance(entry_iterator, std::cend(entry_path)))); | ||||
|                 std::advance(entry_iterator, written); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         write_pipe.close(); | ||||
|         do | ||||
|         { | ||||
|             std::size_t transferred = read_pipe.read_some(buffer.prepare(512), ec); | ||||
|  | ||||
|             if (transferred == 0) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             buffer.commit(transferred); | ||||
|             archive_output.write(boost::asio::buffer_cast<const char *>(buffer.data()), buffer.size()); | ||||
|             buffer.consume(transferred); | ||||
|         } | ||||
|         while (ec == boost::system::errc::success); | ||||
|  | ||||
|         std::filesystem::current_path(current_path); | ||||
|     } | ||||
|  | ||||
|     static void run_vm(boost::asio::io_context& context) | ||||
|     { | ||||
|         std::vector<std::string> arguments = { | ||||
|             "-nographic", | ||||
|             "-M", "virt", | ||||
|             "-bios", "default", | ||||
|             "-kernel", "build/tools/linux-5.15.159/arch/riscv/boot/Image", | ||||
|             "-append", "quiet", | ||||
|             "-initrd", "build/root.cpio" | ||||
|         }; | ||||
|         auto process = boost::process::v2::process(context, | ||||
|                 boost::process::search_path("qemu-system-riscv32"), arguments); | ||||
|         boost::process::v2::execute(std::move(process)); | ||||
|     } | ||||
|  | ||||
|     static void create_init() | ||||
|     { | ||||
|         std::filesystem::copy("build/tools/init", in_root_directory()); | ||||
|     } | ||||
|  | ||||
|     static test_results run_in_path(const std::filesystem::path test_directory) | ||||
|     { | ||||
|         test_results results; | ||||
|         boost::asio::io_context context; | ||||
|  | ||||
|         for (const auto& test_entry : std::filesystem::directory_iterator(test_directory)) | ||||
|         { | ||||
|             if (test_entry.path().extension() != ".eln" || !test_entry.is_regular_file()) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|             test_status result; | ||||
|  | ||||
|             std::cout << "Compiling " << test_entry << std::endl; | ||||
|             try | ||||
|             { | ||||
|                 build_test(context, test_entry); | ||||
|             } | ||||
|             catch (const boost::process::process_error& exception) | ||||
|             { | ||||
|                 std::cout << exception.what() << std::endl; | ||||
|             } | ||||
|         } | ||||
|         for (const auto& executable_test : std::filesystem::directory_iterator(in_build_directory())) | ||||
|         { | ||||
|             if (executable_test.path().has_extension()) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|             run_test(context, executable_test.path()); | ||||
|         } | ||||
|         for (const auto& expectation_entry : std::filesystem::directory_iterator(test_directory / "failures")) | ||||
|         { | ||||
|             auto test_entry = test_directory / expectation_entry.path().filename(); | ||||
|             test_entry.replace_extension(".eln"); | ||||
|             auto result = check_expectation(expectation_entry.path(), in_build_directory()); | ||||
|  | ||||
|             print_result(test_entry, result); | ||||
|             results.add_exit_code(result); | ||||
|         } | ||||
|         std::filesystem::copy(test_directory / "expectations", in_root_directory("expectations"), | ||||
|                 std::filesystem::copy_options::recursive); | ||||
|         create_init(); | ||||
|         cpio_archive(context); | ||||
|         run_vm(context); | ||||
|  | ||||
|         return results; | ||||
|     } | ||||
|  | ||||
|     void print_result(const std::filesystem::path& test_entry, const test_status& result) | ||||
|     { | ||||
|         if (result != test_status::successful) | ||||
|         { | ||||
|             std::cout << test_entry << " failed." << std::endl; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| int main() | ||||
| { | ||||
|     std::filesystem::create_directory(elna::in_build_directory()); | ||||
|     std::filesystem::create_directory(elna::in_actual_directory()); | ||||
|  | ||||
|     std::filesystem::remove_all(elna::in_root_directory()); | ||||
|     std::filesystem::create_directory(elna::in_root_directory()); | ||||
|     std::filesystem::create_directory(elna::in_root_directory("expectations")); | ||||
|     std::filesystem::create_directory(elna::in_root_directory("tests")); | ||||
|  | ||||
|     auto current_environment = boost::this_process::environment(); | ||||
|     current_environment["PATH"] += "./build/tools/sysroot/bin"; | ||||
|  | ||||
|     std::cout << "Run all tests and check the results" << std::endl; | ||||
|     std::filesystem::path test_directory{ "tests" }; | ||||
|     const auto results = elna::run_in_path(test_directory); | ||||
|  | ||||
|     std::cout << std::endl; | ||||
|     std::cout << results.total() << " tests run, " | ||||
|         << results.passed() << " passed, " | ||||
|         << results.failed() << " failed." << std::endl; | ||||
|  | ||||
|     return results.exit_code(); | ||||
| } | ||||
| @@ -96,16 +96,15 @@ async function runVM(cpioImage) { | ||||
| } | ||||
|  | ||||
| async function runInDirectory (directoryPath) { | ||||
|   const testSources = await glob(path.join(directoryPath, '*.eln')) | ||||
|   let failed = 0 | ||||
|  | ||||
|   for (const testEntry of testSources) { | ||||
|     console.log(`Compiling ${path.basename(testEntry)}.`) | ||||
|  | ||||
|   for (const testEntry of await glob(path.join(directoryPath, '*.eln'))) { | ||||
|     const parsedPath = path.parse(testEntry) | ||||
|  | ||||
|     console.log(`Compiling ${parsedPath.base}.`) | ||||
|     const buildResult = await compileTest(parsedPath) | ||||
|  | ||||
|     if (buildResult.output !== '') { | ||||
|     if (buildResult.code !== 0) { | ||||
|       if (!(await checkFailure(parsedPath, buildResult))) { | ||||
|         ++failed | ||||
|       } | ||||
| @@ -120,7 +119,7 @@ async function runInDirectory (directoryPath) { | ||||
|   await runVM(cpioImage) | ||||
|  | ||||
|   return { | ||||
|     total: testSources.length, | ||||
|     total: (await glob(path.join(directoryPath, 'failures/*'))).length, | ||||
|     failed, | ||||
|  | ||||
|     passed () { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user