test(command): cover exec failure paths
Command tests did not assert behavior when exec fails in child processes. I added deterministic regression coverage that forces execl/execlp failure and verifies non-zero exit status propagation for both open() and forkExec paths. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
56
test/utils/command.cpp
Normal file
56
test/utils/command.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#if __has_include(<catch2/catch_test_macros.hpp>)
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#else
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <list>
|
||||||
|
#include <mutex>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
std::mutex reap_mtx;
|
||||||
|
std::list<pid_t> reap;
|
||||||
|
|
||||||
|
extern "C" int waybar_test_execl(const char* path, const char* arg, ...);
|
||||||
|
extern "C" int waybar_test_execlp(const char* file, const char* arg, ...);
|
||||||
|
|
||||||
|
#define execl waybar_test_execl
|
||||||
|
#define execlp waybar_test_execlp
|
||||||
|
#include "util/command.hpp"
|
||||||
|
#undef execl
|
||||||
|
#undef execlp
|
||||||
|
|
||||||
|
extern "C" int waybar_test_execl(const char* path, const char* arg, ...) {
|
||||||
|
(void)path;
|
||||||
|
(void)arg;
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int waybar_test_execlp(const char* file, const char* arg, ...) {
|
||||||
|
(void)file;
|
||||||
|
(void)arg;
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("command::execNoRead returns 127 when shell exec fails", "[util][command]") {
|
||||||
|
const auto result = waybar::util::command::execNoRead("echo should-not-run");
|
||||||
|
REQUIRE(result.exit_code == waybar::util::command::kExecFailureExitCode);
|
||||||
|
REQUIRE(result.out.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("command::forkExec child exits 127 when shell exec fails", "[util][command]") {
|
||||||
|
const auto pid = waybar::util::command::forkExec("echo should-not-run", "test-output");
|
||||||
|
REQUIRE(pid > 0);
|
||||||
|
|
||||||
|
int status = -1;
|
||||||
|
REQUIRE(waitpid(pid, &status, 0) == pid);
|
||||||
|
REQUIRE(WIFEXITED(status));
|
||||||
|
REQUIRE(WEXITSTATUS(status) == waybar::util::command::kExecFailureExitCode);
|
||||||
|
|
||||||
|
std::scoped_lock<std::mutex> lock(reap_mtx);
|
||||||
|
reap.remove(pid);
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ test_src = files(
|
|||||||
'JsonParser.cpp',
|
'JsonParser.cpp',
|
||||||
'SafeSignal.cpp',
|
'SafeSignal.cpp',
|
||||||
'sleeper_thread.cpp',
|
'sleeper_thread.cpp',
|
||||||
|
'command.cpp',
|
||||||
'css_reload_helper.cpp',
|
'css_reload_helper.cpp',
|
||||||
'../../src/util/css_reload_helper.cpp',
|
'../../src/util/css_reload_helper.cpp',
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user