#include import cargoxx.resolver; import cargoxx.util; import std; using cargoxx::resolver::parse_conanfile; using cargoxx::util::ErrorCode; TEST_CASE("parse_conanfile picks up modern set_property form", "[resolver][conan]") { constexpr std::string_view text = R"PY( from conan import ConanFile class FmtConan(ConanFile): name = "fmt" def package_info(self): self.cpp_info.set_property("cmake_file_name", "fmt") self.cpp_info.set_property("cmake_target_name", "fmt::fmt") )PY"; auto r = parse_conanfile(text, "fmt"); REQUIRE(r.has_value()); REQUIRE(r->find_package == "fmt CONFIG REQUIRED"); REQUIRE(r->targets == std::vector{"fmt::fmt"}); } TEST_CASE("parse_conanfile picks up legacy names[] form", "[resolver][conan]") { constexpr std::string_view text = R"PY( class SpdlogConan(ConanFile): def package_info(self): self.cpp_info.names["cmake_find_package"] = "spdlog" )PY"; auto r = parse_conanfile(text, "spdlog"); REQUIRE(r.has_value()); REQUIRE(r->find_package == "spdlog CONFIG REQUIRED"); // Derived target heuristic: spdlog::spdlog REQUIRE(r->targets == std::vector{"spdlog::spdlog"}); } TEST_CASE("parse_conanfile derives cmake_file_name from a colon-namespaced target", "[resolver][conan]") { constexpr std::string_view text = R"PY( self.cpp_info.set_property("cmake_target_name", "Boost::filesystem") )PY"; auto r = parse_conanfile(text, "boost"); REQUIRE(r.has_value()); REQUIRE(r->find_package == "Boost CONFIG REQUIRED"); REQUIRE(r->targets == std::vector{"Boost::filesystem"}); } TEST_CASE("parse_conanfile falls back to the package name when nothing matches", "[resolver][conan]") { constexpr std::string_view text = R"PY( # This recipe gives us nothing useful at the cpp_info level. class OpaqueConan(ConanFile): name = "opaque" )PY"; auto r = parse_conanfile(text, "opaque"); REQUIRE(r.has_value()); REQUIRE(r->find_package == "opaque CONFIG REQUIRED"); REQUIRE(r->targets == std::vector{"opaque::opaque"}); } TEST_CASE("parse_conanfile errors when no information AND no fallback", "[resolver][conan]") { auto r = parse_conanfile("# nothing here", ""); REQUIRE_FALSE(r.has_value()); REQUIRE(r.error().code == ErrorCode::ResolutionUnknownPackage); } TEST_CASE("parse_conanfile accepts single-quoted strings", "[resolver][conan]") { constexpr std::string_view text = R"PY( self.cpp_info.set_property('cmake_target_name', 'absl::strings') self.cpp_info.set_property('cmake_file_name', 'absl') )PY"; auto r = parse_conanfile(text, "abseil"); REQUIRE(r.has_value()); REQUIRE(r->find_package == "absl CONFIG REQUIRED"); REQUIRE(r->targets == std::vector{"absl::strings"}); }