From cab6a4daba4cf235d745195dc8f1e527d829a645 Mon Sep 17 00:00:00 2001 From: ryouze <98982999+ryouze@users.noreply.github.com> Date: Mon, 23 Sep 2024 18:02:25 +0200 Subject: [PATCH] Move repeating code to "helpers.hpp". --- tests/helpers.hpp | 129 +++++++++++++++++++++++++++++++++++ tests/test_all.cpp | 165 ++++++++++----------------------------------- 2 files changed, 163 insertions(+), 131 deletions(-) create mode 100644 tests/helpers.hpp diff --git a/tests/helpers.hpp b/tests/helpers.hpp new file mode 100644 index 0000000..c5cb00a --- /dev/null +++ b/tests/helpers.hpp @@ -0,0 +1,129 @@ +/** + * @file helpers.hpp + * + * @brief Helper functions for automated tests. + */ + +#pragma once + +#include // for std::filesystem +#include // for std::vector + +namespace helpers { + +/** + * @brief Class that represents a temporary directory as a RAII object. + * + * On construction, the class creates a temporary directory on disk. When the object goes out of scope, the directory is removed recursively from disk. + * + * @note This class is marked as `final` to prevent inheritance. + */ +class TempDir final { + public: + /** + * @brief Construct a new TempDir object. + * + * @param directory Path to the temporary directory (e.g., "~/data"). + */ + inline explicit TempDir(const std::filesystem::path &directory) + : directory_(directory) + { + std::filesystem::remove_all(this->directory_); + std::filesystem::create_directories(this->directory_); + } + + /** + * @brief Destroy the TempDir object. + * + * On destruction, the temporary directory is removed recursively from disk. + */ + inline ~TempDir() + { + std::filesystem::remove_all(this->directory_); + } + + /** + * @brief Get the path to the temporary directory. + * + * @return Const reference to a path to the temporary directory provided in the constructor (e.g., "~/data"). + */ + [[nodiscard]] inline const std::filesystem::path &get() const + { + return this->directory_; + } + + private: + /** + * @brief Path to the temporary directory provided in the constructor (e.g., "~/data"). + */ + const std::filesystem::path directory_; +}; + +// Compare and print functions +[[nodiscard]] inline bool compare_and_print_bare_includes(const std::vector &program, + const std::vector &expected) +{ + if (program != expected) { + fmt::print(stderr, "Bare include test failed.\nExpected:\n"); + for (const auto &entry : expected) { + fmt::print(stderr, " Line '{}': '{}', Include: '{}'\n", entry.number, entry.text, entry.header); + } + fmt::print(stderr, "Actual:\n"); + for (const auto &entry : program) { + fmt::print(stderr, " Line '{}': '{}', Include: '{}'\n", entry.number, entry.text, entry.header); + } + return false; + } + + fmt::print(stderr, "Bare include test succeeded.\n"); + for (const auto &entry : program) { + fmt::print(stderr, " Line '{}': '{}', Include: '{}'\n", entry.number, entry.text, entry.header); + } + return true; +} + +[[nodiscard]] inline bool compare_and_print_unused_functions(const std::vector &program, + const std::vector &expected) +{ + if (program != expected) { + fmt::print(stderr, "Unused functions test failed.\nExpected:\n"); + for (const auto &entry : expected) { + fmt::print(stderr, " Line '{}': '{}', Unused Functions: '{}'\n", entry.number, entry.text, fmt::join(entry.unused_functions, ", ")); + } + fmt::print(stderr, "Actual:\n"); + for (const auto &entry : program) { + fmt::print(stderr, " Line '{}': '{}', Unused Functions: '{}'\n", entry.number, entry.text, fmt::join(entry.unused_functions, ", ")); + } + return false; + } + + fmt::print(stderr, "Unused functions test succeeded.\n"); + for (const auto &entry : program) { + fmt::print(stderr, " Line '{}': '{}', Unused Functions: '{}'\n", entry.number, entry.text, fmt::join(entry.unused_functions, ", ")); + } + return true; +} + +[[nodiscard]] inline bool compare_and_print_unlisted_functions(const std::vector &program, + const std::vector &expected) +{ + if (program != expected) { + fmt::print(stderr, "Unlisted functions test failed.\nExpected:\n"); + for (const auto &entry : expected) { + fmt::print(stderr, " Line '{}': '{}', Function: '{}', Link: '{}'\n", entry.number, entry.text, entry.function, entry.link); + } + fmt::print(stderr, "Actual:\n"); + for (const auto &entry : program) { + fmt::print(stderr, " Line '{}': '{}', Function: '{}', Link: '{}'\n", entry.number, entry.text, entry.function, entry.link); + } + return false; + } + + fmt::print(stderr, "Unlisted functions test succeeded.\n"); + for (const auto &entry : program) { + fmt::print(stderr, " Line '{}': '{}', Function: '{}', Link: '{}'\n", entry.number, entry.text, entry.function, entry.link); + } + return true; +} + +} // namespace helpers diff --git a/tests/test_all.cpp b/tests/test_all.cpp index 9c20640..24df3ec 100644 --- a/tests/test_all.cpp +++ b/tests/test_all.cpp @@ -23,9 +23,11 @@ #include "app.hpp" #include "core/args.hpp" -#include "examples.hpp" #include "modules/analyze.hpp" +#include "examples.hpp" +#include "helpers.hpp" + #define TEST_EXECUTABLE_NAME "tests" namespace test_args { @@ -147,43 +149,15 @@ int test_args::invalid() } } -namespace { - -// RAII class to create a temporary directory -class TempDir { - public: - explicit TempDir(const std::filesystem::path &directory) - : directory_(directory) - { - std::filesystem::remove_all(this->directory_); - std::filesystem::create_directories(this->directory_); - } - - ~TempDir() - { - std::filesystem::remove_all(this->directory_); - } - - const std::filesystem::path &get_directory() const - { - return this->directory_; - } - - private: - const std::filesystem::path directory_; -}; - -} // namespace - int test_args::paths() { try { // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Two dummy CPP files - const auto temp_file1 = temp_dir.get_directory() / "example1.cpp"; - const auto temp_file2 = temp_dir.get_directory() / "example2.cpp"; + const auto temp_file1 = temp_dir.get() / "example1.cpp"; + const auto temp_file2 = temp_dir.get() / "example2.cpp"; // Write to the files { @@ -195,7 +169,7 @@ int test_args::paths() } // Store the string representation of the directory path - const std::string dir_path_str = temp_dir.get_directory().string(); + const std::string dir_path_str = temp_dir.get().string(); const char *fake_argv[] = {TEST_EXECUTABLE_NAME, dir_path_str.c_str()}; const core::args::Args args(2, const_cast(fake_argv)); @@ -221,85 +195,14 @@ int test_args::paths() } } -namespace { - -// Compare and print functions -[[nodiscard]] bool compare_and_print_bare_includes(const std::vector &program, - const std::vector &expected) -{ - if (program != expected) { - fmt::print(stderr, "Bare include test failed.\nExpected:\n"); - for (const auto &entry : expected) { - fmt::print(stderr, " Line '{}': '{}', Include: '{}'\n", entry.number, entry.text, entry.header); - } - fmt::print(stderr, "Actual:\n"); - for (const auto &entry : program) { - fmt::print(stderr, " Line '{}': '{}', Include: '{}'\n", entry.number, entry.text, entry.header); - } - return false; - } - - fmt::print(stderr, "Bare include test succeeded.\n"); - for (const auto &entry : program) { - fmt::print(stderr, " Line '{}': '{}', Include: '{}'\n", entry.number, entry.text, entry.header); - } - return true; -} - -[[nodiscard]] bool compare_and_print_unused_functions(const std::vector &program, - const std::vector &expected) -{ - if (program != expected) { - fmt::print(stderr, "Unused functions test failed.\nExpected:\n"); - for (const auto &entry : expected) { - fmt::print(stderr, " Line '{}': '{}', Unused Functions: '{}'\n", entry.number, entry.text, fmt::join(entry.unused_functions, ", ")); - } - fmt::print(stderr, "Actual:\n"); - for (const auto &entry : program) { - fmt::print(stderr, " Line '{}': '{}', Unused Functions: '{}'\n", entry.number, entry.text, fmt::join(entry.unused_functions, ", ")); - } - return false; - } - - fmt::print(stderr, "Unused functions test succeeded.\n"); - for (const auto &entry : program) { - fmt::print(stderr, " Line '{}': '{}', Unused Functions: '{}'\n", entry.number, entry.text, fmt::join(entry.unused_functions, ", ")); - } - return true; -} - -[[nodiscard]] bool compare_and_print_unlisted_functions(const std::vector &program, - const std::vector &expected) -{ - if (program != expected) { - fmt::print(stderr, "Unlisted functions test failed.\nExpected:\n"); - for (const auto &entry : expected) { - fmt::print(stderr, " Line '{}': '{}', Function: '{}', Link: '{}'\n", entry.number, entry.text, entry.function, entry.link); - } - fmt::print(stderr, "Actual:\n"); - for (const auto &entry : program) { - fmt::print(stderr, " Line '{}': '{}', Function: '{}', Link: '{}'\n", entry.number, entry.text, entry.function, entry.link); - } - return false; - } - - fmt::print(stderr, "Unlisted functions test succeeded.\n"); - for (const auto &entry : program) { - fmt::print(stderr, " Line '{}': '{}', Function: '{}', Link: '{}'\n", entry.number, entry.text, entry.function, entry.link); - } - return true; -} - -} // namespace - int test_analyze::analyze_badly_formatted() { try { // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Create a temporary file with badly formatted code - const auto temp_file = temp_dir.get_directory() / "badly_formatted.cpp"; + const auto temp_file = temp_dir.get() / "badly_formatted.cpp"; { std::ofstream f(temp_file); f << examples::badly_formatted; @@ -322,17 +225,17 @@ int test_analyze::analyze_badly_formatted() modules::analyze::CodeParser parser(temp_file.string()); // Compare bare includes - if (!compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { + if (!helpers::compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { throw std::runtime_error("Bare include test failed."); } // Compare unused functions - if (!compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { + if (!helpers::compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { throw std::runtime_error("Unused functions test failed."); } // Compare unlisted functions - if (!compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { + if (!helpers::compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { throw std::runtime_error("Unlisted functions test failed."); } @@ -349,10 +252,10 @@ int test_analyze::analyze_no_issues() { try { // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Create a temporary file with analyze_no_issues code - const auto temp_file = temp_dir.get_directory() / "no_issues.cpp"; + const auto temp_file = temp_dir.get() / "no_issues.cpp"; { std::ofstream f(temp_file); f << examples::no_issues; @@ -367,17 +270,17 @@ int test_analyze::analyze_no_issues() modules::analyze::CodeParser parser(temp_file.string()); // Compare bare includes - if (!compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { + if (!helpers::compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { throw std::runtime_error("Bare include test failed."); } // Compare unused functions - if (!compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { + if (!helpers::compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { throw std::runtime_error("Unused functions test failed."); } // Compare unlisted functions - if (!compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { + if (!helpers::compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { throw std::runtime_error("Unlisted functions test failed."); } @@ -394,10 +297,10 @@ int test_analyze::analyze_bare() { try { // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Create a temporary file with analyze_no_issues code - const auto temp_file = temp_dir.get_directory() / "bare.cpp"; + const auto temp_file = temp_dir.get() / "bare.cpp"; { std::ofstream f(temp_file); f << examples::bare; @@ -415,17 +318,17 @@ int test_analyze::analyze_bare() modules::analyze::CodeParser parser(temp_file.string()); // Compare bare includes - if (!compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { + if (!helpers::compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { throw std::runtime_error("Bare include test failed."); } // Compare unused functions - if (!compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { + if (!helpers::compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { throw std::runtime_error("Unused functions test failed."); } // Compare unlisted functions - if (!compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { + if (!helpers::compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { throw std::runtime_error("Unlisted functions test failed."); } @@ -442,10 +345,10 @@ int test_analyze::analyze_unused() { try { // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Create a temporary file with analyze_no_issues code - const auto temp_file = temp_dir.get_directory() / "unused.cpp"; + const auto temp_file = temp_dir.get() / "unused.cpp"; { std::ofstream f(temp_file); f << examples::unused; @@ -465,17 +368,17 @@ int test_analyze::analyze_unused() modules::analyze::CodeParser parser(temp_file.string()); // Compare bare includes - if (!compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { + if (!helpers::compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { throw std::runtime_error("Bare include test failed."); } // Compare unused functions - if (!compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { + if (!helpers::compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { throw std::runtime_error("Unused functions test failed."); } // Compare unlisted functions - if (!compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { + if (!helpers::compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { throw std::runtime_error("Unlisted functions test failed."); } @@ -492,10 +395,10 @@ int test_analyze::analyze_unlisted() { try { // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Create a temporary file with analyze_unlisted code - const auto temp_file = temp_dir.get_directory() / "unlisted.cpp"; + const auto temp_file = temp_dir.get() / "unlisted.cpp"; { std::ofstream f(temp_file); f << examples::unlisted; @@ -513,17 +416,17 @@ int test_analyze::analyze_unlisted() modules::analyze::CodeParser parser(temp_file.string()); // Compare bare includes - if (!compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { + if (!helpers::compare_and_print_bare_includes(parser.get_bare_includes(), expected_bare_includes)) { throw std::runtime_error("Bare include test failed."); } // Compare unused functions - if (!compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { + if (!helpers::compare_and_print_unused_functions(parser.get_unused_functions(), expected_unused_functions)) { throw std::runtime_error("Unused functions test failed."); } // Compare unlisted functions - if (!compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { + if (!helpers::compare_and_print_unlisted_functions(parser.get_unlisted_functions(), expected_unlisted_functions)) { throw std::runtime_error("Unlisted functions test failed."); } @@ -542,10 +445,10 @@ int test_app::paths() // Create fake files and run the app // Create a temporary directory using RAII - const TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); + const helpers::TempDir temp_dir(std::filesystem::temp_directory_path() / TEST_EXECUTABLE_NAME); // Create a temporary file with analyze_unlisted code - const auto temp_file = temp_dir.get_directory() / "paths.cpp"; + const auto temp_file = temp_dir.get() / "paths.cpp"; { std::ofstream f(temp_file); f << examples::unlisted;