1
0
mirror of synced 2024-11-12 02:00:52 +01:00

tests: Added more tests

This commit is contained in:
WerWolv 2021-09-11 23:13:49 +02:00
parent 254b204d6c
commit 3d15a108af
13 changed files with 351 additions and 21 deletions

View File

@ -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)

View File

@ -5,18 +5,30 @@
#include <hex/pattern_language/pattern_data.hpp>
#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<typename T>
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<pl::PatternData*>& getPatterns() const final { return this->m_patterns; }
virtual void addPattern(pl::PatternData *pattern) final {
virtual const std::vector<PatternData*>& 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<pl::PatternData*> m_patterns;
std::vector<PatternData*> m_patterns;
Mode m_mode;
static inline std::map<std::string, TestPattern*> s_tests;
};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternEnums : public TestPattern {
public:
TestPatternEnums() : TestPattern("Enums"){
auto testEnum = create<PatternDataEnum>(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;
)";
}
};
}

View File

@ -6,7 +6,7 @@ namespace hex::test {
class TestPatternExample : public TestPattern {
public:
TestPatternExample() {
TestPatternExample() : TestPattern("") {
}
~TestPatternExample() override = default;

View File

@ -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);
)";
}
};
}

View File

@ -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);
)";
}
};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternPadding : public TestPattern {
public:
TestPatternPadding() : TestPattern("Padding") {
auto testStruct = create<PatternDataStruct>(0x100, sizeof(s32) + 20 + sizeof(u8[0x10]), "TestStruct", "testStruct");
auto variable = create<PatternDataSigned>(0x100, sizeof(s32), "s32", "variable");
auto padding = create<PatternDataPadding>(0x100 + sizeof(s32), 20, "", "");
auto array = create<PatternDataStaticArray>(0x100 + sizeof(s32) + 20, sizeof(u8[0x10]), "u8", "array");
array->setEntries(create<PatternDataUnsigned>(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;
)";
}
};
}

View File

@ -6,16 +6,16 @@ namespace hex::test {
class TestPatternPlacement : public TestPattern {
public:
TestPatternPlacement() {
TestPatternPlacement() : TestPattern("Placement") {
// placementVar
{
addPattern(createVariablePattern<pl::PatternDataUnsigned>(0x00, sizeof(u32), "u32", "placementVar"));
addPattern(create<PatternDataUnsigned>(0x00, sizeof(u32), "u32", "placementVar"));
}
// placementArray
{
auto placementArray = createVariablePattern<pl::PatternDataStaticArray>(0x10, sizeof(u8) * 10, "u8", "placementArray");
placementArray->setEntries(createVariablePattern<pl::PatternDataUnsigned>(0x10, sizeof(u8), "u8", ""), 10);
auto placementArray = create<PatternDataStaticArray>(0x10, sizeof(u8) * 10, "u8", "placementArray");
placementArray->setEntries(create<PatternDataUnsigned>(0x10, sizeof(u8), "u8", ""), 10);
addPattern(placementArray);
}

View File

@ -0,0 +1,36 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternStructs : public TestPattern {
public:
TestPatternStructs() : TestPattern("Structs") {
auto testStruct = create<PatternDataStruct>(0x100, sizeof(s32) + sizeof(u8[0x10]), "TestStruct", "testStruct");
auto variable = create<PatternDataSigned>(0x100, sizeof(s32), "s32", "variable");
auto array = create<PatternDataStaticArray>(0x100 + sizeof(s32), sizeof(u8[0x10]), "u8", "array");
array->setEntries(create<PatternDataUnsigned>(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;
)";
}
};
}

View File

@ -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);
)";
}
};
}

View File

@ -0,0 +1,36 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternUnions : public TestPattern {
public:
TestPatternUnions() : TestPattern("Unions") {
auto testUnion = create<PatternDataUnion>(0x200, sizeof(u128), "TestUnion", "testUnion");
auto array = create<PatternDataStaticArray>(0x200, sizeof(s32[2]), "s32", "array");
array->setEntries(create<PatternDataSigned>(0x200, sizeof(s32), "s32", ""), 2);
auto variable = create<PatternDataUnsigned>(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;
)";
}
};
}

View File

@ -4,20 +4,34 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/pattern_language/pattern_language.hpp>
#include <hex/pattern_language/evaluator.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <hex/api/content_registry.hpp>
#include "test_provider.hpp"
#include "test_patterns/test_pattern_placement.hpp"
#include "test_patterns/test_pattern.hpp"
using namespace hex::test;
static std::map<std::string, TestPattern*> 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;
}

21
tests/source/tests.cpp Normal file
View File

@ -0,0 +1,21 @@
#include <array>
#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)
};