#include import cargoxx.resolver; import cargoxx.util; import std; using cargoxx::resolver::brute_scan; using cargoxx::util::ErrorCode; namespace { auto fresh_store() -> std::filesystem::path { auto d = std::filesystem::temp_directory_path() / std::format("cargoxx-brute-scan-{}", std::random_device{}()); std::filesystem::create_directories(d / "lib"); std::filesystem::create_directories(d / "include"); return d; } void touch_lib(const std::filesystem::path& store, std::string_view name) { std::ofstream{store / "lib" / std::string{name}}; } void touch_include(const std::filesystem::path& store, std::string_view rel) { auto p = store / "include" / rel; std::filesystem::create_directories(p.parent_path()); std::ofstream{p}; } } // namespace TEST_CASE("brute_scan collects lib*.a and lib*.so files", "[resolver][brute_scan]") { auto store = fresh_store(); touch_lib(store, "libfoo.a"); touch_lib(store, "libbar.so"); touch_lib(store, "libbaz.so.1.2.3"); touch_lib(store, "not-a-lib.txt"); touch_include(store, "foo.h"); auto r = brute_scan(store, "foo"); REQUIRE(r.has_value()); REQUIRE(r->lib_files.size() == 3); auto has = [&](std::string_view suffix) { return std::ranges::any_of(r->lib_files, [&](const auto& p) { return std::string_view{p}.ends_with(suffix); }); }; REQUIRE(has("libfoo.a")); REQUIRE(has("libbar.so")); REQUIRE(has("libbaz.so.1.2.3")); } TEST_CASE("brute_scan exposes include/ as a single search directory", "[resolver][brute_scan]") { auto store = fresh_store(); touch_lib(store, "libsdl.a"); touch_include(store, "SDL2/SDL.h"); touch_include(store, "SDL2/SDL_video.h"); auto r = brute_scan(store, "sdl"); REQUIRE(r.has_value()); REQUIRE(r->include_dirs.size() == 1); REQUIRE(std::string_view{r->include_dirs[0]}.ends_with("/include")); } TEST_CASE("brute_scan errors when neither libs nor headers are present", "[resolver][brute_scan]") { auto d = std::filesystem::temp_directory_path() / std::format("cargoxx-brute-empty-{}", std::random_device{}()); std::filesystem::create_directories(d); auto r = brute_scan(d, "ghost"); REQUIRE_FALSE(r.has_value()); REQUIRE(r.error().code == ErrorCode::ResolutionUnknownPackage); } TEST_CASE("brute_scan emits sorted lib paths for deterministic codegen", "[resolver][brute_scan]") { auto store = fresh_store(); touch_lib(store, "libzz.a"); touch_lib(store, "libaa.a"); touch_lib(store, "libmm.so"); auto r = brute_scan(store, "x"); REQUIRE(r.has_value()); REQUIRE(r->lib_files.size() == 3); REQUIRE(std::ranges::is_sorted(r->lib_files)); }