[M3] add codegen::flake_nix

This commit is contained in:
2026-05-08 12:32:43 +00:00
parent 86e88f236f
commit 384fbf6ac4
6 changed files with 275 additions and 1 deletions

138
tests/codegen_flake.cpp Normal file
View File

@@ -0,0 +1,138 @@
#include <catch2/catch_test_macros.hpp>
import cargoxx.codegen;
import cargoxx.manifest;
import cargoxx.layout;
import cargoxx.lockfile;
import cargoxx.linkdb;
import std;
using cargoxx::codegen::flake_nix;
using cargoxx::codegen::GenerateInputs;
using cargoxx::layout::DiscoveredLayout;
using cargoxx::linkdb::Recipe;
using cargoxx::lockfile::Lockfile;
using cargoxx::lockfile::LockfilePackage;
using cargoxx::manifest::Edition;
using cargoxx::manifest::Manifest;
using cargoxx::manifest::Package;
namespace {
auto pkg(std::string name) -> Package {
return Package{
.name = std::move(name),
.version = "0.1.0",
.edition = Edition::Cpp23,
.authors = {},
.license = std::nullopt,
};
}
auto recipe(std::string attr) -> Recipe {
return Recipe{
.nixpkgs_attr = std::move(attr),
.find_package = "",
.targets = {},
.source = "curated",
};
}
auto root_pkg(std::string name, std::string version,
std::optional<std::string> rev = std::nullopt) -> LockfilePackage {
return LockfilePackage{
.name = std::move(name),
.version = std::move(version),
.dependencies = {},
.nixpkgs_attr = std::nullopt,
.nixpkgs_rev = std::move(rev),
.linkdb_source = std::nullopt,
};
}
} // namespace
TEST_CASE("flake_nix renders the package description and rev",
"[codegen][flake]") {
Manifest m{pkg("hello"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("hello", "0.1.0", "abc123def456")}};
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
auto out = flake_nix(in);
REQUIRE(out.find("description = \"hello\";") != std::string::npos);
REQUIRE(out.find("nixpkgs/abc123def456") != std::string::npos);
}
TEST_CASE("flake_nix uses 'nixos-unstable' when no rev is pinned",
"[codegen][flake]") {
Manifest m{pkg("hello"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
auto out = flake_nix(in);
REQUIRE(out.find("nixpkgs/nixos-unstable") != std::string::npos);
}
TEST_CASE("flake_nix emits an empty buildInputs list when there are no deps",
"[codegen][flake]") {
Manifest m{pkg("hello"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
auto out = flake_nix(in);
REQUIRE(out.find("buildInputs = [\n ];") != std::string::npos);
}
TEST_CASE("flake_nix emits one pkgs.<attr> line per dep",
"[codegen][flake]") {
Manifest m{pkg("app"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("app", "0.1.0", "rev42")}};
std::vector<Recipe> recipes = {recipe("fmt_10"), recipe("spdlog")};
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
auto out = flake_nix(in);
REQUIRE(out.find("pkgs.fmt_10") != std::string::npos);
REQUIRE(out.find("pkgs.spdlog") != std::string::npos);
}
TEST_CASE("flake_nix dedupes duplicate nixpkgs_attrs", "[codegen][flake]") {
Manifest m{pkg("app"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("app", "0.1.0", "rev42")}};
// boost appears twice — same nixpkgs_attr from two component-bearing entries
std::vector<Recipe> recipes = {recipe("boost"), recipe("boost")};
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
auto out = flake_nix(in);
auto first = out.find("pkgs.boost");
REQUIRE(first != std::string::npos);
REQUIRE(out.find("pkgs.boost", first + 1) == std::string::npos);
}
TEST_CASE("flake_nix produces deterministic output", "[codegen][flake]") {
Manifest m{pkg("app"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("app", "0.1.0", "rev42")}};
std::vector<Recipe> recipes = {recipe("fmt_10"), recipe("spdlog"),
recipe("nlohmann_json")};
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
auto a = flake_nix(in);
auto b = flake_nix(in);
REQUIRE(a == b);
}
TEST_CASE("flake_nix output ends with a newline", "[codegen][flake]") {
Manifest m{pkg("hello"), {}, {}};
DiscoveredLayout layout{};
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
auto out = flake_nix(in);
REQUIRE_FALSE(out.empty());
REQUIRE(out.back() == '\n');
}