#[cfg(test)]
mod choice_overflow_tests {
use crate::draw_utils::render_muxbox;
use crate::model::choice::Choice;
use crate::model::common::ScreenBuffer;
use crate::model::common::Bounds;
fn create_test_choice(id: &str, content: &str, selected: bool) -> Choice {
Choice {
id: id.to_string(),
content: Some(content.to_string()),
script: None,
redirect_output: None,
append_output: None,
selected,
waiting: false,
}
}
#[test]
fn test_choice_scroll_overflow_behavior() {
let mut buffer = ScreenBuffer::new(20, 10);
let bounds = Bounds::new(0, 0, 19, 9);
let choices = vec![
create_test_choice("c1", "Choice 1", false),
create_test_choice("c2", "Choice 2", true),
create_test_choice("c3", "Choice 3", false),
create_test_choice("c4", "Choice 4", false),
create_test_choice("c5", "Choice 5", false),
create_test_choice("c6", "Choice 6", false),
create_test_choice("c7", "Choice 7", false),
create_test_choice("c8", "Choice 8", false),
create_test_choice("c9", "Choice 9", false),
create_test_choice("c10", "Choice 10", false),
];
let mut streams = indexmap::IndexMap::new();
let choices_stream = crate::model::common::Stream {
id: "choices".to_string(),
label: "Test Menu".to_string(),
stream_type: crate::model::common::StreamType::Choices,
active: true,
data: crate::model::common::StreamData::Choices(choices),
source: None,
};
streams.insert("choices".to_string(), choices_stream);
render_muxbox(
&bounds,
"white",
"black",
"black",
&streams,
0, 0, "white",
"black",
"center",
"white",
"black",
"black",
"white",
"white",
"scroll",
Some(&true),
0.0, 0.0, false, &mut buffer,
);
let right_column = bounds.right();
let mut scrollbar_found = false;
for y in (bounds.top() + 1)..bounds.bottom() {
let cell = buffer.get_cell(right_column, y);
if cell.ch == '│' || cell.ch == '█' { scrollbar_found = true;
break;
}
}
assert!(scrollbar_found, "Scrollbar should be drawn for overflowing choices in scroll mode");
let choice_1_found = buffer.content_contains("Choice 1");
let choice_10_found = buffer.content_contains("Choice 10");
assert!(choice_1_found, "First choice should be visible at scroll position 0");
assert!(!choice_10_found, "Last choice should not be visible at scroll position 0");
}
#[test]
fn test_choice_scroll_with_vertical_offset() {
let mut buffer = ScreenBuffer::new(20, 8);
let bounds = Bounds::new(0, 0, 19, 7);
let choices = vec![
create_test_choice("c1", "Choice 1", false),
create_test_choice("c2", "Choice 2", false),
create_test_choice("c3", "Choice 3", false),
create_test_choice("c4", "Choice 4", false),
create_test_choice("c5", "Choice 5", false),
create_test_choice("c6", "Choice 6", false),
create_test_choice("c7", "Choice 7", false),
create_test_choice("c8", "Choice 8", false),
];
let mut streams = indexmap::IndexMap::new();
let choices_stream = crate::model::common::Stream {
id: "choices".to_string(),
label: "Scrolled Menu".to_string(),
stream_type: crate::model::common::StreamType::Choices,
active: true,
data: crate::model::common::StreamData::Choices(choices),
source: None,
};
streams.insert("choices".to_string(), choices_stream);
render_muxbox(
&bounds,
"white",
"black",
"black",
&streams,
0, 0, "white",
"black",
"center",
"white",
"black",
"black",
"white",
"white",
"scroll",
Some(&true),
0.0, 100.0, false, &mut buffer,
);
let choice_1_found = buffer.content_contains("Choice 1");
let choice_8_found = buffer.content_contains("Choice 8");
assert!(!choice_1_found, "First choice should not be visible at bottom scroll");
assert!(choice_8_found, "Last choice should be visible at bottom scroll");
}
#[test]
fn test_choice_no_overflow_no_scrollbar() {
let mut buffer = ScreenBuffer::new(20, 10);
let bounds = Bounds::new(0, 0, 19, 9);
let choices = vec![
create_test_choice("c1", "Choice 1", false),
create_test_choice("c2", "Choice 2", true),
];
let mut streams = indexmap::IndexMap::new();
let choices_stream = crate::model::common::Stream {
id: "choices".to_string(),
label: "Small Menu".to_string(),
stream_type: crate::model::common::StreamType::Choices,
active: true,
data: crate::model::common::StreamData::Choices(choices),
source: None,
};
streams.insert("choices".to_string(), choices_stream);
render_muxbox(
&bounds,
"white",
"black",
"black",
&streams,
0, 0, "white",
"black",
"center",
"white",
"black",
"black",
"white",
"white",
"scroll",
Some(&true),
0.0, 0.0, false, &mut buffer,
);
let right_column = bounds.right();
let mut scrollbar_found = false;
for y in (bounds.top() + 1)..bounds.bottom() {
let cell = buffer.get_cell(right_column, y);
if cell.ch == '│' || cell.ch == '█' {
scrollbar_found = true;
break;
}
}
assert!(!scrollbar_found, "Scrollbar should NOT be drawn when choices fit in container");
let cell = buffer.get_cell(right_column, bounds.top() + 1);
assert_eq!(cell.ch, '│', "Right border should be drawn when no scrollbar needed");
}
#[test]
fn test_choice_overflow_detection() {
let mut buffer = ScreenBuffer::new(20, 6); let bounds = Bounds::new(0, 0, 19, 5);
let many_choices: Vec<Choice> = (1..=10).map(|i| {
create_test_choice(&format!("c{}", i), &format!("Choice {}", i), false)
}).collect();
let mut streams = indexmap::IndexMap::new();
let choices_stream = crate::model::common::Stream {
id: "choices".to_string(),
label: "Overflow Test".to_string(),
stream_type: crate::model::common::StreamType::Choices,
active: true,
data: crate::model::common::StreamData::Choices(many_choices),
source: None,
};
streams.insert("choices".to_string(), choices_stream);
render_muxbox(
&bounds,
"white",
"black",
"black",
&streams,
0, 0, "white",
"black",
"center",
"white",
"black",
"black",
"white",
"white",
"scroll",
Some(&true),
0.0, 50.0, false, &mut buffer,
);
let early_choice_found = buffer.content_contains("Choice 1");
let late_choice_found = buffer.content_contains("Choice 10");
let middle_choice_found = buffer.content_contains("Choice 5") || buffer.content_contains("Choice 6");
assert!(!early_choice_found, "Early choices should not be visible at middle scroll");
assert!(!late_choice_found, "Late choices should not be visible at middle scroll");
assert!(middle_choice_found, "Middle choices should be visible at middle scroll");
}
}