[M6] codegen: dev_recipes, [build].include_dirs, baseline warnings, catch_discover_tests
This commit is contained in:
@@ -168,7 +168,14 @@ auto cmd_build(const fs::path& project_root, bool no_build, bool release,
|
|||||||
}
|
}
|
||||||
auto lock = merge_lockfile(*m, recipes, prior);
|
auto lock = merge_lockfile(*m, recipes, prior);
|
||||||
|
|
||||||
codegen::GenerateInputs in{*m, *layout_result, lock, recipes, project_root};
|
codegen::GenerateInputs in{
|
||||||
|
.manifest = *m,
|
||||||
|
.layout = *layout_result,
|
||||||
|
.lock = lock,
|
||||||
|
.recipes = recipes,
|
||||||
|
.dev_recipes = {},
|
||||||
|
.project_root = project_root,
|
||||||
|
};
|
||||||
auto flake_text = codegen::flake_nix(in);
|
auto flake_text = codegen::flake_nix(in);
|
||||||
auto cmake_text = codegen::cmake_lists(in);
|
auto cmake_text = codegen::cmake_lists(in);
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,6 @@ auto emit_header(const manifest::Manifest& m) -> std::string {
|
|||||||
return std::format(
|
return std::format(
|
||||||
"cmake_minimum_required(VERSION 3.30)\n"
|
"cmake_minimum_required(VERSION 3.30)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Opt into experimental C++ modules dyndep + `import std;` support.\n"
|
|
||||||
"# Required until CMake declares these stable.\n"
|
|
||||||
"set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)\n"
|
"set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)\n"
|
||||||
"set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD \"d0edc3af-4c50-42ea-a356-e2862fe7a444\")\n"
|
"set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD \"d0edc3af-4c50-42ea-a356-e2862fe7a444\")\n"
|
||||||
"set(CMAKE_CXX_MODULE_STD ON)\n"
|
"set(CMAKE_CXX_MODULE_STD ON)\n"
|
||||||
@@ -71,29 +69,43 @@ auto emit_header(const manifest::Manifest& m) -> std::string {
|
|||||||
"# Generated by cargoxx — do not edit.\n"
|
"# Generated by cargoxx — do not edit.\n"
|
||||||
"# Source of truth: ../Cargoxx.toml\n"
|
"# Source of truth: ../Cargoxx.toml\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# ----- toolchain configuration -----\n"
|
|
||||||
"set(CMAKE_CXX_STANDARD {})\n"
|
"set(CMAKE_CXX_STANDARD {})\n"
|
||||||
"set(CMAKE_CXX_STANDARD_REQUIRED ON)\n"
|
"set(CMAKE_CXX_STANDARD_REQUIRED ON)\n"
|
||||||
"# EXTENSIONS=ON for libc++ std-module compatibility (clang 21).\n"
|
|
||||||
"set(CMAKE_CXX_EXTENSIONS ON)\n"
|
"set(CMAKE_CXX_EXTENSIONS ON)\n"
|
||||||
"set(CMAKE_CXX_SCAN_FOR_MODULES ON)\n"
|
"set(CMAKE_CXX_SCAN_FOR_MODULES ON)\n"
|
||||||
"set(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n",
|
"set(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n"
|
||||||
|
"\n"
|
||||||
|
"add_compile_options(-Wall -Wextra -Wpedantic -Wconversion)\n",
|
||||||
m.package.name, edition_to_int(m.package.edition));
|
m.package.name, edition_to_int(m.package.edition));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto emit_find_packages(const std::vector<linkdb::Recipe>& recipes) -> std::string {
|
auto emit_find_packages(const std::vector<linkdb::Recipe>& recipes,
|
||||||
if (recipes.empty()) {
|
const std::vector<linkdb::Recipe>& dev_recipes)
|
||||||
|
-> std::string {
|
||||||
|
if (recipes.empty() && dev_recipes.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
std::string out = "\n# ----- dependencies -----\n";
|
std::string out = "\n# ----- dependencies -----\n";
|
||||||
for (const auto& r : recipes) {
|
for (const auto& r : recipes) {
|
||||||
out += std::format("find_package({})\n", r.find_package);
|
out += std::format("find_package({})\n", r.find_package);
|
||||||
}
|
}
|
||||||
|
for (const auto& r : dev_recipes) {
|
||||||
|
out += std::format("find_package({})\n", r.find_package);
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto recipe_is_catch2(const linkdb::Recipe& r) -> bool {
|
||||||
|
return r.find_package.starts_with("Catch2 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto any_recipe_is_catch2(const std::vector<linkdb::Recipe>& dev_recipes) -> bool {
|
||||||
|
return std::ranges::any_of(dev_recipes, recipe_is_catch2);
|
||||||
|
}
|
||||||
|
|
||||||
auto emit_library(const layout::Target& lib, const std::string& package_name,
|
auto emit_library(const layout::Target& lib, const std::string& package_name,
|
||||||
const std::vector<linkdb::Recipe>& recipes,
|
const std::vector<linkdb::Recipe>& recipes,
|
||||||
|
const std::vector<std::string>& include_dirs,
|
||||||
const fs::path& project_root) -> std::string {
|
const fs::path& project_root) -> std::string {
|
||||||
std::string out = "\n# ----- library target -----\n";
|
std::string out = "\n# ----- library target -----\n";
|
||||||
out += std::format("add_library({} STATIC)\n", package_name);
|
out += std::format("add_library({} STATIC)\n", package_name);
|
||||||
@@ -110,6 +122,13 @@ auto emit_library(const layout::Target& lib, const std::string& package_name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out += ")\n";
|
out += ")\n";
|
||||||
|
if (!include_dirs.empty()) {
|
||||||
|
out += std::format("target_include_directories({} SYSTEM PRIVATE", package_name);
|
||||||
|
for (const auto& d : include_dirs) {
|
||||||
|
out += std::format(" ../{}", d);
|
||||||
|
}
|
||||||
|
out += ")\n";
|
||||||
|
}
|
||||||
out += link_block(package_name, "PUBLIC", false, package_name,
|
out += link_block(package_name, "PUBLIC", false, package_name,
|
||||||
collect_dep_targets(recipes));
|
collect_dep_targets(recipes));
|
||||||
return out;
|
return out;
|
||||||
@@ -140,14 +159,22 @@ auto emit_extra_binary(const layout::Target& bin, const std::string& package_nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto emit_test(const layout::Target& t, const std::string& package_name,
|
auto emit_test(const layout::Target& t, const std::string& package_name,
|
||||||
const std::vector<linkdb::Recipe>& recipes, bool has_lib,
|
const std::vector<linkdb::Recipe>& recipes,
|
||||||
const fs::path& project_root) -> std::string {
|
const std::vector<linkdb::Recipe>& dev_recipes, bool has_lib,
|
||||||
|
bool use_catch_discover, const fs::path& project_root) -> std::string {
|
||||||
auto target = std::format("test_{}", t.name);
|
auto target = std::format("test_{}", t.name);
|
||||||
std::string out = std::format("add_executable({} {})\n", target,
|
std::string out = std::format("add_executable({} {})\n", target,
|
||||||
rel_to_build(t.entry, project_root));
|
rel_to_build(t.entry, project_root));
|
||||||
out += link_block(target, "PRIVATE", has_lib, package_name,
|
std::vector<std::string> link_targets = collect_dep_targets(recipes);
|
||||||
collect_dep_targets(recipes));
|
for (const auto& dt : collect_dep_targets(dev_recipes)) {
|
||||||
|
link_targets.push_back(dt);
|
||||||
|
}
|
||||||
|
out += link_block(target, "PRIVATE", has_lib, package_name, link_targets);
|
||||||
|
if (use_catch_discover) {
|
||||||
|
out += std::format("catch_discover_tests({})\n", target);
|
||||||
|
} else {
|
||||||
out += std::format("add_test(NAME {} COMMAND {})\n", t.name, target);
|
out += std::format("add_test(NAME {} COMMAND {})\n", t.name, target);
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,13 +277,15 @@ auto emit_build_flags(const manifest::BuildSettings& build,
|
|||||||
auto cmake_lists(const GenerateInputs& in) -> std::string {
|
auto cmake_lists(const GenerateInputs& in) -> std::string {
|
||||||
const auto& pkg_name = in.manifest.package.name;
|
const auto& pkg_name = in.manifest.package.name;
|
||||||
const bool has_lib = in.layout.library.has_value();
|
const bool has_lib = in.layout.library.has_value();
|
||||||
|
const bool use_catch_discover = any_recipe_is_catch2(in.dev_recipes);
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
out += emit_header(in.manifest);
|
out += emit_header(in.manifest);
|
||||||
out += emit_find_packages(in.recipes);
|
out += emit_find_packages(in.recipes, in.dev_recipes);
|
||||||
|
|
||||||
if (in.layout.library) {
|
if (in.layout.library) {
|
||||||
out += emit_library(*in.layout.library, pkg_name, in.recipes, in.project_root);
|
out += emit_library(*in.layout.library, pkg_name, in.recipes,
|
||||||
|
in.manifest.build.include_dirs, in.project_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* primary = find_primary_bin(in.layout);
|
const auto* primary = find_primary_bin(in.layout);
|
||||||
@@ -277,8 +306,12 @@ auto cmake_lists(const GenerateInputs& in) -> std::string {
|
|||||||
|
|
||||||
if (!in.layout.tests.empty()) {
|
if (!in.layout.tests.empty()) {
|
||||||
out += "\n# ----- tests -----\nenable_testing()\n";
|
out += "\n# ----- tests -----\nenable_testing()\n";
|
||||||
|
if (use_catch_discover) {
|
||||||
|
out += "include(Catch)\n";
|
||||||
|
}
|
||||||
for (const auto& t : in.layout.tests) {
|
for (const auto& t : in.layout.tests) {
|
||||||
out += emit_test(t, pkg_name, in.recipes, has_lib, in.project_root);
|
out += emit_test(t, pkg_name, in.recipes, in.dev_recipes, has_lib,
|
||||||
|
use_catch_discover, in.project_root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ struct GenerateInputs {
|
|||||||
const layout::DiscoveredLayout& layout;
|
const layout::DiscoveredLayout& layout;
|
||||||
const lockfile::Lockfile& lock;
|
const lockfile::Lockfile& lock;
|
||||||
std::vector<linkdb::Recipe> recipes; // one per manifest dep, same order
|
std::vector<linkdb::Recipe> recipes; // one per manifest dep, same order
|
||||||
|
std::vector<linkdb::Recipe> dev_recipes; // one per dev_dependency, same order
|
||||||
std::filesystem::path project_root;
|
std::filesystem::path project_root;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ TEST_CASE("cmake_lists for a binary-only project", "[codegen][cmake]") {
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("project(hello LANGUAGES CXX)") != std::string::npos);
|
REQUIRE(out.find("project(hello LANGUAGES CXX)") != std::string::npos);
|
||||||
@@ -91,7 +91,7 @@ TEST_CASE("cmake_lists for a library-only project", "[codegen][cmake]") {
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("add_library(widget STATIC)") != std::string::npos);
|
REQUIRE(out.find("add_library(widget STATIC)") != std::string::npos);
|
||||||
@@ -110,7 +110,7 @@ TEST_CASE("cmake_lists wires up library + primary binary", "[codegen][cmake]") {
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("add_library(app STATIC)") != std::string::npos);
|
REQUIRE(out.find("add_library(app STATIC)") != std::string::npos);
|
||||||
@@ -133,7 +133,7 @@ TEST_CASE("cmake_lists emits extra binaries from src/bin/", "[codegen][cmake]")
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("add_executable(app_bin ../src/main.cpp)") != std::string::npos);
|
REQUIRE(out.find("add_executable(app_bin ../src/main.cpp)") != std::string::npos);
|
||||||
@@ -150,7 +150,7 @@ TEST_CASE("cmake_lists emits tests with add_test", "[codegen][cmake]") {
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("enable_testing()") != std::string::npos);
|
REQUIRE(out.find("enable_testing()") != std::string::npos);
|
||||||
@@ -167,7 +167,7 @@ TEST_CASE("cmake_lists emits examples", "[codegen][cmake]") {
|
|||||||
.examples = {src_target(TargetKind::Example, "demo", "examples/demo.cpp")},
|
.examples = {src_target(TargetKind::Example, "demo", "examples/demo.cpp")},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("add_executable(example_demo ../examples/demo.cpp)") !=
|
REQUIRE(out.find("add_executable(example_demo ../examples/demo.cpp)") !=
|
||||||
@@ -188,7 +188,7 @@ TEST_CASE("cmake_lists emits find_package per dep", "[codegen][cmake]") {
|
|||||||
recipe("Boost REQUIRED COMPONENTS filesystem system",
|
recipe("Boost REQUIRED COMPONENTS filesystem system",
|
||||||
{"Boost::filesystem", "Boost::system"}),
|
{"Boost::filesystem", "Boost::system"}),
|
||||||
};
|
};
|
||||||
GenerateInputs in{m, layout, lock, recipes, ROOT};
|
GenerateInputs in{m, layout, lock, recipes, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("find_package(fmt CONFIG REQUIRED)") != std::string::npos);
|
REQUIRE(out.find("find_package(fmt CONFIG REQUIRED)") != std::string::npos);
|
||||||
@@ -216,7 +216,7 @@ TEST_CASE("cmake_lists honors warnings_as_errors", "[codegen][cmake]") {
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("foreach(target_name IN ITEMS app_bin)") != std::string::npos);
|
REQUIRE(out.find("foreach(target_name IN ITEMS app_bin)") != std::string::npos);
|
||||||
@@ -236,7 +236,7 @@ TEST_CASE("cmake_lists honors sanitizers", "[codegen][cmake]") {
|
|||||||
.examples = {},
|
.examples = {},
|
||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
GenerateInputs in{m, layout, lock, {}, ROOT};
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
auto out = cmake_lists(in);
|
auto out = cmake_lists(in);
|
||||||
REQUIRE(out.find("-fsanitize=address,undefined") != std::string::npos);
|
REQUIRE(out.find("-fsanitize=address,undefined") != std::string::npos);
|
||||||
@@ -254,11 +254,11 @@ TEST_CASE("cmake_lists maps editions to standard numbers", "[codegen][cmake]") {
|
|||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
|
|
||||||
Manifest m20{pkg("app", Edition::Cpp20), {}, {}};
|
Manifest m20{pkg("app", Edition::Cpp20), {}, {}};
|
||||||
REQUIRE(cmake_lists(GenerateInputs{m20, layout, lock, {}, ROOT})
|
REQUIRE(cmake_lists(GenerateInputs{m20, layout, lock, {}, {}, ROOT})
|
||||||
.find("set(CMAKE_CXX_STANDARD 20)") != std::string::npos);
|
.find("set(CMAKE_CXX_STANDARD 20)") != std::string::npos);
|
||||||
|
|
||||||
Manifest m26{pkg("app", Edition::Cpp26), {}, {}};
|
Manifest m26{pkg("app", Edition::Cpp26), {}, {}};
|
||||||
REQUIRE(cmake_lists(GenerateInputs{m26, layout, lock, {}, ROOT})
|
REQUIRE(cmake_lists(GenerateInputs{m26, layout, lock, {}, {}, ROOT})
|
||||||
.find("set(CMAKE_CXX_STANDARD 26)") != std::string::npos);
|
.find("set(CMAKE_CXX_STANDARD 26)") != std::string::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,72 @@ TEST_CASE("cmake_lists is deterministic", "[codegen][cmake]") {
|
|||||||
};
|
};
|
||||||
Lockfile lock = lock_minimal();
|
Lockfile lock = lock_minimal();
|
||||||
std::vector<Recipe> recipes = {recipe("fmt CONFIG REQUIRED", {"fmt::fmt"})};
|
std::vector<Recipe> recipes = {recipe("fmt CONFIG REQUIRED", {"fmt::fmt"})};
|
||||||
GenerateInputs in{m, layout, lock, recipes, ROOT};
|
GenerateInputs in{m, layout, lock, recipes, {}, ROOT};
|
||||||
|
|
||||||
REQUIRE(cmake_lists(in) == cmake_lists(in));
|
REQUIRE(cmake_lists(in) == cmake_lists(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("cmake_lists emits baseline warnings", "[codegen][cmake]") {
|
||||||
|
Manifest m{pkg("app"), {}, {}};
|
||||||
|
DiscoveredLayout layout{
|
||||||
|
.library = std::nullopt,
|
||||||
|
.binaries = {src_target(TargetKind::Binary, "app", "src/main.cpp")},
|
||||||
|
.tests = {},
|
||||||
|
.examples = {},
|
||||||
|
};
|
||||||
|
Lockfile lock = lock_minimal();
|
||||||
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
|
auto out = cmake_lists(in);
|
||||||
|
REQUIRE(out.find("add_compile_options(-Wall -Wextra -Wpedantic -Wconversion)") !=
|
||||||
|
std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("cmake_lists emits target_include_directories for [build].include_dirs",
|
||||||
|
"[codegen][cmake]") {
|
||||||
|
Manifest m{
|
||||||
|
.package = pkg("widget"),
|
||||||
|
.build = BuildSettings{.include_dirs = {"third_party", "vendor/json"}},
|
||||||
|
};
|
||||||
|
DiscoveredLayout layout{
|
||||||
|
.library = src_target(TargetKind::Library, "widget", "src/lib.cppm",
|
||||||
|
{"src/lib.cppm"}),
|
||||||
|
.binaries = {},
|
||||||
|
.tests = {},
|
||||||
|
.examples = {},
|
||||||
|
};
|
||||||
|
Lockfile lock = lock_minimal();
|
||||||
|
GenerateInputs in{m, layout, lock, {}, {}, ROOT};
|
||||||
|
|
||||||
|
auto out = cmake_lists(in);
|
||||||
|
REQUIRE(out.find("target_include_directories(widget SYSTEM PRIVATE "
|
||||||
|
"../third_party ../vendor/json)") != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("cmake_lists threads dev_recipes through find_package and tests",
|
||||||
|
"[codegen][cmake]") {
|
||||||
|
Manifest m{pkg("app"), {}, {}};
|
||||||
|
DiscoveredLayout layout{
|
||||||
|
.library = src_target(TargetKind::Library, "app", "src/lib.cppm",
|
||||||
|
{"src/lib.cppm"}),
|
||||||
|
.binaries = {},
|
||||||
|
.tests = {src_target(TargetKind::Test, "basic", "tests/basic.cpp")},
|
||||||
|
.examples = {},
|
||||||
|
};
|
||||||
|
Lockfile lock = lock_minimal();
|
||||||
|
std::vector<Recipe> dev_recipes = {
|
||||||
|
recipe("Catch2 CONFIG REQUIRED", {"Catch2::Catch2WithMain"}),
|
||||||
|
};
|
||||||
|
GenerateInputs in{m, layout, lock, {}, dev_recipes, ROOT};
|
||||||
|
|
||||||
|
auto out = cmake_lists(in);
|
||||||
|
REQUIRE(out.find("find_package(Catch2 CONFIG REQUIRED)") != std::string::npos);
|
||||||
|
REQUIRE(out.find("include(Catch)") != std::string::npos);
|
||||||
|
REQUIRE(out.find("catch_discover_tests(test_basic)") != std::string::npos);
|
||||||
|
REQUIRE(out.find("add_test(NAME basic") == std::string::npos);
|
||||||
|
auto link = out.find("target_link_libraries(test_basic PRIVATE");
|
||||||
|
REQUIRE(link != std::string::npos);
|
||||||
|
auto end = out.find(')', link);
|
||||||
|
auto block = out.substr(link, end - link);
|
||||||
|
REQUIRE(block.find("Catch2::Catch2WithMain") != std::string::npos);
|
||||||
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ TEST_CASE("flake_nix always emits the shared nixos-unstable nixpkgs input",
|
|||||||
Manifest m{pkg("hello"), {}, {}};
|
Manifest m{pkg("hello"), {}, {}};
|
||||||
DiscoveredLayout layout{};
|
DiscoveredLayout layout{};
|
||||||
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
|
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
|
||||||
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
|
GenerateInputs in{m, layout, lock, {}, {}, "/tmp/hello"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
REQUIRE(out.find("description = \"hello\";") != std::string::npos);
|
REQUIRE(out.find("description = \"hello\";") != std::string::npos);
|
||||||
@@ -96,7 +96,7 @@ TEST_CASE("flake_nix emits a per-pinned-dep nixpkgs input", "[codegen][flake]")
|
|||||||
dep_pkg("fmt", "10.2.1", "abc123def456"),
|
dep_pkg("fmt", "10.2.1", "abc123def456"),
|
||||||
}};
|
}};
|
||||||
std::vector<Recipe> recipes = {recipe("fmt_10")};
|
std::vector<Recipe> recipes = {recipe("fmt_10")};
|
||||||
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
|
GenerateInputs in{m, layout, lock, recipes, {}, "/tmp/app"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
// Per-dep input attribute
|
// Per-dep input attribute
|
||||||
@@ -117,7 +117,7 @@ TEST_CASE("flake_nix uses shared `pkgs` for unpinned deps",
|
|||||||
DiscoveredLayout layout{};
|
DiscoveredLayout layout{};
|
||||||
Lockfile lock{1, {root_pkg("app", "0.1.0"), dep_pkg("fmt", "*", std::nullopt)}};
|
Lockfile lock{1, {root_pkg("app", "0.1.0"), dep_pkg("fmt", "*", std::nullopt)}};
|
||||||
std::vector<Recipe> recipes = {recipe("fmt_10")};
|
std::vector<Recipe> recipes = {recipe("fmt_10")};
|
||||||
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
|
GenerateInputs in{m, layout, lock, recipes, {}, "/tmp/app"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
REQUIRE(out.find("pkgs.fmt_10") != std::string::npos);
|
REQUIRE(out.find("pkgs.fmt_10") != std::string::npos);
|
||||||
@@ -133,7 +133,7 @@ TEST_CASE("flake_nix mixes pinned and unpinned deps", "[codegen][flake]") {
|
|||||||
dep_pkg("zlib", "*", std::nullopt),
|
dep_pkg("zlib", "*", std::nullopt),
|
||||||
}};
|
}};
|
||||||
std::vector<Recipe> recipes = {recipe("fmt_10"), recipe("zlib")};
|
std::vector<Recipe> recipes = {recipe("fmt_10"), recipe("zlib")};
|
||||||
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
|
GenerateInputs in{m, layout, lock, recipes, {}, "/tmp/app"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
REQUIRE(out.find("pkgs_nixpkgs_fmt_10_2_1.fmt_10") != std::string::npos);
|
REQUIRE(out.find("pkgs_nixpkgs_fmt_10_2_1.fmt_10") != std::string::npos);
|
||||||
@@ -145,7 +145,7 @@ TEST_CASE("flake_nix emits an empty buildInputs list when there are no deps",
|
|||||||
Manifest m{pkg("hello"), {}, {}};
|
Manifest m{pkg("hello"), {}, {}};
|
||||||
DiscoveredLayout layout{};
|
DiscoveredLayout layout{};
|
||||||
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
|
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
|
||||||
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
|
GenerateInputs in{m, layout, lock, {}, {}, "/tmp/hello"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
REQUIRE(out.find("buildInputs = [\n ];") != std::string::npos);
|
REQUIRE(out.find("buildInputs = [\n ];") != std::string::npos);
|
||||||
@@ -162,7 +162,7 @@ TEST_CASE("flake_nix dedupes deps that share input + attr",
|
|||||||
dep_pkg("boost", "1.84.0", "rev42"),
|
dep_pkg("boost", "1.84.0", "rev42"),
|
||||||
}};
|
}};
|
||||||
std::vector<Recipe> recipes = {recipe("boost"), recipe("boost")};
|
std::vector<Recipe> recipes = {recipe("boost"), recipe("boost")};
|
||||||
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
|
GenerateInputs in{m, layout, lock, recipes, {}, "/tmp/app"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
auto first = out.find("pkgs_nixpkgs_boost_1_84_0.boost");
|
auto first = out.find("pkgs_nixpkgs_boost_1_84_0.boost");
|
||||||
@@ -180,7 +180,7 @@ TEST_CASE("flake_nix produces deterministic output", "[codegen][flake]") {
|
|||||||
dep_pkg("spdlog", "*", std::nullopt),
|
dep_pkg("spdlog", "*", std::nullopt),
|
||||||
}};
|
}};
|
||||||
std::vector<Recipe> recipes = {recipe("fmt_10"), recipe("spdlog")};
|
std::vector<Recipe> recipes = {recipe("fmt_10"), recipe("spdlog")};
|
||||||
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
|
GenerateInputs in{m, layout, lock, recipes, {}, "/tmp/app"};
|
||||||
|
|
||||||
REQUIRE(flake_nix(in) == flake_nix(in));
|
REQUIRE(flake_nix(in) == flake_nix(in));
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ TEST_CASE("flake_nix output ends with a newline", "[codegen][flake]") {
|
|||||||
Manifest m{pkg("hello"), {}, {}};
|
Manifest m{pkg("hello"), {}, {}};
|
||||||
DiscoveredLayout layout{};
|
DiscoveredLayout layout{};
|
||||||
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
|
Lockfile lock{1, {root_pkg("hello", "0.1.0")}};
|
||||||
GenerateInputs in{m, layout, lock, {}, "/tmp/hello"};
|
GenerateInputs in{m, layout, lock, {}, {}, "/tmp/hello"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
REQUIRE_FALSE(out.empty());
|
REQUIRE_FALSE(out.empty());
|
||||||
@@ -205,7 +205,7 @@ TEST_CASE("flake_nix sanitizes hyphens and dots in dep names",
|
|||||||
dep_pkg("range-v3", "0.12.0", "rev123"),
|
dep_pkg("range-v3", "0.12.0", "rev123"),
|
||||||
}};
|
}};
|
||||||
std::vector<Recipe> recipes = {recipe("range-v3")};
|
std::vector<Recipe> recipes = {recipe("range-v3")};
|
||||||
GenerateInputs in{m, layout, lock, recipes, "/tmp/app"};
|
GenerateInputs in{m, layout, lock, recipes, {}, "/tmp/app"};
|
||||||
|
|
||||||
auto out = flake_nix(in);
|
auto out = flake_nix(in);
|
||||||
REQUIRE(out.find("nixpkgs_range_v3_0_12_0.url = "
|
REQUIRE(out.find("nixpkgs_range_v3_0_12_0.url = "
|
||||||
|
|||||||
Reference in New Issue
Block a user