116 lines
4.0 KiB
C++
116 lines
4.0 KiB
C++
// Unit + fixture-based test for resolver::nixpkgs_git_resolve. Avoids
|
|
// the multi-GB nixos/nixpkgs clone by building a tiny throwaway repo
|
|
// that mirrors the relevant slice of the nixpkgs layout.
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
|
|
import cargoxx.resolver;
|
|
import cargoxx.exec;
|
|
import cargoxx.util;
|
|
import std;
|
|
|
|
using cargoxx::resolver::nixpkgs_git_resolve;
|
|
using cargoxx::resolver::pick_youngest_commit;
|
|
|
|
namespace {
|
|
|
|
auto run_git(const std::filesystem::path& cwd, std::vector<std::string> args)
|
|
-> int {
|
|
auto r = cargoxx::exec::run(
|
|
"git", args,
|
|
cargoxx::exec::ExecOptions{
|
|
.cwd = cwd,
|
|
.env_overrides = {{"GIT_COMMITTER_NAME", "t"},
|
|
{"GIT_COMMITTER_EMAIL", "t@t"},
|
|
{"GIT_AUTHOR_NAME", "t"},
|
|
{"GIT_AUTHOR_EMAIL", "t@t"},
|
|
{"GIT_COMMITTER_DATE", "1700000000 +0000"},
|
|
{"GIT_AUTHOR_DATE", "1700000000 +0000"}},
|
|
.timeout = std::chrono::seconds{30},
|
|
.inherit_stdio = false,
|
|
});
|
|
REQUIRE(r.has_value());
|
|
return r->exit_code;
|
|
}
|
|
|
|
auto write_text(const std::filesystem::path& p, std::string_view content) {
|
|
std::filesystem::create_directories(p.parent_path());
|
|
std::ofstream{p} << content;
|
|
}
|
|
|
|
auto fixture_repo(std::string_view pkg, std::string_view v1,
|
|
std::string_view v2) -> std::filesystem::path {
|
|
auto root = std::filesystem::temp_directory_path() /
|
|
std::format("cargoxx-git-fixture-{}", std::random_device{}());
|
|
std::filesystem::create_directories(root);
|
|
REQUIRE(run_git(root, {"init", "-q", "-b", "main"}) == 0);
|
|
|
|
auto nix_path =
|
|
root / "pkgs" / "development" / "libraries" / std::string{pkg} / "default.nix";
|
|
write_text(nix_path, std::format("{{ stdenv }}: stdenv.mkDerivation {{ "
|
|
"version = \"{}\"; }}\n",
|
|
v1));
|
|
REQUIRE(run_git(root, {"add", "."}) == 0);
|
|
REQUIRE(run_git(root, {"commit", "-q", "-m", std::format("init {}", v1)}) == 0);
|
|
|
|
write_text(nix_path, std::format("{{ stdenv }}: stdenv.mkDerivation {{ "
|
|
"version = \"{}\"; }}\n",
|
|
v2));
|
|
REQUIRE(run_git(root, {"add", "."}) == 0);
|
|
REQUIRE(run_git(root, {"commit", "-q", "-m", std::format("bump {}", v2)}) == 0);
|
|
|
|
return root;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("pick_youngest_commit picks the highest-timestamp SHA",
|
|
"[resolver][git]") {
|
|
constexpr std::string_view input =
|
|
"abc111 1700000000\n"
|
|
"def222 1800000000\n"
|
|
"ghi333 1750000000\n";
|
|
auto r = pick_youngest_commit(input);
|
|
REQUIRE(r == std::string{"def222"});
|
|
}
|
|
|
|
TEST_CASE("pick_youngest_commit returns nullopt on empty input",
|
|
"[resolver][git]") {
|
|
REQUIRE_FALSE(pick_youngest_commit("").has_value());
|
|
REQUIRE_FALSE(pick_youngest_commit("\n\n").has_value());
|
|
}
|
|
|
|
TEST_CASE("pick_youngest_commit skips malformed lines", "[resolver][git]") {
|
|
constexpr std::string_view input =
|
|
"garbage\n"
|
|
"abc111 1700000000\n"
|
|
"no-timestamp\n";
|
|
auto r = pick_youngest_commit(input);
|
|
REQUIRE(r == std::string{"abc111"});
|
|
}
|
|
|
|
TEST_CASE("nixpkgs_git_resolve finds the introducing commit",
|
|
"[resolver][git]") {
|
|
auto repo = fixture_repo("fmt", "10.2.0", "10.3.0");
|
|
|
|
auto r = nixpkgs_git_resolve("fmt", "10.2.0", repo);
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->size() == 40); // git sha
|
|
|
|
std::error_code ec;
|
|
std::filesystem::remove_all(repo, ec);
|
|
}
|
|
|
|
TEST_CASE("nixpkgs_git_resolve returns ResolutionVersionNotFound for an absent version",
|
|
"[resolver][git]") {
|
|
auto repo = fixture_repo("fmt", "10.2.0", "10.3.0");
|
|
|
|
auto r = nixpkgs_git_resolve("fmt", "99.99.99", repo);
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code ==
|
|
cargoxx::util::ErrorCode::ResolutionVersionNotFound);
|
|
|
|
std::error_code ec;
|
|
std::filesystem::remove_all(repo, ec);
|
|
}
|