tests: Refactor to add support for other types of tests

This commit is contained in:
WerWolv
2021-10-12 21:32:33 +02:00
parent b12cd66679
commit 9b316795fc
33 changed files with 133 additions and 41 deletions

View File

@@ -0,0 +1,72 @@
#pragma once
#include <string>
#include <vector>
#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:
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* create(const std::string &typeName, const std::string &varName, auto ... args) {
auto pattern = new T(args...);
pattern->setTypeName(typeName);
pattern->setVariableName(varName);
return pattern;
}
[[nodiscard]]
virtual std::string getSourceCode() const = 0;
[[nodiscard]]
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<PatternData*> m_patterns;
Mode m_mode;
static inline std::map<std::string, TestPattern*> s_tests;
};
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternBitfields : public TestPattern {
public:
TestPatternBitfields() : TestPattern("Bitfields") {
auto testBitfield = create<PatternDataBitfield>("TestBitfield", "testBitfield", 0x12, (4 * 4) / 8, nullptr);
testBitfield->setEndian(std::endian::big);
testBitfield->setFields({
create<PatternDataBitfieldField>("", "a", 0x12, 0, 4, nullptr),
create<PatternDataBitfieldField>("", "b", 0x12, 4, 4, nullptr),
create<PatternDataBitfieldField>("", "c", 0x12, 8, 4, nullptr),
create<PatternDataBitfieldField>("", "d", 0x12, 12, 4, nullptr)
});
addPattern(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");
)";
}
};
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternEnums : public TestPattern {
public:
TestPatternEnums() : TestPattern("Enums"){
auto testEnum = create<PatternDataEnum>("TestEnum", "testEnum", 0x08, sizeof(u32), nullptr);
testEnum->setEnumValues({
{ u128(0x0000), "A" },
{ s128(0x0C), "B" },
{ u128(0x0D), "C" },
{ u128(0x0E), "D" },
});
testEnum->setEndian(std::endian::big);
addPattern(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");
)";
}
};
}

View File

@@ -0,0 +1,23 @@
#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"(
)";
}
};
}

View File

@@ -0,0 +1,35 @@
#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;
)";
}
};
}

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(100U == 0x64U, MSG);
std::assert(-100 == -0x64, MSG);
std::assert(3.14159F > 1.414D, MSG);
std::assert('A' == 0x41, MSG);
)";
}
};
}

View File

@@ -0,0 +1,76 @@
#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(~0x00 == 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");
)";
}
};
}

View File

@@ -0,0 +1,42 @@
#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");
)";
}
};
}

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>("TestStruct", "testStruct", 0x100, sizeof(s32) + 20 + sizeof(u8[0x10]), nullptr);
auto variable = create<PatternDataSigned>("s32", "variable", 0x100, sizeof(s32), nullptr);
auto padding = create<PatternDataPadding>("padding", "", 0x100 + sizeof(s32), 20, nullptr);
auto array = create<PatternDataStaticArray>("u8", "array", 0x100 + sizeof(s32) + 20, sizeof(u8[0x10]), nullptr);
array->setEntries(create<PatternDataUnsigned>("u8", "", 0x100 + sizeof(s32) + 20, sizeof(u8), nullptr), 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

@@ -0,0 +1,35 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternPlacement : public TestPattern {
public:
TestPatternPlacement() : TestPattern("Placement") {
// placementVar
{
addPattern(create<PatternDataUnsigned>("u32", "placementVar", 0x00, sizeof(u32), nullptr));
}
// placementArray
{
auto placementArray = create<PatternDataStaticArray>("u8", "placementArray", 0x10, sizeof(u8) * 10, nullptr);
placementArray->setEntries(create<PatternDataUnsigned>("u8", "", 0x10, sizeof(u8), nullptr), 10);
addPattern(placementArray);
}
}
~TestPatternPlacement() override = default;
[[nodiscard]]
std::string getSourceCode() const override {
return R"(
u32 placementVar @ 0x00;
u8 placementArray[10] @ 0x10;
)";
}
};
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "test_pattern.hpp"
namespace hex::test {
class TestPatternPointers : public TestPattern {
public:
TestPatternPointers() : TestPattern("Pointers") {
// placementPointer
{
auto placementPointer = create<PatternDataPointer>("", "placementPointer", 0x0C, sizeof(u8), nullptr);
auto pointedTo = create<PatternDataUnsigned>("u32", "", 0x49, sizeof(u32), nullptr);
placementPointer->setPointedAtPattern(pointedTo);
addPattern(placementPointer);
}
}
~TestPatternPointers() override = default;
[[nodiscard]]
std::string getSourceCode() const override {
return R"(
u32 *placementPointer : u8 @ 0x0C;
)";
}
};
}

View File

@@ -0,0 +1,40 @@
#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!");
)";
}
};
}

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>("TestStruct", "testStruct", 0x100, sizeof(s32) + sizeof(u8[0x10]), nullptr);
auto variable = create<PatternDataSigned>("s32", "variable", 0x100, sizeof(s32), nullptr);
auto array = create<PatternDataStaticArray>("u8", "array", 0x100 + sizeof(s32), sizeof(u8[0x10]), nullptr);
array->setEntries(create<PatternDataUnsigned>("u8", "", 0x100 + sizeof(s32), sizeof(u8), nullptr), 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>("TestUnion", "testUnion", 0x200, sizeof(u128), nullptr);
auto array = create<PatternDataStaticArray>("s32", "array", 0x200, sizeof(s32[2]), nullptr);
array->setEntries(create<PatternDataSigned>("s32", "", 0x200, sizeof(s32), nullptr), 2);
auto variable = create<PatternDataUnsigned>("u128", "variable", 0x200, sizeof(u128), nullptr);
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;
)";
}
};
}