From 3d15a108af7b982ab6ff24d8ebe1e2f6b43a3e4d Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sat, 11 Sep 2021 23:13:49 +0200 Subject: [PATCH] tests: Added more tests --- tests/CMakeLists.txt | 9 +++- tests/include/test_patterns/test_pattern.hpp | 43 +++++++++++++-- .../test_patterns/test_pattern_enums.hpp | 38 +++++++++++++ .../test_patterns/test_pattern_example.hpp | 2 +- .../test_pattern_failing_assert.hpp | 26 +++++++++ .../test_patterns/test_pattern_literals.hpp | 32 +++++++++++ .../test_patterns/test_pattern_padding.hpp | 38 +++++++++++++ .../test_patterns/test_pattern_placement.hpp | 8 +-- .../test_patterns/test_pattern_structs.hpp | 36 +++++++++++++ .../test_pattern_succeeding_assert.hpp | 29 ++++++++++ .../test_patterns/test_pattern_unions.hpp | 36 +++++++++++++ tests/source/main.cpp | 54 +++++++++++++++---- tests/source/tests.cpp | 21 ++++++++ 13 files changed, 351 insertions(+), 21 deletions(-) create mode 100644 tests/include/test_patterns/test_pattern_enums.hpp create mode 100644 tests/include/test_patterns/test_pattern_failing_assert.hpp create mode 100644 tests/include/test_patterns/test_pattern_literals.hpp create mode 100644 tests/include/test_patterns/test_pattern_padding.hpp create mode 100644 tests/include/test_patterns/test_pattern_structs.hpp create mode 100644 tests/include/test_patterns/test_pattern_succeeding_assert.hpp create mode 100644 tests/include/test_patterns/test_pattern_unions.hpp create mode 100644 tests/source/tests.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bef40e19a..fc8db44fe 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,11 +6,18 @@ project(unit_tests) # Add new tests here # set(AVAILABLE_TESTS Placement + Structs + Unions + Enums + Literals + Padding + SucceedingAssert + FailingAssert ) -add_executable(unit_tests source/main.cpp) +add_executable(unit_tests source/main.cpp source/tests.cpp) target_include_directories(unit_tests PRIVATE include) target_link_libraries(unit_tests libimhex) diff --git a/tests/include/test_patterns/test_pattern.hpp b/tests/include/test_patterns/test_pattern.hpp index aa423b2ea..e8b767acc 100644 --- a/tests/include/test_patterns/test_pattern.hpp +++ b/tests/include/test_patterns/test_pattern.hpp @@ -5,18 +5,30 @@ #include +#define TEST(name) (hex::test::TestPattern*) new hex::test::TestPattern ## name () + namespace hex::test { + using namespace pl; + + enum class Mode { + Succeeding, + Failing + }; + class TestPattern { public: - TestPattern() = default; + explicit TestPattern(const std::string &name, Mode mode = Mode::Succeeding) : m_mode(mode) { + TestPattern::s_tests.insert({ name, this }); + } + virtual ~TestPattern() { for (auto &pattern : this->m_patterns) delete pattern; } template - static T* createVariablePattern(u64 offset, size_t size, const std::string &typeName, const std::string &varName) { + static T* create(u64 offset, size_t size, const std::string &typeName, const std::string &varName) { auto pattern = new T(offset, size); pattern->setTypeName(typeName); pattern->setVariableName(varName); @@ -24,16 +36,37 @@ namespace hex::test { return pattern; } + [[nodiscard]] virtual std::string getSourceCode() const = 0; [[nodiscard]] - virtual const std::vector& getPatterns() const final { return this->m_patterns; } - virtual void addPattern(pl::PatternData *pattern) final { + virtual const std::vector& getPatterns() const final { return this->m_patterns; } + virtual void addPattern(PatternData *pattern) final { this->m_patterns.push_back(pattern); } + [[nodiscard]] + auto failing() { + this->m_mode = Mode::Failing; + + return this; + } + + [[nodiscard]] + Mode getMode() { + return this->m_mode; + } + + [[nodiscard]] + static auto& getTests() { + return TestPattern::s_tests; + } + private: - std::vector m_patterns; + std::vector m_patterns; + Mode m_mode; + + static inline std::map s_tests; }; } \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_enums.hpp b/tests/include/test_patterns/test_pattern_enums.hpp new file mode 100644 index 000000000..2a8ff4b8e --- /dev/null +++ b/tests/include/test_patterns/test_pattern_enums.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternEnums : public TestPattern { + public: + TestPatternEnums() : TestPattern("Enums"){ + auto testEnum = create(0x120, sizeof(u32), "TestEnum", "testEnum"); + testEnum->setEnumValues({ + { s32(0x0000), "A" }, + { s32(0x1234), "B" }, + { s32(0x1235), "C" }, + { s32(0x1236), "D" }, + }); + + addPattern(testEnum); + } + ~TestPatternEnums() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + enum TestEnum : u32 { + A, + B = 0x1234, + C, + D + }; + + TestEnum testEnum @ 0x120; + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_example.hpp b/tests/include/test_patterns/test_pattern_example.hpp index 40d66695a..5adf8dae9 100644 --- a/tests/include/test_patterns/test_pattern_example.hpp +++ b/tests/include/test_patterns/test_pattern_example.hpp @@ -6,7 +6,7 @@ namespace hex::test { class TestPatternExample : public TestPattern { public: - TestPatternExample() { + TestPatternExample() : TestPattern("") { } ~TestPatternExample() override = default; diff --git a/tests/include/test_patterns/test_pattern_failing_assert.hpp b/tests/include/test_patterns/test_pattern_failing_assert.hpp new file mode 100644 index 000000000..1088ecdac --- /dev/null +++ b/tests/include/test_patterns/test_pattern_failing_assert.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternFailingAssert : public TestPattern { + public: + TestPatternFailingAssert() : TestPattern("FailingAssert", Mode::Failing) { + + } + ~TestPatternFailingAssert() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + #define MSG "Error" + + std::assert(false, MSG); + + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_literals.hpp b/tests/include/test_patterns/test_pattern_literals.hpp new file mode 100644 index 000000000..a1365b01e --- /dev/null +++ b/tests/include/test_patterns/test_pattern_literals.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternLiterals : public TestPattern { + public: + TestPatternLiterals() : TestPattern("Literals") { + + } + ~TestPatternLiterals() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + #define MSG "Invalid literal" + + std::assert(255 == 0xFF, MSG); + std::assert(0xAA == 0b10101010, MSG); + std::assert(12345 != 67890, MSG); + std::assert(100ULL == 0x64ULL, MSG); + std::assert(-100 == -0x64, MSG); + std::assert(3.14159F > 1.414D, MSG); + std::assert('A' == 0x41, MSG); + + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_padding.hpp b/tests/include/test_patterns/test_pattern_padding.hpp new file mode 100644 index 000000000..d64003c18 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_padding.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternPadding : public TestPattern { + public: + TestPatternPadding() : TestPattern("Padding") { + auto testStruct = create(0x100, sizeof(s32) + 20 + sizeof(u8[0x10]), "TestStruct", "testStruct"); + + auto variable = create(0x100, sizeof(s32), "s32", "variable"); + auto padding = create(0x100 + sizeof(s32), 20, "", ""); + auto array = create(0x100 + sizeof(s32) + 20, sizeof(u8[0x10]), "u8", "array"); + array->setEntries(create(0x100 + sizeof(s32) + 20, sizeof(u8), "u8", ""), 0x10); + + testStruct->setMembers({ variable, padding, array }); + + addPattern(testStruct); + } + ~TestPatternPadding() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + struct TestStruct { + s32 variable; + padding[20]; + u8 array[0x10]; + }; + + TestStruct testStruct @ 0x100; + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_placement.hpp b/tests/include/test_patterns/test_pattern_placement.hpp index a78c36202..d9bdddf4d 100644 --- a/tests/include/test_patterns/test_pattern_placement.hpp +++ b/tests/include/test_patterns/test_pattern_placement.hpp @@ -6,16 +6,16 @@ namespace hex::test { class TestPatternPlacement : public TestPattern { public: - TestPatternPlacement() { + TestPatternPlacement() : TestPattern("Placement") { // placementVar { - addPattern(createVariablePattern(0x00, sizeof(u32), "u32", "placementVar")); + addPattern(create(0x00, sizeof(u32), "u32", "placementVar")); } // placementArray { - auto placementArray = createVariablePattern(0x10, sizeof(u8) * 10, "u8", "placementArray"); - placementArray->setEntries(createVariablePattern(0x10, sizeof(u8), "u8", ""), 10); + auto placementArray = create(0x10, sizeof(u8) * 10, "u8", "placementArray"); + placementArray->setEntries(create(0x10, sizeof(u8), "u8", ""), 10); addPattern(placementArray); } diff --git a/tests/include/test_patterns/test_pattern_structs.hpp b/tests/include/test_patterns/test_pattern_structs.hpp new file mode 100644 index 000000000..221a7353e --- /dev/null +++ b/tests/include/test_patterns/test_pattern_structs.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternStructs : public TestPattern { + public: + TestPatternStructs() : TestPattern("Structs") { + auto testStruct = create(0x100, sizeof(s32) + sizeof(u8[0x10]), "TestStruct", "testStruct"); + + auto variable = create(0x100, sizeof(s32), "s32", "variable"); + auto array = create(0x100 + sizeof(s32), sizeof(u8[0x10]), "u8", "array"); + array->setEntries(create(0x100 + sizeof(s32), sizeof(u8), "u8", ""), 0x10); + + testStruct->setMembers({ variable, array }); + + addPattern(testStruct); + } + ~TestPatternStructs() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + struct TestStruct { + s32 variable; + u8 array[0x10]; + }; + + TestStruct testStruct @ 0x100; + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_succeeding_assert.hpp b/tests/include/test_patterns/test_pattern_succeeding_assert.hpp new file mode 100644 index 000000000..dc6d524f7 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_succeeding_assert.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternSucceedingAssert : public TestPattern { + public: + TestPatternSucceedingAssert() : TestPattern("SucceedingAssert") { + + } + ~TestPatternSucceedingAssert() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + #define MSG "Error" + + std::assert(true, MSG); + std::assert(100 == 100, MSG); + std::assert(50 < 100, MSG); + std::assert(1, MSG); + + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/include/test_patterns/test_pattern_unions.hpp b/tests/include/test_patterns/test_pattern_unions.hpp new file mode 100644 index 000000000..342eb6c99 --- /dev/null +++ b/tests/include/test_patterns/test_pattern_unions.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "test_pattern.hpp" + +namespace hex::test { + + class TestPatternUnions : public TestPattern { + public: + TestPatternUnions() : TestPattern("Unions") { + auto testUnion = create(0x200, sizeof(u128), "TestUnion", "testUnion"); + + auto array = create(0x200, sizeof(s32[2]), "s32", "array"); + array->setEntries(create(0x200, sizeof(s32), "s32", ""), 2); + auto variable = create(0x200, sizeof(u128), "u128", "variable"); + + testUnion->setMembers({ array, variable }); + + addPattern(testUnion); + } + ~TestPatternUnions() override = default; + + [[nodiscard]] + std::string getSourceCode() const override { + return R"( + union TestUnion { + s32 array[2]; + u128 variable; + }; + + TestUnion testUnion @ 0x200; + )"; + } + + }; + +} \ No newline at end of file diff --git a/tests/source/main.cpp b/tests/source/main.cpp index 62f8578ab..d50a48951 100644 --- a/tests/source/main.cpp +++ b/tests/source/main.cpp @@ -4,20 +4,34 @@ #include #include +#include #include +#include +#include +#include #include "test_provider.hpp" -#include "test_patterns/test_pattern_placement.hpp" +#include "test_patterns/test_pattern.hpp" using namespace hex::test; -static std::map testPatterns { - { "Placement", new TestPatternPlacement() } -}; +void addFunctions() { + hex::ContentRegistry::PatternLanguageFunctions::Namespace nsStd = { "std" }; + hex::ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](auto &ctx, auto params) { + auto condition = AS_TYPE(hex::pl::ASTNodeIntegerLiteral, params[0])->getValue(); + auto message = AS_TYPE(hex::pl::ASTNodeStringLiteral, params[1])->getString(); -int main(int argc, char **argv) { + if (LITERAL_COMPARE(condition, condition == 0)) + ctx.getConsole().abortEvaluation(hex::format("assertion failed \"{0}\"", message.data())); + + return nullptr; + }); +} + +int test(int argc, char **argv) { + auto &testPatterns = TestPattern::getTests(); ON_SCOPE_EXIT { - for (auto &[key, value] : testPatterns) + for (auto &[key, value] : TestPattern::getTests()) delete value; }; @@ -35,6 +49,7 @@ int main(int argc, char **argv) { } const auto &currTest = testPatterns[testName]; + bool failing = currTest->getMode() == Mode::Failing; auto provider = new TestProvider(); ON_SCOPE_EXIT { delete provider; }; @@ -44,14 +59,24 @@ int main(int argc, char **argv) { } hex::pl::PatternLanguage language; + addFunctions(); // Check if compilation succeeded auto patterns = language.executeString(provider, testPatterns[testName]->getSourceCode()); if (!patterns.has_value()) { hex::log::fatal("Error during compilation!"); - for (auto &[level, line] : language.getConsoleLog()) - hex::log::info("PL: {}", line); + if (auto error = language.getError(); error.has_value()) + hex::log::info("Compile error: {}:{}", error->first, error->second); + else + for (auto &[level, message] : language.getConsoleLog()) + hex::log::info("Evaluate error: {}", message); + + return failing ? EXIT_SUCCESS : EXIT_FAILURE; + } + + if (failing) { + hex::log::fatal("Failing test succeeded!"); return EXIT_FAILURE; } @@ -77,7 +102,16 @@ int main(int argc, char **argv) { } } - hex::log::info("Success!"); - return EXIT_SUCCESS; +} + +int main(int argc, char **argv) { + auto result = test(argc, argv); + + if (result == EXIT_SUCCESS) + hex::log::info("Success!"); + else + hex::log::info("Failed!"); + + return result; } \ No newline at end of file diff --git a/tests/source/tests.cpp b/tests/source/tests.cpp new file mode 100644 index 000000000..cf2cf5f64 --- /dev/null +++ b/tests/source/tests.cpp @@ -0,0 +1,21 @@ +#include + +#include "test_patterns/test_pattern_placement.hpp" +#include "test_patterns/test_pattern_structs.hpp" +#include "test_patterns/test_pattern_unions.hpp" +#include "test_patterns/test_pattern_enums.hpp" +#include "test_patterns/test_pattern_literals.hpp" +#include "test_patterns/test_pattern_padding.hpp" +#include "test_patterns/test_pattern_succeeding_assert.hpp" +#include "test_patterns/test_pattern_failing_assert.hpp" + +std::array Tests = { + TEST(Placement), + TEST(Structs), + TEST(Unions), + TEST(Enums), + TEST(Literals), + TEST(Padding), + TEST(SucceedingAssert), + TEST(FailingAssert) +}; \ No newline at end of file