use std::collections::BTreeMap;
use crate::cli::prepare::propagation::*;
use crate::model::changeset::ChangeType;
use crate::model::config::DependencyBump;
use crate::package_manager::Project;
fn make_project(name: &str, version: &str) -> Project {
crate::package_manager::Project::new_test_with_version(name, version.parse().unwrap())
}
fn make_project_with_deps(name: &str, version: &str, deps: Vec<&str>) -> Project {
crate::package_manager::Project::new_test_with_deps(name, version, deps)
}
#[test]
fn propagation_change_type_patch_mode_always_returns_patch() {
for upstream in [ChangeType::Patch, ChangeType::Minor, ChangeType::Major] {
assert_eq!(
DependencyBump::Patch.to_change_type(upstream),
ChangeType::Patch,
);
}
}
#[test]
fn propagation_change_type_minor_mode_always_returns_minor() {
for upstream in [ChangeType::Patch, ChangeType::Minor, ChangeType::Major] {
assert_eq!(
DependencyBump::Minor.to_change_type(upstream),
ChangeType::Minor,
);
}
}
#[test]
fn propagation_change_type_major_mode_always_returns_major() {
for upstream in [ChangeType::Patch, ChangeType::Minor, ChangeType::Major] {
assert_eq!(
DependencyBump::Major.to_change_type(upstream),
ChangeType::Major,
);
}
}
#[test]
fn propagation_change_type_match_mode_mirrors_upstream() {
assert_eq!(
DependencyBump::Match.to_change_type(ChangeType::Patch),
ChangeType::Patch,
);
assert_eq!(
DependencyBump::Match.to_change_type(ChangeType::Minor),
ChangeType::Minor,
);
assert_eq!(
DependencyBump::Match.to_change_type(ChangeType::Major),
ChangeType::Major,
);
}
#[test]
fn propagation_change_type_auto_mode_maps_minor_and_patch_to_patch() {
assert_eq!(
DependencyBump::Auto.to_change_type(ChangeType::Patch),
ChangeType::Patch,
);
assert_eq!(
DependencyBump::Auto.to_change_type(ChangeType::Minor),
ChangeType::Patch,
);
}
#[test]
fn propagation_change_type_auto_mode_maps_major_to_major() {
assert_eq!(
DependencyBump::Auto.to_change_type(ChangeType::Major),
ChangeType::Major,
);
}
#[test]
fn build_reverse_dep_graph_empty_projects_returns_empty() {
let graph = build_reverse_dep_graph(&[]);
assert!(graph.is_empty());
}
#[test]
fn build_reverse_dep_graph_no_deps_returns_empty() {
let projects = vec![
make_project("pkg-a", "1.0.0"),
make_project("pkg-b", "1.0.0"),
];
let graph = build_reverse_dep_graph(&projects);
assert!(graph.is_empty());
}
#[test]
fn build_reverse_dep_graph_filters_external_deps() {
let projects = vec![
make_project_with_deps("pkg-a", "1.0.0", vec!["serde", "pkg-b"]),
make_project("pkg-b", "1.0.0"),
];
let graph = build_reverse_dep_graph(&projects);
assert_eq!(graph.len(), 1);
assert_eq!(graph["pkg-b"], vec!["pkg-a"]);
}
#[test]
fn build_reverse_dep_graph_multiple_dependents_on_same_package() {
let projects = vec![
make_project_with_deps("pkg-a", "1.0.0", vec!["pkg-c"]),
make_project_with_deps("pkg-b", "1.0.0", vec!["pkg-c"]),
make_project("pkg-c", "1.0.0"),
];
let graph = build_reverse_dep_graph(&projects);
let mut dependents = graph["pkg-c"].clone();
dependents.sort();
assert_eq!(dependents, vec!["pkg-a", "pkg-b"]);
}
#[test]
fn mark_propagation_bumps_empty_aggregated_returns_empty() {
let aggregated = BTreeMap::new();
let version_overrides = BTreeMap::new();
let reverse_deps = BTreeMap::new();
let result = mark_propagation_bumps(
&aggregated,
&version_overrides,
&reverse_deps,
DependencyBump::Auto,
);
assert!(result.is_empty());
}
#[test]
fn mark_propagation_bumps_skips_linked_packages() {
let mut aggregated = BTreeMap::new();
aggregated.insert("pkg-a".to_string(), ChangeType::Major);
let mut version_overrides = BTreeMap::new();
version_overrides.insert("pkg-b".to_string(), "2.0.0".parse().unwrap());
let mut reverse_deps: BTreeMap<String, Vec<String>> = BTreeMap::new();
reverse_deps.insert("pkg-a".to_string(), vec!["pkg-b".to_string()]);
let result = mark_propagation_bumps(
&aggregated,
&version_overrides,
&reverse_deps,
DependencyBump::Auto,
);
assert!(!result.contains_key("pkg-b"));
}
#[test]
fn mark_propagation_bumps_equal_change_type_does_not_propagate() {
let mut aggregated = BTreeMap::new();
aggregated.insert("pkg-a".to_string(), ChangeType::Minor);
aggregated.insert("pkg-b".to_string(), ChangeType::Minor);
let version_overrides = BTreeMap::new();
let mut reverse_deps: BTreeMap<String, Vec<String>> = BTreeMap::new();
reverse_deps.insert("pkg-a".to_string(), vec!["pkg-b".to_string()]);
let result = mark_propagation_bumps(
&aggregated,
&version_overrides,
&reverse_deps,
DependencyBump::Match, );
assert!(
!result.contains_key("pkg-b"),
"Equal ct should not create a propagation entry: {result:?}"
);
}
#[test]
fn mark_propagation_bumps_only_upgrades_not_downgrades() {
let mut aggregated = BTreeMap::new();
aggregated.insert("pkg-a".to_string(), ChangeType::Patch);
aggregated.insert("pkg-b".to_string(), ChangeType::Major);
let version_overrides = BTreeMap::new();
let mut reverse_deps: BTreeMap<String, Vec<String>> = BTreeMap::new();
reverse_deps.insert("pkg-a".to_string(), vec!["pkg-b".to_string()]);
let result = mark_propagation_bumps(
&aggregated,
&version_overrides,
&reverse_deps,
DependencyBump::Auto, );
assert!(!result.contains_key("pkg-b"));
}
#[test]
fn mark_propagation_bumps_diamond_graph_no_duplicate_upstreams() {
let mut aggregated = BTreeMap::new();
aggregated.insert("pkg-a".to_string(), ChangeType::Minor);
aggregated.insert("pkg-x".to_string(), ChangeType::Major);
let version_overrides = BTreeMap::new();
let mut reverse_deps: BTreeMap<String, Vec<String>> = BTreeMap::new();
reverse_deps.insert("pkg-a".to_string(), vec!["pkg-b".to_string()]);
reverse_deps.insert("pkg-x".to_string(), vec!["pkg-b".to_string()]);
reverse_deps.insert("pkg-b".to_string(), vec!["pkg-d".to_string()]);
let result = mark_propagation_bumps(
&aggregated,
&version_overrides,
&reverse_deps,
DependencyBump::Match,
);
assert!(result.contains_key("pkg-d"));
let (_, upstreams) = &result["pkg-d"];
assert_eq!(upstreams.len(), 1);
assert!(upstreams.contains("pkg-b"));
}
#[test]
fn mark_propagation_bumps_terminates_with_circular_deps() {
let mut aggregated = BTreeMap::new();
aggregated.insert("pkg-a".to_string(), ChangeType::Minor);
let version_overrides = BTreeMap::new();
let mut reverse_deps: BTreeMap<String, Vec<String>> = BTreeMap::new();
reverse_deps.insert("pkg-a".to_string(), vec!["pkg-b".to_string()]);
reverse_deps.insert("pkg-b".to_string(), vec!["pkg-a".to_string()]);
let result = mark_propagation_bumps(
&aggregated,
&version_overrides,
&reverse_deps,
DependencyBump::Auto,
);
assert!(result.contains_key("pkg-b"));
}