189 lines
5.5 KiB
C++
189 lines
5.5 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
|
|
import cargoxx.lockfile;
|
|
import cargoxx.util;
|
|
import std;
|
|
|
|
using cargoxx::lockfile::Lockfile;
|
|
using cargoxx::lockfile::LockfilePackage;
|
|
using cargoxx::lockfile::parse;
|
|
using cargoxx::lockfile::write;
|
|
using cargoxx::util::ErrorCode;
|
|
|
|
namespace {
|
|
|
|
auto tmp_path() -> std::filesystem::path {
|
|
auto d = std::filesystem::temp_directory_path() /
|
|
std::format("cargoxx-lockfile-test-{}", std::random_device{}());
|
|
std::filesystem::create_directories(d);
|
|
return d / "Cargoxx.lock";
|
|
}
|
|
|
|
auto root_pkg(std::string name, std::string version,
|
|
std::vector<std::string> deps = {}) -> LockfilePackage {
|
|
return LockfilePackage{
|
|
.name = std::move(name),
|
|
.version = std::move(version),
|
|
.dependencies = std::move(deps),
|
|
.nixpkgs_attr = std::nullopt,
|
|
.nixpkgs_rev = std::nullopt,
|
|
.linkdb_source = std::nullopt,
|
|
};
|
|
}
|
|
|
|
auto dep_pkg(std::string name, std::string version, std::string attr, std::string rev,
|
|
std::string source = "curated") -> LockfilePackage {
|
|
return LockfilePackage{
|
|
.name = std::move(name),
|
|
.version = std::move(version),
|
|
.dependencies = {},
|
|
.nixpkgs_attr = std::move(attr),
|
|
.nixpkgs_rev = std::move(rev),
|
|
.linkdb_source = std::move(source),
|
|
};
|
|
}
|
|
|
|
auto round_trip(const Lockfile& l) -> Lockfile {
|
|
auto path = tmp_path();
|
|
REQUIRE(write(l, path).has_value());
|
|
auto parsed = parse(path);
|
|
REQUIRE(parsed.has_value());
|
|
return *parsed;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("write round-trips a minimal lockfile", "[lockfile]") {
|
|
Lockfile l{1, {root_pkg("my-project", "0.1.0")}};
|
|
REQUIRE(round_trip(l) == l);
|
|
}
|
|
|
|
TEST_CASE("write round-trips a lockfile with deps", "[lockfile]") {
|
|
Lockfile l{
|
|
1,
|
|
{
|
|
root_pkg("my-project", "0.1.0", {"fmt 10.2.1", "spdlog 1.13.0"}),
|
|
dep_pkg("fmt", "10.2.1", "fmt_10", "8a3f...c2d1"),
|
|
dep_pkg("spdlog", "1.13.0", "spdlog", "8a3f...c2d1"),
|
|
},
|
|
};
|
|
REQUIRE(round_trip(l) == l);
|
|
}
|
|
|
|
TEST_CASE("write round-trips lockfile recipe fields", "[lockfile]") {
|
|
Lockfile l{
|
|
1,
|
|
{
|
|
LockfilePackage{
|
|
.name = "fmt",
|
|
.version = "10.2.1",
|
|
.dependencies = {},
|
|
.nixpkgs_attr = "fmt_10",
|
|
.nixpkgs_rev = std::nullopt,
|
|
.linkdb_source = "conan",
|
|
.find_package = "fmt CONFIG REQUIRED",
|
|
.targets = {"fmt::fmt"},
|
|
.pkg_config_module = std::nullopt,
|
|
.brute_force_libs = {},
|
|
.brute_force_includes = {},
|
|
},
|
|
LockfilePackage{
|
|
.name = "sqlite",
|
|
.version = "*",
|
|
.dependencies = {},
|
|
.nixpkgs_attr = "sqlite",
|
|
.nixpkgs_rev = std::nullopt,
|
|
.linkdb_source = "pkg-config",
|
|
.find_package = "PkgConfig REQUIRED",
|
|
.targets = {"PkgConfig::SQLITE3"},
|
|
.pkg_config_module = "sqlite3",
|
|
.brute_force_libs = {},
|
|
.brute_force_includes = {},
|
|
},
|
|
LockfilePackage{
|
|
.name = "obscure",
|
|
.version = "*",
|
|
.dependencies = {},
|
|
.nixpkgs_attr = "obscure",
|
|
.nixpkgs_rev = std::nullopt,
|
|
.linkdb_source = "brute-force",
|
|
.find_package = "",
|
|
.targets = {"obscure::obscure"},
|
|
.pkg_config_module = std::nullopt,
|
|
.brute_force_libs = {"/nix/store/abc/lib/libobscure.a"},
|
|
.brute_force_includes = {"/nix/store/abc/include"},
|
|
},
|
|
},
|
|
};
|
|
REQUIRE(round_trip(l) == l);
|
|
}
|
|
|
|
TEST_CASE("Lockfile::nixpkgs_rev returns the shared rev", "[lockfile]") {
|
|
Lockfile l{
|
|
1,
|
|
{
|
|
root_pkg("p", "0.1.0", {"fmt 10.2.1"}),
|
|
dep_pkg("fmt", "10.2.1", "fmt_10", "abc123"),
|
|
},
|
|
};
|
|
REQUIRE(l.nixpkgs_rev() == "abc123");
|
|
}
|
|
|
|
TEST_CASE("Lockfile::nixpkgs_rev is nullopt when no deps", "[lockfile]") {
|
|
Lockfile l{1, {root_pkg("p", "0.1.0")}};
|
|
REQUIRE_FALSE(l.nixpkgs_rev().has_value());
|
|
}
|
|
|
|
TEST_CASE("parse rejects a missing file", "[lockfile]") {
|
|
auto r = parse("/nonexistent/Cargoxx.lock");
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::ManifestNotFound);
|
|
}
|
|
|
|
TEST_CASE("parse rejects malformed toml", "[lockfile]") {
|
|
auto path = tmp_path();
|
|
std::ofstream{path} << "version = \nname = \"x\"\n";
|
|
auto r = parse(path);
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::ManifestParseError);
|
|
}
|
|
|
|
TEST_CASE("parse rejects a package missing name", "[lockfile]") {
|
|
auto path = tmp_path();
|
|
std::ofstream{path} << R"(
|
|
version = 1
|
|
|
|
[[package]]
|
|
version = "0.1.0"
|
|
)";
|
|
auto r = parse(path);
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::ManifestInvalidField);
|
|
}
|
|
|
|
TEST_CASE("parse rejects a package missing version", "[lockfile]") {
|
|
auto path = tmp_path();
|
|
std::ofstream{path} << R"(
|
|
version = 1
|
|
|
|
[[package]]
|
|
name = "p"
|
|
)";
|
|
auto r = parse(path);
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::ManifestInvalidField);
|
|
}
|
|
|
|
TEST_CASE("parse defaults version to 1 when omitted", "[lockfile]") {
|
|
auto path = tmp_path();
|
|
std::ofstream{path} << R"(
|
|
[[package]]
|
|
name = "p"
|
|
version = "0.1.0"
|
|
)";
|
|
auto r = parse(path);
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->version == 1);
|
|
REQUIRE(r->packages.size() == 1);
|
|
}
|