tests: Added more tests
This commit is contained in:
parent
254b204d6c
commit
3d15a108af
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
38
tests/include/test_patterns/test_pattern_enums.hpp
Normal file
38
tests/include/test_patterns/test_pattern_enums.hpp
Normal 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;
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -6,7 +6,7 @@ namespace hex::test {
|
||||
|
||||
class TestPatternExample : public TestPattern {
|
||||
public:
|
||||
TestPatternExample() {
|
||||
TestPatternExample() : TestPattern("") {
|
||||
|
||||
}
|
||||
~TestPatternExample() override = default;
|
||||
|
26
tests/include/test_patterns/test_pattern_failing_assert.hpp
Normal file
26
tests/include/test_patterns/test_pattern_failing_assert.hpp
Normal 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);
|
||||
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
32
tests/include/test_patterns/test_pattern_literals.hpp
Normal file
32
tests/include/test_patterns/test_pattern_literals.hpp
Normal 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);
|
||||
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
38
tests/include/test_patterns/test_pattern_padding.hpp
Normal file
38
tests/include/test_patterns/test_pattern_padding.hpp
Normal 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;
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
36
tests/include/test_patterns/test_pattern_structs.hpp
Normal file
36
tests/include/test_patterns/test_pattern_structs.hpp
Normal 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;
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
36
tests/include/test_patterns/test_pattern_unions.hpp
Normal file
36
tests/include/test_patterns/test_pattern_unions.hpp
Normal 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;
|
||||
)";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -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
21
tests/source/tests.cpp
Normal 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)
|
||||
};
|
Loading…
Reference in New Issue
Block a user