use pmpx_plugin::Family;
use crate::detect::DetectFailure;
use super::{fail, fixture, official, pick};
#[test]
fn scenario_cargo_toml_only_picks_cargo() {
let fx = fixture(&official(), &["Cargo.toml"]);
let s = pick(&fx, &[], None);
assert_eq!(s.name, "cargo");
assert_eq!(s.family, Family::RUST);
assert_eq!(s.score, 10);
}
#[test]
fn scenario_cargo_lock_picks_cargo() {
let fx = fixture(&official(), &["Cargo.toml", "Cargo.lock"]);
let s = pick(&fx, &[], None);
assert_eq!(s.name, "cargo");
assert_eq!(s.score, 110);
}
#[test]
fn scenario_package_json_alone_falls_back_to_pnpm() {
let fx = fixture(&official(), &["package.json"]);
let s = pick(&fx, &[], None);
assert_eq!(s.name, "pnpm");
assert_eq!(s.score, 10);
assert!(!s.notes.is_empty(), "a tie must produce a note");
}
#[test]
fn scenario_pnpm_lock_picks_pnpm() {
let fx = fixture(&official(), &["package.json", "pnpm-lock.yaml"]);
let s = pick(&fx, &[], None);
assert_eq!(s.name, "pnpm");
assert_eq!(s.score, 110);
}
#[test]
fn scenario_package_lock_picks_npm() {
let fx = fixture(&official(), &["package.json", "package-lock.json"]);
let s = pick(&fx, &[], None);
assert_eq!(s.name, "npm");
}
#[test]
fn scenario_mixed_at_ten_ten_goes_to_node() {
let fx = fixture(&official(), &["Cargo.toml", "package.json"]);
let s = pick(&fx, &[], None);
assert_eq!(s.family, Family::NODE);
assert_eq!(s.name, "pnpm");
}
#[test]
fn scenario_mixed_follows_family_priority() {
let mut fx = fixture(&official(), &["Cargo.toml", "package.json"]);
fx.global.plugin.family_priority = vec!["rust".into(), "node".into()];
let s = pick(&fx, &[], None);
assert_eq!(
s.family,
Family::RUST,
"changing one array changes the default behaviour"
);
}
#[test]
fn scenario_both_locked_at_one_ten_follows_family_priority() {
let fx = fixture(
&official(),
&["Cargo.toml", "Cargo.lock", "package.json", "pnpm-lock.yaml"],
);
let s = pick(&fx, &[], None);
assert_eq!(s.family, Family::NODE);
assert_eq!(s.name, "pnpm");
}
#[test]
fn scenario_pin_rescues_a_lockless_library_crate() {
let fx = fixture(&official(), &["Cargo.toml", "package.json"]);
assert_eq!(pick(&fx, &[], None).family, Family::NODE);
let s = pick(&fx, &[("rust", "cargo")], None);
assert_eq!(s.family, Family::RUST);
assert_eq!(s.name, "cargo");
}
#[test]
fn a_pin_does_not_beat_a_lockfile() {
let fx = fixture(&official(), &["Cargo.toml", "Cargo.lock", "package.json"]);
let s = pick(&fx, &[("node", "pnpm")], None);
assert_eq!(
s.family,
Family::RUST,
"110 points beats the 50-point floor"
);
assert_eq!(s.score, 110);
}
#[test]
fn a_pin_works_even_with_no_files_at_all() {
let fx = fixture(&official(), &[]);
let s = pick(&fx, &[("node", "pnpm")], None);
assert_eq!(s.family, Family::NODE);
}
#[test]
fn explicit_plugin_overrides_the_pin() {
let fx = fixture(&official(), &["Cargo.toml", "Cargo.lock"]);
let s = pick(&fx, &[], Some("npm"));
assert_eq!(s.name, "npm");
assert_eq!(s.family, Family::NODE);
assert!(
s.notes.is_empty(),
"-p is explicit, there should be no ambiguity note"
);
}
#[test]
fn explicit_plugin_overrides_detection_in_a_mixed_project() {
let fx = fixture(&official(), &["Cargo.toml", "Cargo.lock", "package.json"]);
assert_eq!(pick(&fx, &[], None).name, "cargo");
assert_eq!(pick(&fx, &[], Some("yarn")).name, "yarn");
}
#[test]
fn an_unknown_explicit_plugin_lists_what_is_available() {
let fx = fixture(&official(), &["Cargo.toml"]);
match fail(&fx, &[], Some("nope")) {
DetectFailure::UnknownPlugin { name, available } => {
assert_eq!(name, "nope");
assert!(available.contains(&"cargo".to_string()));
assert!(available.contains(&"pnpm".to_string()));
}
other => panic!("expected UnknownPlugin, got {other:?}"),
}
}
#[test]
fn unlisted_families_fall_back_to_name_order() {
let fx = fixture(
&[
("pmpx-plugin-zed", "zebra", &["z.lock"], &[]),
("pmpx-plugin-aaa", "alpha", &["a.lock"], &[]),
],
&["a.lock", "z.lock"],
);
let s = pick(&fx, &[], None);
assert_eq!(
s.family.as_str(),
"alpha",
"unlisted ones follow name order"
);
assert!(!s.notes.is_empty(), "a tie still produces a note");
}
#[test]
fn an_unlisted_plugin_loses_to_a_listed_one_at_the_same_score() {
let fx = fixture(
&[
("pmpx-plugin-aaa", "node", &[], &["package.json"]),
("pmpx-plugin-pnpm", "node", &[], &["package.json"]),
],
&["package.json"],
);
let s = pick(&fx, &[], None);
assert_eq!(
s.name, "pnpm",
"the one in the priority table beats the one that is not"
);
}
#[test]
fn selection_reports_the_winning_score() {
let fx = fixture(&official(), &["package.json", "pnpm-lock.yaml"]);
assert_eq!(pick(&fx, &[], None).score, 110);
}
#[test]
fn selection_carries_the_evidence_it_was_chosen_on() {
let fx = fixture(&official(), &["Cargo.toml", "Cargo.lock"]);
assert_eq!(
pick(&fx, &[], None).matched,
vec!["Cargo.lock", "Cargo.toml"]
);
}
#[test]
fn an_explicit_plugin_carries_its_own_evidence() {
let fx = fixture(&official(), &["package.json", "pnpm-lock.yaml"]);
assert_eq!(
pick(&fx, &[], Some("pnpm")).matched,
vec!["pnpm-lock.yaml", "package.json"]
);
}