[M8] cargoxx-pkgs as a flake: cargoxx add → string-form dep
Wrapper: fix cache.nixos.org-1 key; drop AppImage; pin publish to mozart/cargoxx-pkgs.
This commit is contained in:
93
tests/cmd_publish_validation.cpp
Normal file
93
tests/cmd_publish_validation.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// Validation gates for `cargoxx publish` that fail BEFORE any network
|
||||
// I/O. The publish flow performs `nix flake prefetch` + tea API calls,
|
||||
// both of which need live infra. Everything tested here happens earlier
|
||||
// — schema checks of Cargoxx.toml + Cargoxx.lock + git state.
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
import cargoxx.cli;
|
||||
import cargoxx.manifest;
|
||||
import cargoxx.lockfile;
|
||||
import cargoxx.util;
|
||||
import std;
|
||||
|
||||
using cargoxx::cli::cmd_publish;
|
||||
using cargoxx::util::ErrorCode;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace manifest = cargoxx::manifest;
|
||||
namespace lockfile = cargoxx::lockfile;
|
||||
|
||||
namespace {
|
||||
|
||||
auto fresh_dir() -> fs::path {
|
||||
auto d = fs::temp_directory_path() /
|
||||
std::format("cargoxx-publish-test-{}", std::random_device{}());
|
||||
fs::create_directories(d);
|
||||
return d;
|
||||
}
|
||||
|
||||
auto write_manifest(const fs::path& dir, const manifest::Manifest& m) {
|
||||
REQUIRE(manifest::write(m, dir / "Cargoxx.toml").has_value());
|
||||
}
|
||||
|
||||
auto write_lock(const fs::path& dir) {
|
||||
lockfile::Lockfile lock{
|
||||
.version = 1,
|
||||
.packages = {lockfile::LockfilePackage{.name = "foo", .version = "0.1.0"}},
|
||||
};
|
||||
REQUIRE(lockfile::write(lock, dir / "Cargoxx.lock").has_value());
|
||||
}
|
||||
|
||||
auto minimal_pkg() -> manifest::Package {
|
||||
return manifest::Package{
|
||||
.name = "foo",
|
||||
.version = "0.1.0",
|
||||
.edition = manifest::Edition::Cpp23,
|
||||
.license = "MIT",
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("publish rejects a manifest missing [package].license",
|
||||
"[cli][publish]") {
|
||||
auto root = fresh_dir();
|
||||
auto pkg = minimal_pkg();
|
||||
pkg.license = std::nullopt;
|
||||
write_manifest(root, manifest::Manifest{pkg, {}, {}});
|
||||
write_lock(root);
|
||||
|
||||
auto r = cmd_publish(root, /*dry_run=*/true);
|
||||
REQUIRE_FALSE(r.has_value());
|
||||
REQUIRE(r.error().code == ErrorCode::ManifestInvalidField);
|
||||
REQUIRE(r.error().message.find("license") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("publish rejects a project without Cargoxx.lock", "[cli][publish]") {
|
||||
auto root = fresh_dir();
|
||||
write_manifest(root, manifest::Manifest{minimal_pkg(), {}, {}});
|
||||
// No lockfile.
|
||||
|
||||
auto r = cmd_publish(root, /*dry_run=*/true);
|
||||
REQUIRE_FALSE(r.has_value());
|
||||
REQUIRE(r.error().code == ErrorCode::ManifestNotFound);
|
||||
}
|
||||
|
||||
TEST_CASE("publish rejects path-form dependencies", "[cli][publish]") {
|
||||
auto root = fresh_dir();
|
||||
auto pkg = minimal_pkg();
|
||||
manifest::Dependency dep{
|
||||
.name = "sibling",
|
||||
.version_spec = "*",
|
||||
.source = manifest::DepSource::CargoxxPath,
|
||||
.path = "../sibling",
|
||||
};
|
||||
write_manifest(root, manifest::Manifest{pkg, {dep}, {}});
|
||||
write_lock(root);
|
||||
|
||||
auto r = cmd_publish(root, /*dry_run=*/true);
|
||||
REQUIRE_FALSE(r.has_value());
|
||||
REQUIRE(r.error().code == ErrorCode::ManifestInvalidField);
|
||||
REQUIRE(r.error().message.find("path dep") != std::string::npos);
|
||||
}
|
||||
@@ -181,16 +181,21 @@ optimize = "max"
|
||||
REQUIRE(r.error().code == ErrorCode::ManifestUnknownField);
|
||||
}
|
||||
|
||||
TEST_CASE("parse accepts reserved [package] fields", "[manifest][parse]") {
|
||||
TEST_CASE("parse stores description / repository / homepage on Package",
|
||||
"[manifest][parse]") {
|
||||
auto p = write_manifest(R"(
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
description = "demo"
|
||||
repository = "https://example.com/foo"
|
||||
homepage = "https://example.com"
|
||||
)");
|
||||
auto r = parse(p);
|
||||
REQUIRE(r.has_value());
|
||||
REQUIRE(r->package.description == "demo");
|
||||
REQUIRE(r->package.repository == "https://example.com/foo");
|
||||
REQUIRE(r->package.homepage == "https://example.com");
|
||||
}
|
||||
|
||||
TEST_CASE("parse accepts reserved top-level tables", "[manifest][parse]") {
|
||||
|
||||
@@ -138,3 +138,44 @@ TEST_CASE("write fails when the target directory does not exist",
|
||||
auto r = write(m, "/nonexistent/dir/Cargoxx.toml");
|
||||
REQUIRE_FALSE(r.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("write round-trips a path-form dependency", "[manifest][write]") {
|
||||
Manifest m{
|
||||
pkg("consumer", "0.1.0"),
|
||||
{Dependency{
|
||||
.name = "mylib",
|
||||
.version_spec = "*",
|
||||
.components = {},
|
||||
.source = cargoxx::manifest::DepSource::CargoxxPath,
|
||||
.path = "../mylib",
|
||||
}},
|
||||
{},
|
||||
};
|
||||
REQUIRE(round_trip(m) == m);
|
||||
}
|
||||
|
||||
TEST_CASE("write round-trips a git-form dependency", "[manifest][write]") {
|
||||
Manifest m{
|
||||
pkg("consumer", "0.1.0"),
|
||||
{Dependency{
|
||||
.name = "mylib",
|
||||
.version_spec = "*",
|
||||
.components = {},
|
||||
.source = cargoxx::manifest::DepSource::CargoxxGit,
|
||||
.git_url = "https://gitea.example/me/mylib",
|
||||
.git_rev = "0123456789012345678901234567890123456789",
|
||||
}},
|
||||
{},
|
||||
};
|
||||
REQUIRE(round_trip(m) == m);
|
||||
}
|
||||
|
||||
TEST_CASE("write round-trips description/repository/homepage",
|
||||
"[manifest][write]") {
|
||||
auto p = pkg("foo", "0.1.0");
|
||||
p.description = "demo library";
|
||||
p.repository = "https://gitea.example/me/foo";
|
||||
p.homepage = "https://example.com/foo";
|
||||
Manifest m{p, {}, {}};
|
||||
REQUIRE(round_trip(m) == m);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user