Add missing virtual distructors
This commit is contained in:
		| @@ -9,9 +9,6 @@ find_package(Boost COMPONENTS program_options REQUIRED) | |||||||
| find_package(FLEX) | find_package(FLEX) | ||||||
| include_directories(${Boost_INCLUDE_DIR}) | 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) | FLEX_TARGET(scanner source/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp) | ||||||
|  |  | ||||||
| add_executable(elna cli/main.cpp | add_executable(elna cli/main.cpp | ||||||
|   | |||||||
| @@ -153,6 +153,7 @@ namespace elna::source | |||||||
|         explicit node(const position position); |         explicit node(const position position); | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|  |         virtual ~node() noexcept = default; | ||||||
|         virtual void accept(parser_visitor *) = 0; |         virtual void accept(parser_visitor *) = 0; | ||||||
|  |  | ||||||
|         /** |         /** | ||||||
|   | |||||||
| @@ -41,6 +41,8 @@ namespace elna::source | |||||||
|         error(const std::filesystem::path& path, const position position); |         error(const std::filesystem::path& path, const position position); | ||||||
|  |  | ||||||
|     public: |     public: | ||||||
|  |         virtual ~error() noexcept = default; | ||||||
|  |  | ||||||
|         /// Error text. |         /// Error text. | ||||||
|         virtual std::string what() const = 0; |         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() |     void intermediate_code::clear() | ||||||
|     { |     { | ||||||
|         this->instructions.clear(); |         this->instructions.clear(); | ||||||
|         std::uint32_t variable_counter = 1; |         this->m_variable_counter = 1; | ||||||
|         std::uint32_t label_counter = 0; |         this->m_label_counter = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     std::vector<quadruple>::iterator intermediate_code::begin() |     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) { | async function runInDirectory (directoryPath) { | ||||||
|   const testSources = await glob(path.join(directoryPath, '*.eln')) |  | ||||||
|   let failed = 0 |   let failed = 0 | ||||||
|  |  | ||||||
|   for (const testEntry of testSources) { |   for (const testEntry of await glob(path.join(directoryPath, '*.eln'))) { | ||||||
|     console.log(`Compiling ${path.basename(testEntry)}.`) |  | ||||||
|  |  | ||||||
|     const parsedPath = path.parse(testEntry) |     const parsedPath = path.parse(testEntry) | ||||||
|  |  | ||||||
|  |     console.log(`Compiling ${parsedPath.base}.`) | ||||||
|     const buildResult = await compileTest(parsedPath) |     const buildResult = await compileTest(parsedPath) | ||||||
|  |  | ||||||
|     if (buildResult.output !== '') { |     if (buildResult.code !== 0) { | ||||||
|       if (!(await checkFailure(parsedPath, buildResult))) { |       if (!(await checkFailure(parsedPath, buildResult))) { | ||||||
|         ++failed |         ++failed | ||||||
|       } |       } | ||||||
| @@ -120,7 +119,7 @@ async function runInDirectory (directoryPath) { | |||||||
|   await runVM(cpioImage) |   await runVM(cpioImage) | ||||||
|  |  | ||||||
|   return { |   return { | ||||||
|     total: testSources.length, |     total: (await glob(path.join(directoryPath, 'failures/*'))).length, | ||||||
|     failed, |     failed, | ||||||
|  |  | ||||||
|     passed () { |     passed () { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user