tests: Removed pattern language tests as they are now done in their own repo
This commit is contained in:
parent
17383083fb
commit
1e7ed14810
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
||||
Subproject commit 3abaa2a36d833bb3be7a580dff9b89c37c876a18
|
||||
Subproject commit 956b16fed807615eec144b9ec58d8300749351e0
|
@ -2,9 +2,8 @@ project(unit_tests)
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
add_custom_target(unit_tests DEPENDS helpers algorithms pattern_language)
|
||||
add_custom_target(unit_tests DEPENDS helpers algorithms)
|
||||
add_subdirectory(common)
|
||||
|
||||
add_subdirectory(helpers)
|
||||
add_subdirectory(algorithms)
|
||||
add_subdirectory(pattern_language)
|
@ -1,47 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(pattern_language_tests)
|
||||
|
||||
|
||||
# Add new tests here #
|
||||
set(AVAILABLE_TESTS
|
||||
Placement
|
||||
Structs
|
||||
Unions
|
||||
Enums
|
||||
Literals
|
||||
Padding
|
||||
SucceedingAssert
|
||||
FailingAssert
|
||||
Bitfields
|
||||
Math
|
||||
RValues
|
||||
Namespaces
|
||||
ExtraSemicolon
|
||||
Pointers
|
||||
Arrays
|
||||
NestedStructs
|
||||
)
|
||||
|
||||
|
||||
add_executable(pattern_language_tests
|
||||
source/main.cpp
|
||||
source/tests.cpp
|
||||
)
|
||||
|
||||
|
||||
# ---- No need to change anything from here downwards unless you know what you're doing ---- #
|
||||
|
||||
target_include_directories(pattern_language_tests PRIVATE include)
|
||||
target_link_libraries(pattern_language_tests libimhex)
|
||||
|
||||
set_target_properties(pattern_language_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_custom_command(TARGET pattern_language_tests
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/test_data" ${CMAKE_BINARY_DIR})
|
||||
|
||||
foreach (test IN LISTS AVAILABLE_TESTS)
|
||||
add_test(NAME "PatternLanguage/${test}" COMMAND pattern_language_tests "${test}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
endforeach ()
|
||||
add_dependencies(unit_tests ${PROJECT_NAME})
|
@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.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:
|
||||
explicit TestPattern(const std::string &name, Mode mode = Mode::Succeeding) : m_mode(mode) {
|
||||
TestPattern::s_tests.insert({ name, this });
|
||||
}
|
||||
|
||||
virtual ~TestPattern() = default;
|
||||
|
||||
template<typename T>
|
||||
static std::unique_ptr<T> create(const std::string &typeName, const std::string &varName, auto... args) {
|
||||
auto pattern = std::make_unique<T>(nullptr, args...);
|
||||
pattern->setTypeName(typeName);
|
||||
pattern->setVariableName(varName);
|
||||
|
||||
return std::move(pattern);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual std::string getSourceCode() const = 0;
|
||||
|
||||
[[nodiscard]] virtual const std::vector<std::unique_ptr<Pattern>> &getPatterns() const final { return this->m_patterns; }
|
||||
virtual void addPattern(std::unique_ptr<Pattern> &&pattern) final {
|
||||
this->m_patterns.push_back(std::move(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<std::unique_ptr<Pattern>> m_patterns;
|
||||
Mode m_mode;
|
||||
|
||||
static inline std::map<std::string, TestPattern *> s_tests;
|
||||
};
|
||||
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_struct.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_dynamic.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternArrays : public TestPattern {
|
||||
public:
|
||||
TestPatternArrays() : TestPattern("Arrays") {
|
||||
auto first = create<PatternArrayStatic>("u8", "first", 0x0, sizeof(u8[4]));
|
||||
first->setEntries(create<PatternUnsigned>("u8", "", 0x0, sizeof(u8)), 4);
|
||||
|
||||
auto second = create<PatternArrayStatic>("u8", "second", 0x4, sizeof(u8[4]));
|
||||
second->setEntries(create<PatternUnsigned>("u8", "", 0x4, sizeof(u8)), 4);
|
||||
|
||||
auto testStruct = create<PatternStruct>("Signature", "sign", 0x0, sizeof(u8[8]));
|
||||
std::vector<std::shared_ptr<pl::Pattern>> structMembers;
|
||||
{
|
||||
structMembers.push_back(std::move(first));
|
||||
structMembers.push_back(std::move(second));
|
||||
}
|
||||
testStruct->setMembers(std::move(structMembers));
|
||||
|
||||
addPattern(std::move(testStruct));
|
||||
}
|
||||
~TestPatternArrays() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
fn end_of_signature() {
|
||||
return $ >= 8;
|
||||
};
|
||||
|
||||
struct Signature {
|
||||
u8 first[4];
|
||||
u8 second[while(!end_of_signature())];
|
||||
};
|
||||
|
||||
Signature sign @ 0x0;
|
||||
|
||||
std::assert(sign.first[0] == 0x89, "Invalid 1st byte of signature");
|
||||
std::assert(sign.first[1] == 0x50, "Invalid 2nd byte of signature");
|
||||
std::assert(sign.first[2] == 0x4E, "Invalid 3rd byte of signature");
|
||||
std::assert(sign.first[3] == 0x47, "Invalid 4th byte of signature");
|
||||
std::assert(sizeof(sign.second) == 4, "Invalid size of signature");
|
||||
std::assert(sign.second[0] == 0x0D, "Invalid 5th byte of signature");
|
||||
std::assert(sign.second[1] == 0x0A, "Invalid 6th byte of signature");
|
||||
std::assert(sign.second[2] == 0x1A, "Invalid 7th byte of signature");
|
||||
std::assert(sign.second[3] == 0x0A, "Invalid 8th byte of signature");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_bitfield.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternBitfields : public TestPattern {
|
||||
public:
|
||||
TestPatternBitfields() : TestPattern("Bitfields") {
|
||||
auto testBitfield = create<PatternBitfield>("TestBitfield", "testBitfield", 0x12, (4 * 4) / 8);
|
||||
testBitfield->setEndian(std::endian::big);
|
||||
|
||||
std::vector<std::shared_ptr<pl::Pattern>> bitfieldFields;
|
||||
{
|
||||
bitfieldFields.push_back(create<PatternBitfieldField>("", "a", 0x12, 0, 4, testBitfield.get()));
|
||||
bitfieldFields.push_back(create<PatternBitfieldField>("", "b", 0x12, 4, 4, testBitfield.get()));
|
||||
bitfieldFields.push_back(create<PatternBitfieldField>("", "c", 0x12, 8, 4, testBitfield.get()));
|
||||
bitfieldFields.push_back(create<PatternBitfieldField>("", "d", 0x12, 12, 4, testBitfield.get()));
|
||||
}
|
||||
|
||||
testBitfield->setFields(std::move(bitfieldFields));
|
||||
|
||||
addPattern(std::move(testBitfield));
|
||||
}
|
||||
~TestPatternBitfields() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
bitfield TestBitfield {
|
||||
a : 4;
|
||||
b : 4;
|
||||
c : 4;
|
||||
d : 4;
|
||||
};
|
||||
|
||||
be TestBitfield testBitfield @ 0x12;
|
||||
|
||||
std::assert(testBitfield.a == 0x0A, "Field A invalid");
|
||||
std::assert(testBitfield.b == 0x00, "Field B invalid");
|
||||
std::assert(testBitfield.c == 0x04, "Field C invalid");
|
||||
std::assert(testBitfield.d == 0x03, "Field D invalid");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_enum.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternEnums : public TestPattern {
|
||||
public:
|
||||
TestPatternEnums() : TestPattern("Enums") {
|
||||
auto testEnum = create<PatternEnum>("TestEnum", "testEnum", 0x08, sizeof(u32));
|
||||
testEnum->setEnumValues({
|
||||
{u128(0x00), "A"},
|
||||
{ i128(0x0C), "B"},
|
||||
{ u128(0x0D), "C"},
|
||||
{ u128(0x0E), "D"},
|
||||
});
|
||||
testEnum->setEndian(std::endian::big);
|
||||
|
||||
addPattern(std::move(testEnum));
|
||||
}
|
||||
~TestPatternEnums() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
enum TestEnum : u32 {
|
||||
A,
|
||||
B = 0x0C,
|
||||
C,
|
||||
D
|
||||
};
|
||||
|
||||
be TestEnum testEnum @ 0x08;
|
||||
|
||||
std::assert(testEnum == TestEnum::C, "Invalid enum value");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternExample : public TestPattern {
|
||||
public:
|
||||
TestPatternExample() : TestPattern("") {
|
||||
}
|
||||
~TestPatternExample() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternExtraSemicolon : public TestPattern {
|
||||
public:
|
||||
TestPatternExtraSemicolon() : TestPattern("ExtraSemicolon") {
|
||||
}
|
||||
~TestPatternExtraSemicolon() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
struct Test {
|
||||
u32 x;;;
|
||||
u8 y;
|
||||
float z;;
|
||||
};;
|
||||
|
||||
struct Test2 {
|
||||
u32 x;
|
||||
u32 y;
|
||||
};
|
||||
|
||||
Test test @ 0x00;;;
|
||||
Test test2 @ 0x10;
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#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);
|
||||
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#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(100U == 0x64U, MSG);
|
||||
std::assert(-100 == -0x64, MSG);
|
||||
std::assert(3.14159F > 1.414D, MSG);
|
||||
std::assert('A' == 0x41, MSG);
|
||||
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternMath : public TestPattern {
|
||||
public:
|
||||
TestPatternMath() : TestPattern("Math") {
|
||||
}
|
||||
~TestPatternMath() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
// Compare operations
|
||||
std::assert(123 == 123, "== operation error");
|
||||
std::assert(123 != 567, "!= operation error");
|
||||
std::assert(111 < 222, "< operation error");
|
||||
std::assert(333 > 222, "> operation error");
|
||||
std::assert(100 >= 100, ">= operation error");
|
||||
std::assert(200 <= 200, "<= operation error");
|
||||
|
||||
// Boolean operations
|
||||
std::assert(true, "true literal invalid");
|
||||
std::assert(true && true, "&& operator error");
|
||||
std::assert(false || true, "|| operator error");
|
||||
std::assert(true ^^ false, "^^ operator error");
|
||||
std::assert(!false, "! operator error");
|
||||
|
||||
// Bitwise operations
|
||||
std::assert(0xFF00FF | 0x00AA00 == 0xFFAAFF, "| operator error");
|
||||
std::assert(0xFFFFFF & 0x00FF00 == 0x00FF00, "& operator error");
|
||||
std::assert(0xFFFFFF ^ 0x00AA00 == 0xFF55FF, "^ operator error");
|
||||
std::assert(~0x00U == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "~ operator error");
|
||||
std::assert(0xAA >> 4 == 0x0A, ">> operator error");
|
||||
std::assert(0xAA << 4 == 0xAA0, "<< operator error");
|
||||
|
||||
// Basic operations
|
||||
std::assert(100 + 200 == 300, "+ operator error");
|
||||
std::assert(400 - 200 == 200, "- operator error");
|
||||
std::assert(10 * 20 == 200, "* operator error");
|
||||
std::assert(200 / 100 == 2, "/ operator error");
|
||||
std::assert(100 % 2 == 0, "% operator error");
|
||||
|
||||
// Special operators
|
||||
std::assert($ == 0, "$ operator error");
|
||||
std::assert(((10 == 20) ? 30 : 40) == 40, "?: operator error");
|
||||
|
||||
// Type operators
|
||||
struct TypeTest { u32 x, y, z; };
|
||||
TypeTest typeTest @ 0x100;
|
||||
|
||||
std::assert(addressof(typeTest) == 0x100, "addressof operator error");
|
||||
std::assert(sizeof(typeTest) == 3 * 4, "sizeof operator error");
|
||||
|
||||
// Properties
|
||||
std::assert(100 + 200 == 200 + 100, "+ operator commutativity error");
|
||||
std::assert(100 - 200 != 200 - 100, "- operator commutativity error");
|
||||
std::assert(100 * 200 == 200 * 100, "* operator commutativity error");
|
||||
std::assert(100F / 200F != 200F / 100F, "/ operator commutativity error");
|
||||
|
||||
std::assert(10 + (20 + 30) == (10 + 20) + 30, "+ operator associativity error");
|
||||
std::assert(10 - (20 - 30) != (10 - 20) - 30, "- operator associativity error");
|
||||
std::assert(10 * (20 * 30) == (10 * 20) * 30, "* operator associativity error");
|
||||
std::assert(10F / (20F / 30F) != (10F / 20F) / 30F, "/ operator associativity error");
|
||||
|
||||
std::assert(10 * (20 + 30) == 10 * 20 + 10 * 30, "* operator distributivity error");
|
||||
std::assert(10F / (20F + 30F) != 10F / 20F + 10F / 30F, "/ operator distributivity error");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternNamespaces : public TestPattern {
|
||||
public:
|
||||
TestPatternNamespaces() : TestPattern("Namespaces") {
|
||||
}
|
||||
~TestPatternNamespaces() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
namespace A {
|
||||
struct Test {
|
||||
u32 x;
|
||||
};
|
||||
}
|
||||
|
||||
namespace B {
|
||||
struct Test {
|
||||
u16 x;
|
||||
};
|
||||
}
|
||||
|
||||
using ATest = A::Test;
|
||||
|
||||
A::Test test1 @ 0x10;
|
||||
ATest test2 @ 0x20;
|
||||
B::Test test3 @ 0x20;
|
||||
|
||||
std::assert(sizeof(test1) == sizeof(test2), "error using namespaced type");
|
||||
std::assert(sizeof(test2) != sizeof(test3), "error differentiating two namespace types with same name");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_struct.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_dynamic.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternNestedStructs : public TestPattern {
|
||||
public:
|
||||
TestPatternNestedStructs() : TestPattern("NestedStructs") {
|
||||
const size_t HEADER_START = 0x0;
|
||||
const size_t HEADER_SIZE = sizeof(u8);
|
||||
const size_t BODY_START = HEADER_SIZE;
|
||||
const size_t BODY_SIZE = 0x89 - 1;
|
||||
|
||||
auto data = create<PatternStruct>("Data", "data", HEADER_START, HEADER_SIZE + BODY_SIZE);
|
||||
{
|
||||
auto hdr = create<PatternStruct>("Header", "hdr", HEADER_START, HEADER_SIZE);
|
||||
{
|
||||
std::vector<std::shared_ptr<pl::Pattern>> hdrMembers {
|
||||
std::shared_ptr(create<PatternUnsigned>("u8", "len", HEADER_START, sizeof(u8)))
|
||||
};
|
||||
hdr->setMembers(std::move(hdrMembers));
|
||||
}
|
||||
|
||||
auto body = create<PatternStruct>("Body", "body", BODY_START, BODY_SIZE);
|
||||
{
|
||||
auto bodyArray = create<PatternArrayStatic>("u8", "arr", BODY_START, BODY_SIZE);
|
||||
bodyArray->setEntries(create<PatternUnsigned>("u8", "", BODY_START, sizeof(u8)), BODY_SIZE);
|
||||
std::vector<std::shared_ptr<pl::Pattern>> bodyMembers {
|
||||
std::shared_ptr(std::move(bodyArray))
|
||||
};
|
||||
body->setMembers(std::move(bodyMembers));
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<pl::Pattern>> dataMembers {
|
||||
std::shared_ptr(std::move(hdr)),
|
||||
std::shared_ptr(std::move(body))
|
||||
};
|
||||
data->setMembers(std::move(dataMembers));
|
||||
}
|
||||
|
||||
addPattern(std::move(data));
|
||||
}
|
||||
~TestPatternNestedStructs() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
fn end_of_body() {
|
||||
u32 start = addressof(parent.parent.hdr);
|
||||
u32 len = parent.parent.hdr.len;
|
||||
u32 end = start + len;
|
||||
|
||||
return $ >= end;
|
||||
};
|
||||
|
||||
struct Header {
|
||||
u8 len;
|
||||
};
|
||||
|
||||
struct Body {
|
||||
u8 arr[while(!end_of_body())];
|
||||
};
|
||||
|
||||
struct Data {
|
||||
Header hdr;
|
||||
Body body;
|
||||
};
|
||||
|
||||
Data data @ 0x0;
|
||||
|
||||
std::assert(data.hdr.len == 0x89, "Invalid length");
|
||||
std::assert(sizeof(data.body.arr) == 0x89 - 1, "Invalid size of body");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_signed.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_struct.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_padding.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternPadding : public TestPattern {
|
||||
public:
|
||||
TestPatternPadding() : TestPattern("Padding") {
|
||||
auto testStruct = create<PatternStruct>("TestStruct", "testStruct", 0x100, sizeof(i32) + 20 + sizeof(u8[0x10]));
|
||||
|
||||
auto variable = create<PatternSigned>("s32", "variable", 0x100, sizeof(i32));
|
||||
auto padding = create<PatternPadding>("padding", "", 0x100 + sizeof(i32), 20);
|
||||
auto array = create<PatternArrayStatic>("u8", "array", 0x100 + sizeof(i32) + 20, sizeof(u8[0x10]));
|
||||
array->setEntries(create<PatternUnsigned>("u8", "", 0x100 + sizeof(i32) + 20, sizeof(u8)), 0x10);
|
||||
|
||||
std::vector<std::shared_ptr<pl::Pattern>> structMembers;
|
||||
{
|
||||
structMembers.push_back(std::move(variable));
|
||||
structMembers.push_back(std::move(padding));
|
||||
structMembers.push_back(std::move(array));
|
||||
}
|
||||
|
||||
testStruct->setMembers(std::move(structMembers));
|
||||
|
||||
addPattern(std::move(testStruct));
|
||||
}
|
||||
~TestPatternPadding() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
struct TestStruct {
|
||||
s32 variable;
|
||||
padding[20];
|
||||
u8 array[0x10];
|
||||
};
|
||||
|
||||
TestStruct testStruct @ 0x100;
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternPlacement : public TestPattern {
|
||||
public:
|
||||
TestPatternPlacement() : TestPattern("Placement") {
|
||||
// placementVar
|
||||
{
|
||||
addPattern(create<PatternUnsigned>("u32", "placementVar", 0x00, sizeof(u32)));
|
||||
}
|
||||
|
||||
// placementArray
|
||||
{
|
||||
auto placementArray = create<PatternArrayStatic>("u8", "placementArray", 0x10, sizeof(u8) * 10);
|
||||
placementArray->setEntries(std::move(create<PatternUnsigned>("u8", "", 0x10, sizeof(u8))), 10);
|
||||
addPattern(std::move(placementArray));
|
||||
}
|
||||
}
|
||||
~TestPatternPlacement() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
u32 placementVar @ 0x00;
|
||||
u8 placementArray[10] @ 0x10;
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_pointer.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternPointers : public TestPattern {
|
||||
public:
|
||||
TestPatternPointers() : TestPattern("Pointers") {
|
||||
// placementPointer
|
||||
{
|
||||
auto placementPointer = create<PatternPointer>("", "placementPointer", 0x0C, sizeof(u8));
|
||||
placementPointer->setPointedAtAddress(0x49);
|
||||
|
||||
auto pointedTo = create<PatternUnsigned>("u32", "", 0x49, sizeof(u32));
|
||||
placementPointer->setPointedAtPattern(std::move(pointedTo));
|
||||
addPattern(std::move(placementPointer));
|
||||
}
|
||||
}
|
||||
~TestPatternPointers() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
u32 *placementPointer : u8 @ 0x0C;
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternRValues : public TestPattern {
|
||||
public:
|
||||
TestPatternRValues() : TestPattern("RValues") {
|
||||
}
|
||||
~TestPatternRValues() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
union C {
|
||||
u8 y;
|
||||
u8 array[parent.parent.x];
|
||||
};
|
||||
|
||||
struct B {
|
||||
C *c : u8;
|
||||
};
|
||||
|
||||
struct A {
|
||||
u8 x;
|
||||
B b;
|
||||
};
|
||||
|
||||
A a @ 0x00;
|
||||
|
||||
std::assert(sizeof(a.b.c) == a.x && a.x != 0x00, "RValue parent test failed!");
|
||||
std::assert(a.b.c.y == a.b.c.array[0], "RValue array access test failed!");
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_signed.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_struct.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternStructs : public TestPattern {
|
||||
public:
|
||||
TestPatternStructs() : TestPattern("Structs") {
|
||||
auto testStruct = create<PatternStruct>("TestStruct", "testStruct", 0x100, sizeof(i32) + sizeof(u8[0x10]));
|
||||
|
||||
auto variable = create<PatternSigned>("s32", "variable", 0x100, sizeof(i32));
|
||||
auto array = create<PatternArrayStatic>("u8", "array", 0x100 + sizeof(i32), sizeof(u8[0x10]));
|
||||
array->setEntries(create<PatternUnsigned>("u8", "", 0x100 + sizeof(i32), sizeof(u8)), 0x10);
|
||||
|
||||
std::vector<std::shared_ptr<pl::Pattern>> structMembers;
|
||||
{
|
||||
structMembers.push_back(std::move(variable));
|
||||
structMembers.push_back(std::move(array));
|
||||
}
|
||||
testStruct->setMembers(std::move(structMembers));
|
||||
|
||||
addPattern(std::move(testStruct));
|
||||
}
|
||||
~TestPatternStructs() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
struct TestStruct {
|
||||
s32 variable;
|
||||
u8 array[0x10];
|
||||
};
|
||||
|
||||
TestStruct testStruct @ 0x100;
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#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);
|
||||
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "test_pattern.hpp"
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_signed.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_union.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
class TestPatternUnions : public TestPattern {
|
||||
public:
|
||||
TestPatternUnions() : TestPattern("Unions") {
|
||||
auto testUnion = create<PatternUnion>("TestUnion", "testUnion", 0x200, sizeof(u128));
|
||||
|
||||
auto array = create<PatternArrayStatic>("s32", "array", 0x200, sizeof(i32[2]));
|
||||
array->setEntries(create<PatternSigned>("s32", "", 0x200, sizeof(i32)), 2);
|
||||
auto variable = create<PatternUnsigned>("u128", "variable", 0x200, sizeof(u128));
|
||||
|
||||
std::vector<std::shared_ptr<pl::Pattern>> unionMembers;
|
||||
{
|
||||
unionMembers.push_back(std::move(array));
|
||||
unionMembers.push_back(std::move(variable));
|
||||
}
|
||||
|
||||
testUnion->setMembers(std::move(unionMembers));
|
||||
|
||||
addPattern(std::move(testUnion));
|
||||
}
|
||||
~TestPatternUnions() override = default;
|
||||
|
||||
[[nodiscard]] std::string getSourceCode() const override {
|
||||
return R"(
|
||||
union TestUnion {
|
||||
s32 array[2];
|
||||
u128 variable;
|
||||
};
|
||||
|
||||
TestUnion testUnion @ 0x200;
|
||||
)";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace hex::test {
|
||||
using namespace hex::prv;
|
||||
|
||||
class TestProvider : public prv::Provider {
|
||||
public:
|
||||
TestProvider() : Provider(), m_testFile(fs::File("test_data", fs::File::Mode::Read)) {
|
||||
if (!this->m_testFile.isValid() || this->m_testFile.getSize() == 0) {
|
||||
hex::log::fatal("Failed to open test data!");
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
}
|
||||
~TestProvider() override = default;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool isReadable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return false; }
|
||||
[[nodiscard]] bool isResizable() const override { return false; }
|
||||
[[nodiscard]] bool isSavable() const override { return false; }
|
||||
|
||||
[[nodiscard]] std::string getName() const override {
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override {
|
||||
this->m_testFile.seek(offset);
|
||||
this->m_testFile.readBuffer(static_cast<u8 *>(buffer), size);
|
||||
}
|
||||
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override {
|
||||
this->m_testFile.seek(offset);
|
||||
this->m_testFile.write(static_cast<const u8 *>(buffer), size);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getActualSize() const override {
|
||||
return this->m_testFile.getSize();
|
||||
}
|
||||
|
||||
bool open() override { return true; }
|
||||
void close() override { }
|
||||
|
||||
private:
|
||||
fs::File m_testFile;
|
||||
};
|
||||
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#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/ast_node.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include "test_provider.hpp"
|
||||
#include "test_patterns/test_pattern.hpp"
|
||||
|
||||
#include <fmt/args.h>
|
||||
|
||||
using namespace hex::test;
|
||||
|
||||
static std::string format(pl::Evaluator *ctx, const auto ¶ms) {
|
||||
auto format = pl::Token::literalToString(params[0], true);
|
||||
std::string message;
|
||||
|
||||
fmt::dynamic_format_arg_store<fmt::format_context> formatArgs;
|
||||
|
||||
for (u32 i = 1; i < params.size(); i++) {
|
||||
auto ¶m = params[i];
|
||||
|
||||
std::visit(hex::overloaded {
|
||||
[&](pl::Pattern *value) {
|
||||
formatArgs.push_back(value->toString(ctx->getProvider()));
|
||||
},
|
||||
[&](auto &&value) {
|
||||
formatArgs.push_back(value);
|
||||
} },
|
||||
param);
|
||||
}
|
||||
|
||||
try {
|
||||
return fmt::vformat(format, formatArgs);
|
||||
} catch (fmt::format_error &error) {
|
||||
pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void addFunctions() {
|
||||
using namespace hex::ContentRegistry::PatternLanguage;
|
||||
|
||||
Namespace nsStd = { "std" };
|
||||
hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "assert", ParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> Token::Literal {
|
||||
auto condition = Token::literalToBoolean(params[0]);
|
||||
auto message = Token::literalToString(params[1], false);
|
||||
|
||||
if (!condition)
|
||||
LogConsole::abortEvaluation(hex::format("assertion failed \"{0}\"", message));
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
hex::ContentRegistry::PatternLanguage::addFunction(nsStd, "print", ParameterCount::atLeast(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
|
||||
ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params));
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
int test(int argc, char **argv) {
|
||||
auto &testPatterns = TestPattern::getTests();
|
||||
|
||||
// Check if a test to run has been provided
|
||||
if (argc != 2) {
|
||||
hex::log::fatal("Invalid number of arguments specified! {}", argc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check if that test exists
|
||||
std::string testName = argv[1];
|
||||
if (!testPatterns.contains(testName)) {
|
||||
hex::log::fatal("No test with name {} found!", testName);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const auto &currTest = testPatterns[testName];
|
||||
bool failing = currTest->getMode() == Mode::Failing;
|
||||
|
||||
auto provider = new TestProvider();
|
||||
ON_SCOPE_EXIT { delete provider; };
|
||||
if (provider->getActualSize() == 0) {
|
||||
hex::log::fatal("Failed to load Testing Data");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
pl::PatternLanguage language;
|
||||
|
||||
// Check if compilation succeeded
|
||||
auto result = language.executeString(provider, testPatterns[testName]->getSourceCode());
|
||||
if (!result) {
|
||||
hex::log::fatal("Error during compilation!");
|
||||
|
||||
if (auto error = language.getError(); error.has_value())
|
||||
hex::log::info("Compile error: {} : {}", error->getLineNumber(), error->what());
|
||||
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;
|
||||
}
|
||||
|
||||
// Check if the right number of patterns have been produced
|
||||
if (language.getPatterns().size() != currTest->getPatterns().size() && !currTest->getPatterns().empty()) {
|
||||
hex::log::fatal("Source didn't produce expected number of patterns");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check if the produced patterns are the ones expected
|
||||
for (u32 i = 0; i < currTest->getPatterns().size(); i++) {
|
||||
auto &evaluatedPattern = *language.getPatterns()[i];
|
||||
auto &controlPattern = *currTest->getPatterns()[i];
|
||||
|
||||
if (evaluatedPattern != controlPattern) {
|
||||
hex::log::fatal("Pattern with name {}:{} didn't match template", evaluatedPattern.getTypeName(), evaluatedPattern.getVariableName());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int result = EXIT_SUCCESS;
|
||||
|
||||
addFunctions();
|
||||
|
||||
for (u32 i = 0; i < 16; i++) {
|
||||
result = test(argc, argv);
|
||||
if (result != EXIT_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT {
|
||||
for (auto &[key, value] : TestPattern::getTests())
|
||||
delete value;
|
||||
};
|
||||
|
||||
if (result == EXIT_SUCCESS)
|
||||
hex::log::info("Success!");
|
||||
else
|
||||
hex::log::info("Failed!");
|
||||
|
||||
return result;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#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"
|
||||
#include "test_patterns/test_pattern_bitfields.hpp"
|
||||
#include "test_patterns/test_pattern_math.hpp"
|
||||
#include "test_patterns/test_pattern_rvalues.hpp"
|
||||
#include "test_patterns/test_pattern_namespaces.hpp"
|
||||
#include "test_patterns/test_pattern_extra_semicolon.hpp"
|
||||
#include "test_patterns/test_pattern_pointers.hpp"
|
||||
#include "test_patterns/test_pattern_arrays.hpp"
|
||||
#include "test_patterns/test_pattern_nested_structs.hpp"
|
||||
|
||||
std::array Tests = {
|
||||
TEST(Placement),
|
||||
TEST(Structs),
|
||||
TEST(Unions),
|
||||
TEST(Enums),
|
||||
TEST(Literals),
|
||||
TEST(Padding),
|
||||
TEST(SucceedingAssert),
|
||||
TEST(FailingAssert),
|
||||
TEST(Bitfields),
|
||||
TEST(Math),
|
||||
TEST(RValues),
|
||||
TEST(Namespaces),
|
||||
TEST(ExtraSemicolon),
|
||||
TEST(Pointers),
|
||||
TEST(Arrays),
|
||||
TEST(NestedStructs),
|
||||
};
|
Binary file not shown.
Before Width: | Height: | Size: 164 KiB |
Loading…
x
Reference in New Issue
Block a user