[Fix] Connection Management
This commit is contained in:
parent
9e9e3597da
commit
3f2ac18333
122 changed files with 19970 additions and 5263 deletions
|
|
@ -1,15 +0,0 @@
|
|||
use iota_cli::controls::button::{button_minimum_width, horizontal_button_widths};
|
||||
|
||||
#[test]
|
||||
fn width_allocation_handles_exact_spare_and_insufficient_space() {
|
||||
assert_eq!(horizontal_button_widths(7, &[3, 4]), Some(vec![3, 4]));
|
||||
assert_eq!(horizontal_button_widths(10, &[3, 4]), Some(vec![5, 5]));
|
||||
assert_eq!(horizontal_button_widths(6, &[3, 4]), None);
|
||||
assert_eq!(horizontal_button_widths(10, &[]), Some(Vec::new()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimum_width_uses_terminal_columns() {
|
||||
assert_eq!(button_minimum_width("é"), 3);
|
||||
assert_eq!(button_minimum_width("界"), 4);
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
use iota_cli::controls::{
|
||||
checkbox_group::{CheckboxChange, CheckboxGroup, CheckboxItem},
|
||||
navigation::DisabledFocusPolicy,
|
||||
radio_group::{DisabledSelectionPolicy, RadioChange, RadioGroup, RadioGroupError, RadioItem},
|
||||
};
|
||||
|
||||
fn checkbox(value: u8, enabled: bool) -> CheckboxItem<u8> {
|
||||
CheckboxItem {
|
||||
value,
|
||||
label: value.to_string(),
|
||||
description: None,
|
||||
enabled,
|
||||
disabled_reason: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn radio(value: u8, enabled: bool) -> RadioItem<u8> {
|
||||
RadioItem {
|
||||
value,
|
||||
label: value.to_string(),
|
||||
description: None,
|
||||
enabled,
|
||||
disabled_reason: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checkbox_selection_and_disabled_focus_are_independent() {
|
||||
let mut group = CheckboxGroup::new(
|
||||
vec![checkbox(1, true), checkbox(2, false), checkbox(3, true)],
|
||||
[1, 99],
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
group.selected().iter().copied().collect::<Vec<_>>(),
|
||||
vec![1]
|
||||
);
|
||||
assert_eq!(group.toggle_focused(), CheckboxChange::Deselected(1));
|
||||
group.focus_next();
|
||||
assert_eq!(group.focused_item().unwrap().value, 3);
|
||||
group.set_focus_policy(DisabledFocusPolicy::Include);
|
||||
group.focus_previous();
|
||||
assert_eq!(group.focused_item().unwrap().value, 2);
|
||||
assert_eq!(group.toggle_focused(), CheckboxChange::IgnoredDisabled(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checkbox_non_wrapping_navigation_stops_at_the_edge() {
|
||||
let mut group = CheckboxGroup::new(vec![checkbox(1, true), checkbox(2, true)], []).unwrap();
|
||||
group.set_wrap_navigation(false);
|
||||
group.focus_previous();
|
||||
assert_eq!(group.focused_item().unwrap().value, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn radio_validates_default_and_preserves_one_selection() {
|
||||
assert!(matches!(
|
||||
RadioGroup::new(Vec::<RadioItem<u8>>::new(), None, 1),
|
||||
Err(RadioGroupError::Empty)
|
||||
));
|
||||
assert!(matches!(
|
||||
RadioGroup::new(vec![radio(1, true)], None, 2),
|
||||
Err(RadioGroupError::DefaultMissing)
|
||||
));
|
||||
assert!(matches!(
|
||||
RadioGroup::new(vec![radio(1, false)], None, 1),
|
||||
Err(RadioGroupError::DefaultDisabled)
|
||||
));
|
||||
|
||||
let mut group = RadioGroup::new(vec![radio(1, true), radio(2, true)], Some(2), 1).unwrap();
|
||||
assert_eq!(group.selected(), &2);
|
||||
group.focus_next();
|
||||
assert_eq!(group.selected(), &2);
|
||||
assert_eq!(group.select_focused(), RadioChange::Unchanged(2));
|
||||
group.focus_previous();
|
||||
assert_eq!(
|
||||
group.select_focused(),
|
||||
RadioChange::Changed {
|
||||
previous: 2,
|
||||
selected: 1
|
||||
}
|
||||
);
|
||||
assert_eq!(group.selected(), &1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn groups_initially_focus_the_first_enabled_item() {
|
||||
let checkboxes = CheckboxGroup::new(vec![checkbox(1, false), checkbox(2, true)], []).unwrap();
|
||||
assert_eq!(checkboxes.focused_item().unwrap().value, 2);
|
||||
let radios = RadioGroup::new(vec![radio(1, false), radio(2, true)], None, 2).unwrap();
|
||||
assert_eq!(radios.focused_item().value, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disabling_a_selected_radio_obeys_the_configured_policy() {
|
||||
let mut group = RadioGroup::new(vec![radio(1, true), radio(2, true)], Some(2), 1).unwrap();
|
||||
group.set_enabled(&2, false).unwrap();
|
||||
assert_eq!(group.selected(), &1);
|
||||
|
||||
group.set_enabled(&2, true).unwrap();
|
||||
group.focus_next();
|
||||
group.select_focused();
|
||||
group.set_disabled_selection_policy(DisabledSelectionPolicy::ReturnError);
|
||||
assert_eq!(
|
||||
group.set_enabled(&2, false),
|
||||
Err(RadioGroupError::SelectedItemDisabled)
|
||||
);
|
||||
assert_eq!(group.selected(), &2);
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
use iota_cli::layout::fit::{
|
||||
FitLevel, RequiredSize, centered_rect, inset_checked, reserve_vertical, select_fit_level,
|
||||
};
|
||||
use ratatui::layout::Rect;
|
||||
|
||||
#[test]
|
||||
fn selects_fit_by_both_dimensions() {
|
||||
let preferred = RequiredSize {
|
||||
width: 80,
|
||||
height: 20,
|
||||
};
|
||||
let compact = RequiredSize {
|
||||
width: 50,
|
||||
height: 12,
|
||||
};
|
||||
assert_eq!(
|
||||
select_fit_level(Rect::new(0, 0, 80, 20), preferred, compact),
|
||||
FitLevel::Preferred
|
||||
);
|
||||
assert_eq!(
|
||||
select_fit_level(Rect::new(0, 0, 50, 12), preferred, compact),
|
||||
FitLevel::Compact
|
||||
);
|
||||
assert_eq!(
|
||||
select_fit_level(Rect::new(0, 0, 80, 11), preferred, compact),
|
||||
FitLevel::Fallback
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rectangle_helpers_do_not_underflow() {
|
||||
let zero = Rect::new(4, 5, 0, 0);
|
||||
assert_eq!(
|
||||
centered_rect(
|
||||
zero,
|
||||
RequiredSize {
|
||||
width: 10,
|
||||
height: 10
|
||||
}
|
||||
),
|
||||
zero
|
||||
);
|
||||
assert_eq!(reserve_vertical(zero, 1, 0), None);
|
||||
assert_eq!(inset_checked(zero, 1, 1), None);
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use iota_cli::{
|
||||
interaction_result::InteractionResult,
|
||||
render_context::RenderContext,
|
||||
screens::{
|
||||
screens::{AppEvent, HitMap, Screen, UiEvent},
|
||||
screens::{HitMap, IotaEffect, IotaInteraction, IotaScreen, UiEvent},
|
||||
settings::SettingsScreen,
|
||||
},
|
||||
theme::{ThemeName, resolve},
|
||||
|
|
@ -20,35 +18,21 @@ fn buffer_text(terminal: &Terminal<TestBackend>) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn settings_preview_and_save_emit_typed_application_events() {
|
||||
#[test]
|
||||
fn settings_preview_and_save_emit_typed_effects() {
|
||||
let mut screen = SettingsScreen::new(ThemeName::Ansi);
|
||||
let preview = screen.handle_event(UiEvent::Key(KeyEvent::from(KeyCode::Right)));
|
||||
let InteractionResult::AppTask { task } = preview else {
|
||||
panic!("theme preview should emit an application task");
|
||||
let preview = screen.handle_event(&UiEvent::Key(KeyEvent::from(KeyCode::Right)));
|
||||
let IotaInteraction::Effect(IotaEffect::ApplyTheme { theme, persist }) = preview else {
|
||||
panic!("theme preview should emit an effect");
|
||||
};
|
||||
assert!(matches!(
|
||||
task.await,
|
||||
UiEvent::App(AppEvent::ApplyTheme {
|
||||
theme: ThemeName::Surface,
|
||||
persist: false
|
||||
})
|
||||
));
|
||||
assert_eq!(theme, ThemeName::Surface);
|
||||
assert!(!persist);
|
||||
|
||||
let save = screen.handle_event(UiEvent::Key(KeyEvent::from(KeyCode::Enter)));
|
||||
let InteractionResult::AppTask { task } = save else {
|
||||
panic!("theme save should emit an application task");
|
||||
let save = screen.handle_event(&UiEvent::Key(KeyEvent::from(KeyCode::Enter)));
|
||||
let IotaInteraction::Effect(IotaEffect::SaveSettings { theme, .. }) = save else {
|
||||
panic!("theme save should emit an effect");
|
||||
};
|
||||
assert!(matches!(
|
||||
task.await,
|
||||
UiEvent::App(AppEvent::SaveSettings {
|
||||
theme: ThemeName::Surface,
|
||||
color: _,
|
||||
unicode: _,
|
||||
cli_output: _,
|
||||
cli_require_confirmation: _
|
||||
})
|
||||
));
|
||||
assert_eq!(theme, ThemeName::Surface);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -60,12 +44,7 @@ fn settings_is_readable_in_every_theme_and_layout() {
|
|||
let screen = SettingsScreen::new(theme_name);
|
||||
terminal
|
||||
.draw(|frame| {
|
||||
screen.render(
|
||||
frame,
|
||||
frame.area(),
|
||||
&RenderContext { theme: &theme },
|
||||
&mut HitMap::default(),
|
||||
);
|
||||
screen.render_legacy(frame, frame.area(), &theme, &mut HitMap::new());
|
||||
})
|
||||
.unwrap();
|
||||
let rendered = buffer_text(&terminal);
|
||||
|
|
|
|||
Loading…
Reference in a new issue