#include #include #include #include "elna/tester.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 int exit_code) noexcept { ++m_total; if (exit_code == 0) { ++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 int build_test(const std::filesystem::directory_entry& test_entry) { const std::filesystem::path test_filename = test_entry.path().filename(); std::filesystem::path test_binary = in_build_directory(test_filename); std::filesystem::path test_object = test_binary; test_binary.replace_extension(); test_object.replace_extension(".o"); std::filesystem::remove(test_binary); std::filesystem::remove(test_object); auto status = boost::process::system("./build/bin/elna", "-o", test_object.string(), test_entry.path().string()); if (status != 0) { return status; } status = boost::process::system( "/opt/riscv/bin/riscv32-unknown-elf-ld", "-o", test_binary.string(), "-L/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/", "-L/opt/riscv/riscv32-unknown-elf/lib", "/opt/riscv/riscv32-unknown-elf/lib/crt0.o", "/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/crtbegin.o", test_object.string(), "--start-group", "-lgcc", "-lc", "-lgloss", "--end-group", "/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/crtend.o" ); return status; } static int run_test(const std::filesystem::directory_entry& test_entry) { const std::filesystem::path test_filename = test_entry.path().filename(); std::filesystem::path test_binary = in_build_directory(test_filename); test_binary.replace_extension(); std::filesystem::path expectation_path = test_entry.path().parent_path() / "expectations" / test_filename; expectation_path.replace_extension(".txt"); std::cout << "Running " << test_binary << std::endl; boost::process::pipe pipe_stream; boost::process::child vm( "/opt/riscv/bin/spike", "--isa=RV32IMAC", "/opt/riscv/riscv32-unknown-elf/bin/pk", test_binary.string(), boost::process::std_out > pipe_stream ); boost::process::child diff( "/usr/bin/diff", "-Nur", "--color", expectation_path.string(), "-", boost::process::std_in < pipe_stream ); vm.wait(); diff.wait(); return diff.exit_code(); } static test_results run_in_path(const std::filesystem::path test_directory) { test_results results; for (const auto& test_entry : std::filesystem::directory_iterator(test_directory)) { if (test_entry.path().extension() != ".eln" || !test_entry.is_regular_file()) { continue; } int status{ 0 }; try { status = build_test(test_entry); } catch (const boost::process::process_error& exception) { std::cout << exception.what() << std::endl; status = 3; continue; } if (status == 0) { status = run_test(test_entry); } results.add_exit_code(status); } return results; } }; int main() { std::filesystem::create_directory(elna::in_build_directory()); 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(); }