| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2025 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | // GCOV_EXCL_START | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <filesystem> | ||
| 8 | #include <functional> | ||
| 9 | #include <string> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include <gtest/gtest.h> | ||
| 13 | |||
| 14 | namespace spice::testing { | ||
| 15 | |||
| 16 | const char *const PATH_TEST_FILES = "./test-files/"; | ||
| 17 | static constexpr unsigned int EXPECTED_NUMBER_OF_TESTS = 250; | ||
| 18 | const char *const GDB_READING_SYMBOLS_MESSAGE = "Reading symbols from "; | ||
| 19 | const char *const GDB_INFERIOR_MESSAGE = "[Inferior"; | ||
| 20 | |||
| 21 | const char *const INPUT_NAME_LINKER_FLAGS = "linker-flags.txt"; | ||
| 22 | const char *const INPUT_NAME_CLI_FLAGS = "cli-flags.txt"; | ||
| 23 | const char *const INPUT_NAME_SANITIZER = "sanitizer.txt"; | ||
| 24 | |||
| 25 | const char *const REF_NAME_SOURCE = "source.spice"; | ||
| 26 | const char *const REF_NAME_PARSE_TREE = "parse-tree.dot"; | ||
| 27 | const char *const REF_NAME_SYNTAX_TREE = "syntax-tree.dot"; | ||
| 28 | const char *const REF_NAME_DEP_GRAPH = "dependency-graph.dot"; | ||
| 29 | const char *const REF_NAME_SYMBOL_TABLE = "symbol-table.json"; | ||
| 30 | const char *const REF_NAME_TYPE_REGISTRY = "type-registry.out"; | ||
| 31 | const char *const REF_NAME_CACHE_STATS = "cache-stats.out"; | ||
| 32 | const char *const REF_NAME_IR = "ir-code.ll"; | ||
| 33 | const char *const REF_NAME_ASM = "assembly.asm"; | ||
| 34 | static constexpr const char *const REF_NAME_OPT_IR[6] = { | ||
| 35 | "ir-code.ll", "ir-code-O1.ll", "ir-code-O2.ll", "ir-code-O3.ll", "ir-code-Os.ll", "ir-code-Oz.ll", | ||
| 36 | }; | ||
| 37 | const char *const REF_NAME_EXECUTION_OUTPUT = "cout.out"; | ||
| 38 | const char *const REF_NAME_GDB_OUTPUT = "debug.out"; | ||
| 39 | const char *const REF_NAME_ERROR_OUTPUT = "exception.out"; | ||
| 40 | const char *const REF_NAME_WARNING_OUTPUT = "warning.out"; | ||
| 41 | const char *const REF_NAME_EXIT_CODE = "exit-code.out"; | ||
| 42 | |||
| 43 | const char *const CTL_SKIP_DISABLED = "disabled"; | ||
| 44 | const char *const CTL_SKIP_GH = "skip-gh-actions"; | ||
| 45 | const char *const CTL_SKIP_WINDOWS = "skip-windows"; | ||
| 46 | const char *const CTL_DEBUG_INFO = "with-debug-info"; | ||
| 47 | const char *const CTL_RUN_BUILTIN_TESTS = "run-builtin-tests"; | ||
| 48 | const char *const CTL_DEBUG_SCRIPT = "debug.gdb"; | ||
| 49 | const char *const CTL_LTO = "with-lto"; | ||
| 50 | |||
| 51 | |||
| 52 | struct TestCase { | ||
| 53 | const std::string testSuite; | ||
| 54 | const std::string testName; | ||
| 55 | const std::filesystem::path testPath; | ||
| 56 | }; | ||
| 57 | |||
| 58 | // Typedefs | ||
| 59 | typedef const std::function<std::string()> &GetOutputFct; | ||
| 60 | typedef const std::function<void(std::string &expectedOutput, std::string &actualOutput)> &ModifyOutputFct; | ||
| 61 | |||
| 62 | class TestUtil { | ||
| 63 | public: | ||
| 64 | // Public structs | ||
| 65 | struct NameResolver { | ||
| 66 | − | template <class T> std::string operator()(const ::testing::TestParamInfo<T> &info) const { | |
| 67 | − | T testCase = static_cast<T>(info.param); | |
| 68 | − | return TestUtil::toCamelCase(testCase.testSuite) + "_" + TestUtil::toCamelCase(testCase.testName); | |
| 69 | − | } | |
| 70 | }; | ||
| 71 | |||
| 72 | // Public static methods | ||
| 73 | static std::vector<TestCase> collectTestCases(const char *suiteName, bool useSubDirs); | ||
| 74 | static bool checkRefMatch( | ||
| 75 | const std::filesystem::path &originalRefPath, GetOutputFct getActualOutput, | ||
| 76 | − | ModifyOutputFct modifyOutputFct = [](std::string &, std::string &) {}, | |
| 77 | bool x86Only = false); | ||
| 78 | static bool doesRefExist(const std::filesystem::path &originalRefPath); | ||
| 79 | static void handleError(const TestCase &testCase, const std::exception &error); | ||
| 80 | static std::vector<std::string> getSubdirs(const std::filesystem::path &basePath); | ||
| 81 | static std::vector<std::string> getFileContentLinesVector(const std::filesystem::path &filePath); | ||
| 82 | static std::string toCamelCase(std::string input); | ||
| 83 | static consteval const char *getDefaultExecutableName() { | ||
| 84 | #if OS_WINDOWS | ||
| 85 | return ".\\source.exe"; | ||
| 86 | #else | ||
| 87 | return "./source"; | ||
| 88 | #endif | ||
| 89 | } | ||
| 90 | static bool isDisabled(const TestCase &testCase); | ||
| 91 | static void eraseGDBHeader(std::string &gdbOutput); | ||
| 92 | static void eraseLinesBySubstring(std::string &irCode, const char *needle); | ||
| 93 | |||
| 94 | private: | ||
| 95 | // Private methods | ||
| 96 | static std::array<std::filesystem::path, 3> expandRefPaths(const std::filesystem::path &refPath); | ||
| 97 | }; | ||
| 98 | |||
| 99 | } // namespace spice::testing | ||
| 100 | |||
| 101 | // GCOV_EXCL_STOP | ||
| 102 |