#include #include #include #include #include #include #include namespace { struct TempDir { std::filesystem::path path; TempDir() : path(std::filesystem::temp_directory_path() / ("fold-confirm-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()))) { std::filesystem::create_directories(path); } ~TempDir() { std::filesystem::remove_all(path); } }; void writeFile(const std::filesystem::path& path, const std::string& content) { std::ofstream(path) << content; } std::string locateFoldBinary() { if (const char* env = std::getenv("FOLD_BINARY")) { if (*env && std::filesystem::exists(env)) { return std::filesystem::canonical(env).string(); } } auto cwd = std::filesystem::current_path(); for (const auto& rel : {"../../src/cli/fold", "../../../src/cli/fold", "../src/cli/fold"}) { auto candidate = cwd / rel; if (std::filesystem::exists(candidate)) { return std::filesystem::canonical(candidate).string(); } } return ""; } } // namespace TEST_CASE("fold confirm confirms a null-deref finding", "[confirm][cli]") { const std::string fold_bin = locateFoldBinary(); if (fold_bin.empty()) { WARN("could not locate fold binary; skipping confirm CLI test"); return; } TempDir dir; const auto source = dir.path / "main.cpp"; const auto db = dir.path / "compile_commands.json"; const auto out = dir.path / "confirm.json"; writeFile(source, "int f(bool cond) {\n" " int* p = nullptr;\n" " if (cond) return *p;\n" " return 0;\n" "}\n"); writeFile(db, nlohmann::json::array( {{{"directory", dir.path.string()}, {"command", std::string("clang++ -std=c++20 -c ") + source.string()}, {"file", source.string()}}}) .dump(2)); const std::string cmd = "\"" + fold_bin + "\" confirm --rule null-deref --output \"" + out.string() + "\" \"" + db.string() + "\""; REQUIRE(std::system(cmd.c_str()) == 0); std::ifstream in(out); REQUIRE(in.good()); auto result = nlohmann::json::parse(in); REQUIRE(result["summary"]["total"] == 1); REQUIRE(result["summary"]["confirmed"] == 1); REQUIRE(result["findings"].size() == 1); REQUIRE(result["findings"][0]["detector"] == "null-deref"); REQUIRE(result["findings"][0]["status"] == "confirmed"); REQUIRE(result["findings"][0]["counterexample"]["variables"]["p"] == "0x0"); REQUIRE(result["findings"][0]["counterexample"]["path"].size() >= 1); }