Given the engine can afford days of compute (fuzzing-grade), widen the solver budgets so hard queries resolve instead of timing out: - checkAdaptive escalation ceiling raised to 1 hour per query (was 8x base) - budget_seconds 7200 -> 604800 (7 days) - per_tu_timeout 900 -> 86400 (24h) A single hard query getting up to an hour of escalating compute is cheap relative to a lost vulnerability.
78 lines
3.3 KiB
C++
78 lines
3.3 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
#include <set>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
#include "../../include/fold/cli/scan_option_catalog.hpp"
|
|
|
|
TEST_CASE("scan option catalog has unique canonical and compatibility names",
|
|
"[scan-options][contract]") {
|
|
std::set<std::string_view> keys;
|
|
std::set<std::string_view> cli_flags;
|
|
std::set<std::string_view> mcp_names;
|
|
std::size_t mcp_count = 0;
|
|
|
|
const auto& catalog = fold::cli::scanOptionCatalog();
|
|
REQUIRE(catalog.size() >= 50);
|
|
for (const auto& option : catalog) {
|
|
REQUIRE_FALSE(option.key.empty());
|
|
REQUIRE_FALSE(option.description.empty());
|
|
REQUIRE(keys.insert(option.key).second);
|
|
if (option.cli_exposed)
|
|
REQUIRE(cli_flags.insert(option.cli_flag).second);
|
|
if (!option.mcp_exposed)
|
|
continue;
|
|
++mcp_count;
|
|
REQUIRE(mcp_names.insert(option.key).second);
|
|
for (const auto alias : option.mcp_aliases)
|
|
REQUIRE(mcp_names.insert(alias).second);
|
|
}
|
|
REQUIRE(mcp_count == 19);
|
|
}
|
|
|
|
TEST_CASE("scan option catalog resolves aliases and applies typed values",
|
|
"[scan-options][contract]") {
|
|
const auto* binary = fold::cli::findScanOption("binary_path");
|
|
REQUIRE(binary != nullptr);
|
|
REQUIRE(binary->key == "binary");
|
|
REQUIRE(binary->cli_flag == "--binary");
|
|
|
|
const auto* max_functions = fold::cli::findScanOption("max_functions");
|
|
REQUIRE(max_functions != nullptr);
|
|
REQUIRE(max_functions->key == "binary_max_functions");
|
|
|
|
fold::cli::ScanOptions options;
|
|
REQUIRE(fold::cli::applyScanOption(options, "binary_path", std::string("app.bin")));
|
|
REQUIRE(fold::cli::applyScanOption(options, "max_functions", 64));
|
|
REQUIRE(fold::cli::applyScanOption(options, "nullable_allocations", true));
|
|
REQUIRE(fold::cli::applyScanOption(options, "per_tu_timeout", 17U));
|
|
REQUIRE(fold::cli::applyScanOption(options, "mode", std::string("binary")));
|
|
REQUIRE(
|
|
fold::cli::applyScanOption(options, "configuration_profile", std::string("profile.json")));
|
|
|
|
REQUIRE(options.binary_path == "app.bin");
|
|
REQUIRE(options.binary_max_functions == 64);
|
|
REQUIRE(options.nullable_allocations);
|
|
REQUIRE(options.per_tu_timeout_seconds == 17U);
|
|
REQUIRE(options.mode == "binary");
|
|
REQUIRE(options.configuration_profile_path == "profile.json");
|
|
REQUIRE(options.mode_explicit);
|
|
REQUIRE_FALSE(fold::cli::applyScanOption(options, "budget_seconds", true));
|
|
REQUIRE_FALSE(fold::cli::applyScanOption(options, "not_an_option", 1));
|
|
}
|
|
|
|
TEST_CASE("scan option catalog defaults match the runtime contract", "[scan-options][contract]") {
|
|
const auto* mode = fold::cli::findScanOption("mode");
|
|
const auto* budget = fold::cli::findScanOption("budget_seconds");
|
|
const auto* per_query = fold::cli::findScanOption("per_query_ms");
|
|
const auto* nullable = fold::cli::findScanOption("nullable_allocations");
|
|
REQUIRE(mode != nullptr);
|
|
REQUIRE(budget != nullptr);
|
|
REQUIRE(per_query != nullptr);
|
|
REQUIRE(nullable != nullptr);
|
|
|
|
REQUIRE(std::get<std::string_view>(mode->default_value) == "auto");
|
|
REQUIRE(std::get<int>(budget->default_value) == 604800);
|
|
REQUIRE(std::get<int>(per_query->default_value) == 30000);
|
|
REQUIRE_FALSE(std::get<bool>(nullable->default_value));
|
|
}
|