use std::fs;
use std::path::Path;
use assert_cmd::Command;
use predicates::str::contains;
use tempfile::tempdir;
fn shipper_cmd() -> Command {
Command::new(assert_cmd::cargo::cargo_bin!("shipper-cli"))
}
fn write_file(path: &Path, content: &str) {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("mkdir");
}
fs::write(path, content).expect("write");
}
fn create_workspace(root: &Path) {
write_file(
&root.join("Cargo.toml"),
r#"
[workspace]
members = ["alpha"]
resolver = "2"
"#,
);
write_file(
&root.join("alpha/Cargo.toml"),
r#"
[package]
name = "alpha"
version = "0.1.0"
edition = "2021"
"#,
);
write_file(&root.join("alpha/src/lib.rs"), "pub fn alpha() {}\n");
}
#[test]
fn plan_succeeds_without_config_file() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
assert!(
!td.path().join(".shipper.toml").exists(),
"precondition: no config file"
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("plan")
.assert()
.success()
.stdout(contains("alpha@0.1.0"))
.stdout(contains("Total packages to publish: 1"));
}
#[test]
fn plan_loads_config_from_workspace_root() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
write_file(
&td.path().join(".shipper.toml"),
r#"
schema_version = "shipper.config.v1"
[policy]
mode = "fast"
"#,
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("plan")
.assert()
.success()
.stdout(contains("alpha@0.1.0"));
}
#[test]
fn config_flag_loads_from_custom_path() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
let custom_config = td.path().join("custom").join("my-config.toml");
write_file(
&custom_config,
r#"
schema_version = "shipper.config.v1"
[policy]
mode = "balanced"
"#,
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("--config")
.arg(&custom_config)
.arg("plan")
.assert()
.success()
.stdout(contains("alpha@0.1.0"));
}
#[test]
fn config_flag_with_missing_file_fails() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
let missing = td.path().join("does-not-exist.toml");
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("--config")
.arg(&missing)
.arg("plan")
.assert()
.failure()
.stderr(contains("Failed to load config from"));
}
#[test]
fn config_registry_name_appears_in_plan_output() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
write_file(
&td.path().join(".shipper.toml"),
r#"
schema_version = "shipper.config.v1"
[registry]
name = "my-private-registry"
api_base = "https://registry.example.com"
"#,
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("plan")
.assert()
.success()
.stdout(contains("my-private-registry"))
.stdout(contains("https://registry.example.com"));
}
#[test]
fn invalid_toml_in_workspace_config_fails() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
write_file(
&td.path().join(".shipper.toml"),
"this is not valid toml {{{{",
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("plan")
.assert()
.failure()
.stderr(contains("Failed to load config from workspace"));
}
#[test]
fn config_with_invalid_values_fails_validation() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
write_file(
&td.path().join(".shipper.toml"),
r#"
schema_version = "shipper.config.v1"
[output]
lines = 0
"#,
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("plan")
.assert()
.failure()
.stderr(contains("validation failed"));
}
#[test]
fn config_flag_with_invalid_toml_fails() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
let bad_config = td.path().join("bad.toml");
write_file(&bad_config, "not valid [[[");
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("--config")
.arg(&bad_config)
.arg("plan")
.assert()
.failure()
.stderr(contains("Failed to load config from"));
}
#[test]
fn cli_registry_flag_overrides_config_registry() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
write_file(
&td.path().join(".shipper.toml"),
r#"
schema_version = "shipper.config.v1"
[registry]
name = "config-registry"
api_base = "https://config.example.com"
"#,
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("--registry")
.arg("cli-registry")
.arg("plan")
.assert()
.success()
.stdout(contains("cli-registry"));
}
#[test]
fn cli_api_base_flag_overrides_config_api_base() {
let td = tempdir().expect("tempdir");
create_workspace(td.path());
write_file(
&td.path().join(".shipper.toml"),
r#"
schema_version = "shipper.config.v1"
[registry]
name = "my-reg"
api_base = "https://config-api.example.com"
"#,
);
shipper_cmd()
.arg("--manifest-path")
.arg(td.path().join("Cargo.toml"))
.arg("--api-base")
.arg("https://cli-api.example.com")
.arg("plan")
.assert()
.success()
.stdout(contains("https://cli-api.example.com"));
}