use super::CrateSource;
use std::path::PathBuf;
fn fixtures_dir() -> PathBuf {
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
manifest_dir
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.join("tests/fixtures")
}
fn format_summaries(packs: &[super::BatteryPackSummary]) -> String {
packs
.iter()
.map(|bp| format!("{} {} -- {}", bp.name, bp.version, bp.description))
.collect::<Vec<_>>()
.join("\n")
}
#[test]
fn list_discovers_local_battery_packs() {
let source = CrateSource::Local(fixtures_dir());
let packs = super::fetch_battery_pack_list(&source, None).unwrap();
let formatted = format_summaries(&packs);
assert!(
formatted.contains("basic-battery-pack"),
"Expected basic-battery-pack"
);
assert!(
formatted.contains("broken-battery-pack"),
"Expected broken-battery-pack"
);
assert!(
formatted.contains("fancy-battery-pack"),
"Expected fancy-battery-pack"
);
assert!(
formatted.contains("managed-battery-pack"),
"Expected managed-battery-pack"
);
}
#[test]
fn list_filter_narrows_results() {
let source = CrateSource::Local(fixtures_dir());
let packs = super::fetch_battery_pack_list(&source, Some("basic")).unwrap();
let formatted = format_summaries(&packs);
assert_eq!(packs.len(), 1, "Expected exactly 1 result");
assert!(
formatted.contains("basic-battery-pack"),
"Expected basic-battery-pack"
);
}
#[test]
fn list_filter_no_match_returns_empty() {
let source = CrateSource::Local(fixtures_dir());
let packs = super::fetch_battery_pack_list(&source, Some("nonexistent")).unwrap();
assert!(packs.is_empty());
}
#[test]
fn list_invalid_workspace_path_errors() {
let source = CrateSource::Local(PathBuf::from("/nonexistent/path"));
let result = super::fetch_battery_pack_list(&source, None);
assert!(result.is_err());
}
#[test]
fn list_short_names_are_correct() {
let source = CrateSource::Local(fixtures_dir());
let packs = super::fetch_battery_pack_list(&source, None).unwrap();
let short_names: Vec<&str> = packs.iter().map(|bp| bp.short_name.as_str()).collect();
assert_eq!(short_names.len(), 4, "Expected 4 packs");
assert!(short_names.contains(&"basic"), "Expected 'basic'");
assert!(short_names.contains(&"broken"), "Expected 'broken'");
assert!(short_names.contains(&"fancy"), "Expected 'fancy'");
assert!(short_names.contains(&"managed"), "Expected 'managed'");
}
#[test]
fn show_detail_excludes_hidden_crates() {
let fancy_path = fixtures_dir().join("fancy-battery-pack");
let detail =
super::fetch_battery_pack_detail("fancy", Some(fancy_path.to_str().unwrap())).unwrap();
assert!(!detail.crates.contains(&"serde".to_string()));
assert!(!detail.crates.contains(&"serde_json".to_string()));
assert!(!detail.crates.contains(&"cc".to_string()));
assert!(detail.crates.contains(&"clap".to_string()));
assert!(detail.crates.contains(&"dialoguer".to_string()));
assert!(detail.crates.contains(&"indicatif".to_string()));
assert!(detail.crates.contains(&"console".to_string()));
assert!(detail.crates.contains(&"assert_cmd".to_string()));
assert!(detail.crates.contains(&"predicates".to_string()));
}
#[test]
fn show_detail_no_hidden_returns_all_crates() {
let basic_path = fixtures_dir().join("basic-battery-pack");
let detail =
super::fetch_battery_pack_detail("basic", Some(basic_path.to_str().unwrap())).unwrap();
assert!(detail.crates.contains(&"anyhow".to_string()));
assert!(detail.crates.contains(&"thiserror".to_string()));
assert!(detail.crates.contains(&"eyre".to_string()));
assert_eq!(detail.crates.len(), 3);
}
use std::path::Path;
fn resolve_with_fixture(cargo_toml: &str, bp_crate_root: &Path) -> anyhow::Result<String> {
super::resolve_bp_managed_content(cargo_toml, bp_crate_root)
}
#[test]
fn resolve_bp_managed_resolves_versions() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
anyhow.bp-managed = true
clap.bp-managed = true
[build-dependencies]
managed-battery-pack.bp-managed = true
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let result = resolve_with_fixture(cargo_toml, &bp_root).unwrap();
assert!(
result.contains(r#"name = "my-app""#),
"Expected package name"
);
assert!(
result.contains(r#"anyhow = "1""#),
"Expected anyhow version"
);
assert!(
result.contains(r#"clap = { version = "4""#),
"Expected clap version"
);
assert!(
result.contains(r#"managed-battery-pack = "0.2.0""#),
"Expected managed-battery-pack version"
);
}
#[test]
fn resolve_bp_managed_resolves_dev_and_build_deps() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
anyhow.bp-managed = true
[dev-dependencies]
insta.bp-managed = true
[build-dependencies]
cc.bp-managed = true
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let result = resolve_with_fixture(cargo_toml, &bp_root).unwrap();
assert!(
result.contains(r#"name = "my-app""#),
"Expected package name"
);
assert!(result.contains(r#"anyhow = "1""#), "Expected anyhow");
assert!(result.contains(r#"insta = "1.34""#), "Expected insta");
assert!(result.contains(r#"cc = "1.0""#), "Expected cc");
}
#[test]
fn resolve_bp_managed_errors_on_version_and_bp_managed() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
anyhow = { version = "1", bp-managed = true }
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let err = resolve_with_fixture(cargo_toml, &bp_root).unwrap_err();
assert!(
err.to_string().contains("bp-managed") && err.to_string().contains("conflicting keys"),
"should error on both bp-managed and version: {err}"
);
}
#[test]
fn resolve_bp_managed_leaves_explicit_versions_untouched() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
serde = "1.0.200"
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let result = resolve_with_fixture(cargo_toml, &bp_root).unwrap();
assert!(
result.contains(r#"serde = "1.0.200""#),
"explicit version should be untouched: {result}"
);
}
#[test]
fn resolve_bp_managed_errors_on_unresolvable_dep() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
nonexistent.bp-managed = true
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let err = resolve_with_fixture(cargo_toml, &bp_root).unwrap_err();
assert!(
err.to_string().contains("nonexistent")
&& err.to_string().contains("no battery pack provides it"),
"should error on unresolvable dep: {err}"
);
}
#[test]
fn resolve_bp_managed_noop_without_managed_deps() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
serde = "1"
"#;
let result = resolve_with_fixture(cargo_toml, &bp_root).unwrap();
assert!(
result.contains(r#"serde = "1""#),
"should be unchanged: {result}"
);
}
#[test]
fn resolve_bp_managed_errors_on_features_and_bp_managed() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
clap = { bp-managed = true, features = ["derive"] }
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let err = resolve_with_fixture(cargo_toml, &bp_root).unwrap_err();
assert!(
err.to_string().contains("conflicting keys") && err.to_string().contains("features"),
"should error on bp-managed with features: {err}"
);
}
#[test]
fn resolve_bp_managed_errors_on_no_default_features_and_bp_managed() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
clap = { bp-managed = true, default-features = false }
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let err = resolve_with_fixture(cargo_toml, &bp_root).unwrap_err();
assert!(
err.to_string().contains("conflicting keys")
&& err.to_string().contains("default-features"),
"should error on bp-managed with default-features: {err}"
);
}
#[test]
fn resolve_bp_managed_inline_table_syntax() {
let bp_root = fixtures_dir().join("managed-battery-pack");
let cargo_toml = r#"[package]
name = "my-app"
version = "0.1.0"
[dependencies]
anyhow = { bp-managed = true }
clap = { bp-managed = true }
[build-dependencies]
managed-battery-pack = { bp-managed = true }
[package.metadata.battery-pack]
managed-battery-pack = { features = ["default"] }
"#;
let result = resolve_with_fixture(cargo_toml, &bp_root).unwrap();
assert!(
result.contains(r#"name = "my-app""#),
"Expected package name"
);
assert!(result.contains(r#"anyhow = "1""#), "Expected anyhow");
assert!(
result.contains(r#"clap = { version = "4""#),
"Expected clap"
);
assert!(
result.contains(r#"managed-battery-pack = "0.2.0""#),
"Expected managed-battery-pack"
);
}