tests: Added more tests
This commit is contained in:
parent
254b204d6c
commit
3d15a108af
@ -6,11 +6,18 @@ project(unit_tests)
|
|||||||
# Add new tests here #
|
# Add new tests here #
|
||||||
set(AVAILABLE_TESTS
|
set(AVAILABLE_TESTS
|
||||||
Placement
|
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_include_directories(unit_tests PRIVATE include)
|
||||||
target_link_libraries(unit_tests libimhex)
|
target_link_libraries(unit_tests libimhex)
|
||||||
|
|
||||||
|
@ -5,18 +5,30 @@
|
|||||||
|
|
||||||
#include <hex/pattern_language/pattern_data.hpp>
|
#include <hex/pattern_language/pattern_data.hpp>
|
||||||
|
|
||||||
|
#define TEST(name) (hex::test::TestPattern*) new hex::test::TestPattern ## name ()
|
||||||
|
|
||||||
namespace hex::test {
|
namespace hex::test {
|
||||||
|
|
||||||
|
using namespace pl;
|
||||||
|
|
||||||
|
enum class Mode {
|
||||||
|
Succeeding,
|
||||||
|
Failing
|
||||||
|
};
|
||||||
|
|
||||||
class TestPattern {
|
class TestPattern {
|
||||||
public:
|
public:
|
||||||
TestPattern() = default;
|
explicit TestPattern(const std::string &name, Mode mode = Mode::Succeeding) : m_mode(mode) {
|
||||||
|
TestPattern::s_tests.insert({ name, this });
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~TestPattern() {
|
virtual ~TestPattern() {
|
||||||
for (auto &pattern : this->m_patterns)
|
for (auto &pattern : this->m_patterns)
|
||||||
delete pattern;
|
delete pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
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);
|
auto pattern = new T(offset, size);
|
||||||
pattern->setTypeName(typeName);
|
pattern->setTypeName(typeName);
|
||||||
pattern->setVariableName(varName);
|
pattern->setVariableName(varName);
|
||||||
@ -24,16 +36,37 @@ namespace hex::test {
|
|||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
virtual std::string getSourceCode() const = 0;
|
virtual std::string getSourceCode() const = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual const std::vector<pl::PatternData*>& getPatterns() const final { return this->m_patterns; }
|
virtual const std::vector<PatternData*>& getPatterns() const final { return this->m_patterns; }
|
||||||
virtual void addPattern(pl::PatternData *pattern) final {
|
virtual void addPattern(PatternData *pattern) final {
|
||||||
this->m_patterns.push_back(pattern);
|
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:
|
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 {
|
class TestPatternExample : public TestPattern {
|
||||||
public:
|
public:
|
||||||
TestPatternExample() {
|
TestPatternExample() : TestPattern("") {
|
||||||
|
|
||||||
}
|
}
|
||||||
~TestPatternExample() override = default;
|
~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 {
|
class TestPatternPlacement : public TestPattern {
|
||||||
public:
|
public:
|
||||||
TestPatternPlacement() {
|
TestPatternPlacement() : TestPattern("Placement") {
|
||||||
// placementVar
|
// placementVar
|
||||||
{
|
{
|
||||||
addPattern(createVariablePattern<pl::PatternDataUnsigned>(0x00, sizeof(u32), "u32", "placementVar"));
|
addPattern(create<PatternDataUnsigned>(0x00, sizeof(u32), "u32", "placementVar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// placementArray
|
// placementArray
|
||||||
{
|
{
|
||||||
auto placementArray = createVariablePattern<pl::PatternDataStaticArray>(0x10, sizeof(u8) * 10, "u8", "placementArray");
|
auto placementArray = create<PatternDataStaticArray>(0x10, sizeof(u8) * 10, "u8", "placementArray");
|
||||||
placementArray->setEntries(createVariablePattern<pl::PatternDataUnsigned>(0x10, sizeof(u8), "u8", ""), 10);
|
placementArray->setEntries(create<PatternDataUnsigned>(0x10, sizeof(u8), "u8", ""), 10);
|
||||||
addPattern(placementArray);
|
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/utils.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
#include <hex/pattern_language/pattern_language.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_provider.hpp"
|
||||||
#include "test_patterns/test_pattern_placement.hpp"
|
#include "test_patterns/test_pattern.hpp"
|
||||||
|
|
||||||
using namespace hex::test;
|
using namespace hex::test;
|
||||||
|
|
||||||
static std::map<std::string, TestPattern*> testPatterns {
|
void addFunctions() {
|
||||||
{ "Placement", new TestPatternPlacement() }
|
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 {
|
ON_SCOPE_EXIT {
|
||||||
for (auto &[key, value] : testPatterns)
|
for (auto &[key, value] : TestPattern::getTests())
|
||||||
delete value;
|
delete value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,6 +49,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto &currTest = testPatterns[testName];
|
const auto &currTest = testPatterns[testName];
|
||||||
|
bool failing = currTest->getMode() == Mode::Failing;
|
||||||
|
|
||||||
auto provider = new TestProvider();
|
auto provider = new TestProvider();
|
||||||
ON_SCOPE_EXIT { delete provider; };
|
ON_SCOPE_EXIT { delete provider; };
|
||||||
@ -44,14 +59,24 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hex::pl::PatternLanguage language;
|
hex::pl::PatternLanguage language;
|
||||||
|
addFunctions();
|
||||||
|
|
||||||
// Check if compilation succeeded
|
// Check if compilation succeeded
|
||||||
auto patterns = language.executeString(provider, testPatterns[testName]->getSourceCode());
|
auto patterns = language.executeString(provider, testPatterns[testName]->getSourceCode());
|
||||||
if (!patterns.has_value()) {
|
if (!patterns.has_value()) {
|
||||||
hex::log::fatal("Error during compilation!");
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +102,16 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hex::log::info("Success!");
|
|
||||||
|
|
||||||
return EXIT_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…
x
Reference in New Issue
Block a user