194 lines
6.1 KiB
C++
194 lines
6.1 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
|
|
import cargoxx.layout;
|
|
import cargoxx.util;
|
|
import std;
|
|
|
|
using cargoxx::layout::DiscoveredLayout;
|
|
using cargoxx::layout::discover;
|
|
using cargoxx::layout::Target;
|
|
using cargoxx::layout::TargetKind;
|
|
using cargoxx::util::ErrorCode;
|
|
|
|
namespace {
|
|
|
|
class TempProject {
|
|
public:
|
|
TempProject() {
|
|
root_ = std::filesystem::temp_directory_path() /
|
|
std::format("cargoxx-layout-test-{}", std::random_device{}());
|
|
std::filesystem::create_directories(root_);
|
|
}
|
|
|
|
~TempProject() {
|
|
std::error_code ec;
|
|
std::filesystem::remove_all(root_, ec);
|
|
}
|
|
|
|
TempProject(const TempProject&) = delete;
|
|
TempProject& operator=(const TempProject&) = delete;
|
|
TempProject(TempProject&&) = delete;
|
|
TempProject& operator=(TempProject&&) = delete;
|
|
|
|
auto root() const -> const std::filesystem::path& { return root_; }
|
|
|
|
auto touch(std::string_view rel) -> std::filesystem::path {
|
|
auto p = root_ / rel;
|
|
std::filesystem::create_directories(p.parent_path());
|
|
std::ofstream{p} << "// stub\n";
|
|
return p;
|
|
}
|
|
|
|
private:
|
|
std::filesystem::path root_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("discover returns LayoutNoTarget for an empty src", "[layout]") {
|
|
TempProject p;
|
|
std::filesystem::create_directories(p.root() / "src");
|
|
auto r = discover(p.root(), "foo");
|
|
REQUIRE_FALSE(r.has_value());
|
|
REQUIRE(r.error().code == ErrorCode::LayoutNoTarget);
|
|
}
|
|
|
|
TEST_CASE("discover finds main.cpp as a binary", "[layout]") {
|
|
TempProject p;
|
|
auto main = p.touch("src/main.cpp");
|
|
auto r = discover(p.root(), "foo");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE_FALSE(r->library.has_value());
|
|
REQUIRE(r->binaries.size() == 1);
|
|
REQUIRE(r->binaries[0].kind == TargetKind::Binary);
|
|
REQUIRE(r->binaries[0].name == "foo");
|
|
REQUIRE(r->binaries[0].entry == main);
|
|
}
|
|
|
|
TEST_CASE("discover finds lib.cppm as a library", "[layout]") {
|
|
TempProject p;
|
|
auto lib = p.touch("src/lib.cppm");
|
|
auto r = discover(p.root(), "foo");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->library.has_value());
|
|
REQUIRE(r->library->kind == TargetKind::Library);
|
|
REQUIRE(r->library->name == "foo");
|
|
REQUIRE(r->library->entry == lib);
|
|
REQUIRE(r->library->module_units == std::vector{lib});
|
|
REQUIRE(r->library->additional_sources.empty());
|
|
REQUIRE(r->binaries.empty());
|
|
}
|
|
|
|
TEST_CASE("discover supports lib + main together", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/lib.cppm");
|
|
p.touch("src/main.cpp");
|
|
auto r = discover(p.root(), "foo");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->library.has_value());
|
|
REQUIRE(r->binaries.size() == 1);
|
|
REQUIRE(r->binaries[0].entry.filename() == "main.cpp");
|
|
}
|
|
|
|
TEST_CASE("discover collects nested .cppm and .cpp into the library",
|
|
"[layout]") {
|
|
TempProject p;
|
|
auto lib = p.touch("src/lib.cppm");
|
|
auto inner_cppm = p.touch("src/internal/foo.cppm");
|
|
auto inner_cpp = p.touch("src/internal/foo.cpp");
|
|
auto r = discover(p.root(), "foo");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->library->module_units.size() == 2);
|
|
REQUIRE(std::ranges::find(r->library->module_units, lib) !=
|
|
r->library->module_units.end());
|
|
REQUIRE(std::ranges::find(r->library->module_units, inner_cppm) !=
|
|
r->library->module_units.end());
|
|
REQUIRE(r->library->additional_sources == std::vector{inner_cpp});
|
|
}
|
|
|
|
TEST_CASE("discover excludes src/bin/* from the library walk", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/lib.cppm");
|
|
p.touch("src/bin/tool.cpp");
|
|
auto r = discover(p.root(), "foo");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->library->additional_sources.empty());
|
|
REQUIRE(r->binaries.size() == 1);
|
|
REQUIRE(r->binaries[0].name == "tool");
|
|
}
|
|
|
|
TEST_CASE("discover lists src/bin/*.cpp as additional binaries", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/main.cpp");
|
|
p.touch("src/bin/foo.cpp");
|
|
p.touch("src/bin/bar.cpp");
|
|
auto r = discover(p.root(), "pkg");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->binaries.size() == 3);
|
|
// sorted alphabetically by target name
|
|
REQUIRE(r->binaries[0].name == "bar");
|
|
REQUIRE(r->binaries[1].name == "foo");
|
|
REQUIRE(r->binaries[2].name == "pkg");
|
|
}
|
|
|
|
TEST_CASE("discover does not recurse into src/bin/", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/main.cpp");
|
|
p.touch("src/bin/foo.cpp");
|
|
p.touch("src/bin/sub/nested.cpp"); // should be ignored
|
|
auto r = discover(p.root(), "pkg");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->binaries.size() == 2);
|
|
}
|
|
|
|
TEST_CASE("discover lists tests/*.cpp", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/main.cpp");
|
|
p.touch("tests/alpha.cpp");
|
|
p.touch("tests/beta.cpp");
|
|
p.touch("tests/sub/nested.cpp"); // ignored, no recursion
|
|
auto r = discover(p.root(), "pkg");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->tests.size() == 2);
|
|
REQUIRE(r->tests[0].name == "alpha");
|
|
REQUIRE(r->tests[0].kind == TargetKind::Test);
|
|
REQUIRE(r->tests[1].name == "beta");
|
|
}
|
|
|
|
TEST_CASE("discover lists examples/*.cpp", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/main.cpp");
|
|
p.touch("examples/demo.cpp");
|
|
auto r = discover(p.root(), "pkg");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->examples.size() == 1);
|
|
REQUIRE(r->examples[0].name == "demo");
|
|
REQUIRE(r->examples[0].kind == TargetKind::Example);
|
|
}
|
|
|
|
TEST_CASE("discover ignores non .cpp/.cppm files", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/main.cpp");
|
|
p.touch("src/notes.txt");
|
|
p.touch("src/lib.cppm");
|
|
p.touch("src/internal/header.h"); // headers in src/ are ignored
|
|
auto r = discover(p.root(), "pkg");
|
|
REQUIRE(r.has_value());
|
|
REQUIRE(r->library->module_units.size() == 1);
|
|
REQUIRE(r->library->additional_sources.empty());
|
|
}
|
|
|
|
TEST_CASE("discover output is deterministic across runs", "[layout]") {
|
|
TempProject p;
|
|
p.touch("src/lib.cppm");
|
|
p.touch("src/zeta.cppm");
|
|
p.touch("src/alpha.cppm");
|
|
p.touch("src/middle.cppm");
|
|
auto r1 = discover(p.root(), "pkg");
|
|
auto r2 = discover(p.root(), "pkg");
|
|
REQUIRE(r1.has_value());
|
|
REQUIRE(r2.has_value());
|
|
REQUIRE(*r1 == *r2);
|
|
REQUIRE(std::ranges::is_sorted(r1->library->module_units));
|
|
}
|