mod enter_message;
mod single_package;
use crossterm::event::KeyCode;
use crate::model::changeset::ChangeType;
use crate::package_manager::Project;
use crate::tui::change::test_helpers::dummy_projects;
use crate::tui::change::*;
#[test]
fn reorder_projects_mixed_changed_and_unchanged() {
let projects = dummy_projects(3); let changed_flags = vec![false, true, false];
let ro = reorder_projects(&projects, &changed_flags);
assert_eq!(ro.changed_count, 1);
assert_eq!(ro.projects[0].name(), "project-1"); assert_eq!(ro.projects[1].name(), "project-0"); assert_eq!(ro.projects[2].name(), "project-2");
assert_eq!(ro.orig_to_new[0], 1); assert_eq!(ro.orig_to_new[1], 0); assert_eq!(ro.orig_to_new[2], 2); }
#[test]
fn reorder_projects_all_changed() {
let projects = dummy_projects(2);
let ro = reorder_projects(&projects, &[true, true]);
assert_eq!(ro.changed_count, 2);
assert_eq!(ro.projects[0].name(), "project-0");
assert_eq!(ro.projects[1].name(), "project-1");
assert_eq!(ro.orig_to_new[0], 0);
assert_eq!(ro.orig_to_new[1], 1);
}
#[test]
fn reorder_projects_all_unchanged() {
let projects = dummy_projects(2);
let ro = reorder_projects(&projects, &[false, false]);
assert_eq!(ro.changed_count, 0);
assert_eq!(ro.projects[0].name(), "project-0");
assert_eq!(ro.projects[1].name(), "project-1");
assert_eq!(ro.orig_to_new[0], 0);
assert_eq!(ro.orig_to_new[1], 1);
}
#[test]
fn reorder_projects_empty() {
let ro = reorder_projects(&[], &[]);
assert_eq!(ro.changed_count, 0);
assert!(ro.projects.is_empty());
assert!(ro.orig_to_new.is_empty());
}
#[test]
fn reorder_projects_single_project() {
let projects = dummy_projects(1);
let ro = reorder_projects(&projects, &[true]);
assert_eq!(ro.changed_count, 1);
assert_eq!(ro.projects[0].name(), "project-0");
assert_eq!(ro.orig_to_new[0], 0);
}
#[test]
fn reorder_projects_sorts_changed_group_by_name() {
let projects = vec![
Project::new_test("beta", "/nonexistent/beta"),
Project::new_test("alpha", "/nonexistent/alpha"),
];
let ro = reorder_projects(&projects, &[true, true]);
assert_eq!(ro.changed_count, 2);
assert_eq!(ro.projects[0].name(), "alpha");
assert_eq!(ro.projects[1].name(), "beta");
assert_eq!(ro.orig_to_new[0], 1); assert_eq!(ro.orig_to_new[1], 0); }
#[test]
fn reorder_projects_sorts_unchanged_group_by_name() {
let projects = vec![
Project::new_test("zeta", "/nonexistent/zeta"),
Project::new_test("gamma", "/nonexistent/gamma"),
];
let ro = reorder_projects(&projects, &[false, false]);
assert_eq!(ro.changed_count, 0);
assert_eq!(ro.projects[0].name(), "gamma");
assert_eq!(ro.projects[1].name(), "zeta");
assert_eq!(ro.orig_to_new[0], 1); assert_eq!(ro.orig_to_new[1], 0); }
fn unwrap_select_projects(
result: anyhow::Result<HandleResult>,
) -> (Vec<bool>, Vec<ChangeType>, usize, bool, usize) {
match result.unwrap() {
KeyResult::Continue(Screen::SelectProjects(SelectProjectsState {
selected,
levels,
cursor,
error,
changed_count,
})) => (selected, levels, cursor, error, changed_count),
other => panic!(
"Expected Continue(SelectProjects), got different variant: {:?}",
std::mem::discriminant(&other)
),
}
}
fn unwrap_enter_message(result: anyhow::Result<HandleResult>) -> Vec<(Project, ChangeType)> {
match result.unwrap() {
KeyResult::Continue(Screen::EnterMessage { projects, .. }) => projects,
_ => panic!("Expected Continue(EnterMessage)"),
}
}
#[test]
fn workflow_select_projects_then_enter_message() {
let projects = dummy_projects(3);
let screen = Screen::SelectProjects(SelectProjectsState {
selected: vec![true, true, true],
levels: vec![ChangeType::Patch; 3],
cursor: 0,
error: false,
changed_count: 3,
});
let (selected, levels, cursor, error, changed_count) =
unwrap_select_projects(handle_key(screen, KeyCode::Char(' '), &projects));
assert_eq!(selected, vec![false, true, true]);
assert_eq!(levels, vec![ChangeType::Patch; 3]);
assert_eq!(cursor, 0);
assert!(!error);
assert_eq!(changed_count, 3);
let screen = Screen::SelectProjects(SelectProjectsState {
selected: vec![false, true, true],
levels: vec![ChangeType::Patch; 3],
cursor: 1,
error: false,
changed_count: 3,
});
let (selected2, levels2, ..) =
unwrap_select_projects(handle_key(screen, KeyCode::Right, &projects));
assert_eq!(selected2, vec![false, true, true]);
assert_eq!(levels2[1], ChangeType::Major);
let screen = Screen::SelectProjects(SelectProjectsState {
selected: vec![false, true, true],
levels: vec![ChangeType::Patch, ChangeType::Major, ChangeType::Patch],
cursor: 0,
error: false,
changed_count: 3,
});
let proj = unwrap_enter_message(handle_key(screen, KeyCode::Enter, &projects));
assert_eq!(proj.len(), 2);
assert_eq!(proj[0].0.name(), "project-1");
assert_eq!(proj[0].1, ChangeType::Major);
assert_eq!(proj[1].0.name(), "project-2");
assert_eq!(proj[1].1, ChangeType::Patch);
}
#[test]
fn build_initial_screen_single_project_returns_single_package() {
let projects = dummy_projects(1);
let ro = reorder_projects(&projects, &[true]);
let screen = build_initial_screen(&ro, &[], false);
assert!(
matches!(screen, Screen::SinglePackage { .. }),
"Expected SinglePackage for one project"
);
}
#[test]
fn run_change_type_shortcircuit_selects_only_changed() {
let projects = dummy_projects(3);
let changed = vec![true, false, false];
let options = ChangeOptions {
change_type: Some(ChangeType::Patch),
projects: None,
};
let result = run(&projects, &options, &changed).unwrap().unwrap();
assert_eq!(result.projects.len(), 1);
assert_eq!(result.projects[0].0.name(), "project-0");
}
#[test]
fn run_change_type_shortcircuit_falls_back_to_all_when_none_changed() {
let projects = dummy_projects(2);
let changed = vec![false, false];
let options = ChangeOptions {
change_type: Some(ChangeType::Minor),
projects: None,
};
let result = run(&projects, &options, &changed).unwrap().unwrap();
assert_eq!(result.projects.len(), 2);
}
#[test]
fn run_change_type_shortcircuit_explicit_projects_override_changed() {
let projects = dummy_projects(3);
let changed = vec![false, true, false];
let options = ChangeOptions {
change_type: Some(ChangeType::Patch),
projects: Some(vec![2]),
};
let result = run(&projects, &options, &changed).unwrap().unwrap();
assert_eq!(result.projects.len(), 1);
assert_eq!(result.projects[0].0.name(), "project-2");
}
#[test]
fn build_initial_screen_no_pre_selection_selects_only_changed() {
let projects = dummy_projects(2);
let ro = reorder_projects(&projects, &[true, false]); let screen = build_initial_screen(&ro, &[], false);
match screen {
Screen::SelectProjects(SelectProjectsState {
selected,
changed_count,
..
}) => {
assert_eq!(changed_count, 1);
assert!(selected[0], "first project (changed) should be selected");
assert!(
!selected[1],
"second project (unchanged) should not be selected"
);
}
_ => panic!("Expected SelectProjects"),
}
}