fold/tests/integration/test_confirm_cli.cpp

83 lines
2.8 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <chrono>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>
#include <string>
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);
}