#include #include #include #include #include #include #include // Helper function to execute a command and capture output std::string exec_command(const std::string& cmd) { std::array buffer; std::string result; std::unique_ptr 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()); }