feat: simple valgrind integration in vctest & AppImage workflow: change build-type to RelWithDebInfo

This commit is contained in:
MihailRis 2025-01-01 15:47:41 +03:00
parent 727d578e33
commit 4c23dc6adf
2 changed files with 52 additions and 7 deletions

View File

@ -24,18 +24,19 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y build-essential libglfw3-dev libglfw3 libglew-dev \
libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev libcurl4-openssl-dev libgtest-dev cmake squashfs-tools
libglm-dev libpng-dev libopenal-dev libluajit-5.1-dev libvorbis-dev \
libcurl4-openssl-dev libgtest-dev cmake squashfs-tools valgrind
# fix luajit paths
sudo ln -s /usr/lib/x86_64-linux-gnu/libluajit-5.1.a /usr/lib/x86_64-linux-gnu/liblua5.1.a
sudo ln -s /usr/include/luajit-2.1 /usr/include/lua
# install EnTT
git clone https://github.com/skypjack/entt.git
cd entt/build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
sudo make install
cd ../..
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVOXELENGINE_BUILD_APPDIR=1 -DVOXELENGINE_BUILD_TESTS=ON
- name: Build
run: cmake --build build -t install
- name: Run tests

View File

@ -16,6 +16,7 @@ struct Config {
fs::path directory;
fs::path resDir {"res"};
fs::path workingDir {"."};
std::string memchecker = "valgrind";
bool outputAlways = false;
};
@ -29,6 +30,7 @@ static bool perform_keyword(
std::cout << " --tests <path>, -d <path> = tests directory path\n";
std::cout << " --res <path>, -r <path> = 'res' directory path\n";
std::cout << " --user <path>, -u <path> = user directory path\n";
std::cout << " --memchecker <path> = path to valgrind\n";
std::cout << " --output-always = always show tests output\n";
std::cout << std::endl;
return false;
@ -127,6 +129,37 @@ static void display_test_output(
}
}
static void display_segfault_valgrind(
const fs::path& path, const fs::path& name, std::ostream& stream
) {
stream << "[MEMCHECK] " << name << std::endl;
if (fs::exists(path)) {
std::ifstream t(path);
while (!t.eof()) {
std::string line;
std::getline(t, line);
// skip until the terminating signal
if (line.find("Process terminating with default action of signal ") != std::string::npos) {
break;
}
}
std::stringstream ss;
while (!t.eof()) {
std::string line;
std::getline(t, line);
size_t pos = line.find("== ");
if (pos == std::string::npos) {
continue;
}
if (line.find("If you") != std::string::npos) {
break;
}
ss << line.substr(pos + 3) << "\n";
}
stream << ss.str() << std::endl;
}
}
static std::string fix_path(std::string s) {
for (char& c : s) {
if (c == '\\') {
@ -136,7 +169,7 @@ static std::string fix_path(std::string s) {
return s;
}
static bool run_test(const Config& config, const fs::path& path) {
static bool run_test(const Config& config, const fs::path& path, bool memcheck = false) {
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
@ -145,6 +178,9 @@ static bool run_test(const Config& config, const fs::path& path) {
auto name = path.stem();
std::stringstream ss;
if (memcheck) {
ss << config.memchecker << " ";
}
ss << fs::canonical(config.executable) << " --headless";
ss << " --test " << fix_path(path.string());
ss << " --res " << fix_path(config.resDir.string());
@ -162,9 +198,17 @@ static bool run_test(const Config& config, const fs::path& path) {
.count();
if (code) {
display_test_output(outputFile, name, std::cerr);
std::cerr << "[FAILED] " << name << " in " << testTime << " ms" << std::endl;
fs::remove(outputFile);
if (memcheck) {
// valgrind-specific output
display_segfault_valgrind(outputFile, name, std::cerr);
fs::remove(outputFile);
} else {
display_test_output(outputFile, name, std::cerr);
std::cerr << "[FAILED] " << name << " in " << testTime
<< " ms (code=" << code << ")" << std::endl;
fs::remove(outputFile);
run_test(config, path, true);
}
return false;
} else {
if (config.outputAlways) {