173 lines
5.4 KiB
C++
173 lines
5.4 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
#include <array>
|
|
#include <cstdio>
|
|
#include <filesystem>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Helper function to execute a command and capture output
|
|
std::string exec_command(const std::string& cmd) {
|
|
std::array<char, 128> buffer;
|
|
std::string result;
|
|
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
|
|
|
if (!pipe) {
|
|
return "";
|
|
}
|
|
|
|
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
|
result += buffer.data();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
TEST_CASE("gwatch binary exists and is executable", "[integration]") {
|
|
std::filesystem::path gwatch_path = "./build/gwatch";
|
|
|
|
if (!std::filesystem::exists(gwatch_path)) {
|
|
WARN("gwatch binary not found at ./build/gwatch");
|
|
return;
|
|
}
|
|
|
|
REQUIRE(std::filesystem::exists(gwatch_path));
|
|
|
|
// Check if it's executable
|
|
auto perms = std::filesystem::status(gwatch_path).permissions();
|
|
bool is_executable = (perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none;
|
|
REQUIRE(is_executable);
|
|
}
|
|
|
|
TEST_CASE("gwatch shows help message", "[integration]") {
|
|
std::filesystem::path gwatch_path = "./build/gwatch";
|
|
|
|
if (!std::filesystem::exists(gwatch_path)) {
|
|
WARN("gwatch binary not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
std::string output = exec_command("./build/gwatch --help");
|
|
|
|
// Help should mention the main options
|
|
REQUIRE(output.find("--exec") != std::string::npos);
|
|
REQUIRE(output.find("--var") != std::string::npos);
|
|
}
|
|
|
|
TEST_CASE("gwatch requires both --exec and --var arguments", "[integration]") {
|
|
std::filesystem::path gwatch_path = "./build/gwatch";
|
|
|
|
if (!std::filesystem::exists(gwatch_path)) {
|
|
WARN("gwatch binary not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
// Test missing both arguments
|
|
std::string output = exec_command("./build/gwatch 2>&1");
|
|
bool has_error = (output.find("required") != std::string::npos ||
|
|
output.find("Error") != std::string::npos);
|
|
REQUIRE(has_error);
|
|
}
|
|
|
|
TEST_CASE("gwatch detects non-existent variable", "[integration]") {
|
|
std::filesystem::path gwatch_path = "./build/gwatch";
|
|
std::filesystem::path test_binary = "./test_access";
|
|
|
|
if (!std::filesystem::exists(gwatch_path)) {
|
|
WARN("gwatch binary not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
if (!std::filesystem::exists(test_binary)) {
|
|
WARN("test_access binary not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
std::string output = exec_command(
|
|
"./build/gwatch --var nonexistent_var_xyz --exec ./test_access 2>&1");
|
|
|
|
bool found_error = (output.find("not found") != std::string::npos);
|
|
REQUIRE(found_error);
|
|
}
|
|
|
|
TEST_CASE("gwatch handles missing executable", "[integration]") {
|
|
std::filesystem::path gwatch_path = "./build/gwatch";
|
|
|
|
if (!std::filesystem::exists(gwatch_path)) {
|
|
WARN("gwatch binary not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
std::string output = exec_command(
|
|
"./build/gwatch --var some_var --exec /nonexistent/path 2>&1");
|
|
|
|
REQUIRE((output.find("Cannot open") != std::string::npos ||
|
|
output.find("Error") != std::string::npos));
|
|
}
|
|
|
|
TEST_CASE("Test binaries compile correctly", "[integration]") {
|
|
// Verify test programs exist
|
|
SECTION("test_access") {
|
|
if (std::filesystem::exists("./test_access")) {
|
|
REQUIRE(true);
|
|
|
|
// Try to check if it has debug symbols
|
|
std::string output = exec_command("file ./test_access");
|
|
// Should mention it's an ELF executable
|
|
REQUIRE(output.find("ELF") != std::string::npos);
|
|
} else {
|
|
WARN("test_access not found");
|
|
}
|
|
}
|
|
|
|
SECTION("test_with_args") {
|
|
if (std::filesystem::exists("./test_with_args")) {
|
|
REQUIRE(true);
|
|
|
|
std::string output = exec_command("file ./test_with_args");
|
|
REQUIRE(output.find("ELF") != std::string::npos);
|
|
} else {
|
|
WARN("test_with_args not found");
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("DWARF debug information is present in test binaries", "[integration]") {
|
|
SECTION("test_access has DWARF info") {
|
|
if (!std::filesystem::exists("./test_access")) {
|
|
WARN("test_access not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
// Check for debug sections using readelf
|
|
std::string output = exec_command("readelf -S ./test_access 2>&1");
|
|
|
|
// Should have debug sections if compiled with -g
|
|
bool has_debug = (output.find(".debug_") != std::string::npos);
|
|
|
|
if (!has_debug) {
|
|
WARN("test_access may not have debug symbols. Compile with: gcc -g -O0 -o test_access test_access.c");
|
|
}
|
|
|
|
REQUIRE(has_debug);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Command-line argument parsing", "[integration]") {
|
|
// Test that arguments after -- are properly handled
|
|
std::filesystem::path gwatch_path = "./build/gwatch";
|
|
|
|
if (!std::filesystem::exists(gwatch_path)) {
|
|
WARN("gwatch binary not found, skipping test");
|
|
return;
|
|
}
|
|
|
|
// This should at least parse correctly (even if the var doesn't exist)
|
|
// We're mainly checking that the -- separator doesn't cause a crash
|
|
std::string output = exec_command(
|
|
"./build/gwatch --var test_var --exec ./test_with_args -- arg1 arg2 2>&1");
|
|
|
|
// Should either find the var or report it's not found, but not crash
|
|
REQUIRE(!output.empty());
|
|
}
|