mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
tests: Added automatic pattern tests
This commit is contained in:
5
.github/FUNDING.yml
vendored
Normal file
5
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Sponsor links
|
||||
|
||||
patreon: werwolv
|
||||
custom: https://werwolv.net/donate
|
||||
github: WerWolv
|
||||
51
.github/workflows/tests.yml
vendored
Normal file
51
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: "Unit Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ '*' ]
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: 🧪 Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
build-essential \
|
||||
gcc-11 \
|
||||
g++-11 \
|
||||
lld \
|
||||
${PKGCONF:-} \
|
||||
cmake \
|
||||
make \
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-11 CXX=g++-11 cmake \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DLIBPL_ENABLE_TESTS=OFF \
|
||||
..
|
||||
make -j4
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
tests/cmake-build-debug/
|
||||
|
||||
.idea/
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -2,3 +2,6 @@
|
||||
path = yara/official_rules
|
||||
url = https://github.com/Yara-Rules/rules
|
||||
branch = master
|
||||
[submodule "tests/lib/pl"]
|
||||
path = tests/lib/pl
|
||||
url = https://github.com/WerWolv/PatternLanguage
|
||||
|
||||
@@ -83,4 +83,7 @@ Hex patterns, include patterns and magic files for the use with the ImHex Hex Ed
|
||||
|
||||
## Contributing
|
||||
|
||||
If you want to contribute a file to the database, please make a PR which adds it to the right folder and adds a new entry to the table in this readme. Thanks a lot :)
|
||||
If you want to contribute a file to the database, please make a PR which adds it to the right folder and adds a new entry to the table in this readme.
|
||||
To take advantage of the automatic pattern testing, please consider adding a test file named `<pattern_name>.hexpat.<extension>` to the `/tests/patterns/test_data` directory. Try to keep this file as small as possible so the repository doesn't become excessively large
|
||||
|
||||
Thanks a lot :)
|
||||
11
tests/CMakeLists.txt
Normal file
11
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(tests)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
add_subdirectory(lib/pl)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_subdirectory(patterns)
|
||||
1
tests/lib/pl
Submodule
1
tests/lib/pl
Submodule
Submodule tests/lib/pl added at d399836b69
38
tests/patterns/CMakeLists.txt
Normal file
38
tests/patterns/CMakeLists.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(patterns_tests)
|
||||
|
||||
set(TOP_LEVEL "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
||||
|
||||
file(GLOB PATTERNS
|
||||
"${TOP_LEVEL}/patterns/*.hexpat"
|
||||
)
|
||||
|
||||
set(PATTERN_INCLUDES "${TOP_LEVEL}/includes/std")
|
||||
|
||||
add_executable(patterns_tests
|
||||
source/main.cpp
|
||||
)
|
||||
|
||||
target_include_directories(patterns_tests PRIVATE include)
|
||||
target_link_libraries(patterns_tests libpl)
|
||||
|
||||
set_target_properties(patterns_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
foreach (pattern IN LISTS PATTERNS)
|
||||
get_filename_component(PATTERN_NAME ${pattern} NAME)
|
||||
|
||||
file(GLOB TEST_FILES "${CMAKE_CURRENT_SOURCE_DIR}/test_data/${PATTERN_NAME}.*")
|
||||
|
||||
message(STATUS ${CMAKE_CURRENT_SOURCE_DIR}/test_data/${PATTERN_NAME}.*)
|
||||
if (TEST_FILES)
|
||||
list(GET TEST_FILES 0 TEST_FILE)
|
||||
else ()
|
||||
set(TEST_FILE "")
|
||||
endif ()
|
||||
|
||||
set(TEST_NAME "Patterns/${PATTERN_NAME}")
|
||||
|
||||
add_test(NAME ${TEST_NAME} COMMAND patterns_tests "${PATTERN_NAME}" "${pattern}" "${PATTERN_INCLUDES}" "${TEST_FILE}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set_tests_properties(${TEST_NAME} PROPERTIES SKIP_RETURN_CODE 77)
|
||||
endforeach ()
|
||||
75
tests/patterns/source/main.cpp
Normal file
75
tests/patterns/source/main.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include <pl.hpp>
|
||||
#include <helpers/file.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#define EXIT_SKIP 77
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// If only 4 arguments have been provided, then no test file was provided. Skip the test in that case
|
||||
if (argc == 4)
|
||||
return EXIT_SKIP;
|
||||
|
||||
// Any number of arguments other than 5 are invalid
|
||||
if (argc != 5)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Extract command line arguments
|
||||
const std::string patternName = argv[1];
|
||||
const std::fs::path patternFilePath = argv[2];
|
||||
const std::fs::path includePath = argv[3];
|
||||
const std::fs::path testFilePath = argv[4];
|
||||
|
||||
if (testFilePath.empty())
|
||||
return EXIT_SKIP;
|
||||
|
||||
fmt::print("Running test {} on test file {}\n", patternName, testFilePath.stem().string());
|
||||
|
||||
// Open pattern file
|
||||
pl::fs::File patternFile(patternFilePath, pl::fs::File::Mode::Read);
|
||||
if (!patternFile.isValid())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Open test file
|
||||
pl::fs::File testFile(testFilePath, pl::fs::File::Mode::Read);
|
||||
if (!testFile.isValid())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Setup Pattern Language Runtime
|
||||
pl::PatternLanguage runtime;
|
||||
{
|
||||
constexpr auto DummyPragmaHandler = [](const auto&, const auto&){ return true; };
|
||||
|
||||
runtime.setDataSource([&](pl::u64 address, pl::u8 *data, size_t size) {
|
||||
testFile.seek(address);
|
||||
testFile.readBuffer(data, size);
|
||||
}, 0x00, testFile.getSize());
|
||||
runtime.setDangerousFunctionCallHandler([]{ return true; });
|
||||
runtime.setIncludePaths({ includePath });
|
||||
runtime.addPragma("MIME", DummyPragmaHandler);
|
||||
}
|
||||
|
||||
// Execute pattern
|
||||
if (!runtime.executeString(patternFile.readString())) {
|
||||
fmt::print("Error during execution!\n");
|
||||
|
||||
if (const auto &hardError = runtime.getError(); hardError.has_value())
|
||||
fmt::print("Hard error: {}\n\n", hardError.value().what());
|
||||
|
||||
for (const auto &[level, message] : runtime.getConsoleLog()) {
|
||||
switch (level) {
|
||||
case pl::LogConsole::Level::Debug: fmt::print(" [DEBUG] "); break;
|
||||
case pl::LogConsole::Level::Info: fmt::print(" [INFO] "); break;
|
||||
case pl::LogConsole::Level::Warning: fmt::print(" [WARN] "); break;
|
||||
case pl::LogConsole::Level::Error: fmt::print(" [ERROR] "); break;
|
||||
}
|
||||
|
||||
fmt::print("{}\n", message);
|
||||
}
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user