use crate::model::common::{ChoiceExecutionSource, Stream, StreamSource, StreamType};
use crate::tests::test_utils::TestDataFactory;
use indexmap::IndexMap;
use std::time::SystemTime;
#[cfg(test)]
mod tests {
use super::*;
fn create_test_stream(id: &str, stream_type: StreamType, is_closeable: bool) -> Stream {
let label = match &stream_type {
StreamType::Content => "Content".to_string(),
StreamType::Choices => "Choices".to_string(),
StreamType::RedirectedOutput(name) => format!("→{}", name),
StreamType::ChoiceExecution(choice_id) => format!("Choice:{}", choice_id),
StreamType::PtySession(name) => format!("PTY:{}", name),
StreamType::ExternalSocket => "Socket".to_string(),
_ => "Test".to_string(),
};
let source = if is_closeable {
Some(StreamSource::ChoiceExecution(ChoiceExecutionSource {
choice_id: format!("choice_{}", id),
thread_id: None,
process_id: None,
execution_type: "thread".to_string(),
started_at: SystemTime::now(),
muxbox_id: format!("test_box_{}", id),
timeout_seconds: None,
}))
} else {
None
};
Stream {
id: id.to_string(),
stream_type,
label,
content: vec!["test content".to_string()],
choices: None,
source, content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
}
}
#[test]
fn test_stream_is_closeable() {
let closeable_stream = create_test_stream(
"test1",
StreamType::RedirectedOutput("output".to_string()),
true,
);
assert!(
closeable_stream.is_closeable(),
"RedirectedOutput stream should be closeable"
);
let choice_stream = create_test_stream(
"test2",
StreamType::ChoiceExecution("choice123".to_string()),
true,
);
assert!(
choice_stream.is_closeable(),
"ChoiceExecution stream should be closeable"
);
let pty_stream =
create_test_stream("test3", StreamType::PtySession("bash".to_string()), true);
assert!(
pty_stream.is_closeable(),
"PtySession stream should be closeable"
);
let socket_stream = create_test_stream("test4", StreamType::ExternalSocket, true);
assert!(
socket_stream.is_closeable(),
"ExternalSocket stream should be closeable"
);
let content_stream = create_test_stream("test5", StreamType::Content, false);
assert!(
!content_stream.is_closeable(),
"Content stream should not be closeable"
);
let choices_stream = create_test_stream("test6", StreamType::Choices, false);
assert!(
!choices_stream.is_closeable(),
"Choices stream should not be closeable"
);
}
#[test]
fn test_muxbox_get_tab_close_buttons() {
let mut muxbox = TestDataFactory::create_test_muxbox("test_box");
let mut streams = IndexMap::new();
streams.insert(
"content".to_string(),
create_test_stream("content", StreamType::Content, false),
);
streams.insert(
"redirect".to_string(),
create_test_stream(
"redirect",
StreamType::RedirectedOutput("target".to_string()),
true,
),
);
streams.insert(
"choice".to_string(),
create_test_stream(
"choice",
StreamType::ChoiceExecution("choice123".to_string()),
true,
),
);
muxbox.streams = streams;
let close_buttons = muxbox.get_tab_close_buttons();
let expected = vec![false, true, true];
assert_eq!(close_buttons.len(), 3, "Should have 3 close button entries");
assert_eq!(
close_buttons, expected,
"Close buttons should match expected pattern"
);
}
#[test]
fn test_muxbox_get_tab_stream_ids() {
let mut muxbox = TestDataFactory::create_test_muxbox("test_box");
let mut streams = IndexMap::new();
streams.insert(
"stream1".to_string(),
create_test_stream("stream1", StreamType::Content, false),
);
streams.insert(
"stream2".to_string(),
create_test_stream(
"stream2",
StreamType::RedirectedOutput("output".to_string()),
true,
),
);
streams.insert(
"stream3".to_string(),
create_test_stream(
"stream3",
StreamType::ChoiceExecution("choice".to_string()),
true,
),
);
muxbox.streams = streams;
let stream_ids = muxbox.get_tab_stream_ids();
let expected = vec![
"stream1".to_string(),
"stream2".to_string(),
"stream3".to_string(),
];
assert_eq!(
stream_ids, expected,
"Stream IDs should match insertion order"
);
}
#[test]
fn test_tab_close_click_detection() {
use crate::draw_utils::calculate_tab_close_click;
let tab_labels = vec![
"Content".to_string(),
"→Output".to_string(),
"Choice:test".to_string(),
];
let tab_close_buttons = vec![false, true, true];
let close_result = calculate_tab_close_click(
22, 0, 40, &tab_labels,
&tab_close_buttons,
0, &Some("white".to_string()), &Some("black".to_string()), );
assert!(
close_result.is_some() || close_result.is_none(),
"Function should return valid Option"
);
}
#[test]
fn test_empty_streams_close_buttons() {
let muxbox = TestDataFactory::create_test_muxbox("empty_box");
let close_buttons = muxbox.get_tab_close_buttons();
assert!(
close_buttons.is_empty(),
"Empty streams should return empty close buttons"
);
let stream_ids = muxbox.get_tab_stream_ids();
assert!(
stream_ids.is_empty(),
"Empty streams should return empty stream IDs"
);
}
#[test]
fn test_mixed_closeable_streams() {
let mut muxbox = TestDataFactory::create_test_muxbox("mixed_box");
let mut streams = IndexMap::new();
streams.insert(
"content".to_string(),
create_test_stream("content", StreamType::Content, false),
);
streams.insert(
"choices".to_string(),
create_test_stream("choices", StreamType::Choices, false),
);
streams.insert(
"redirect1".to_string(),
create_test_stream(
"redirect1",
StreamType::RedirectedOutput("out1".to_string()),
true,
),
);
streams.insert(
"pty".to_string(),
create_test_stream("pty", StreamType::PtySession("bash".to_string()), true),
);
streams.insert(
"redirect2".to_string(),
create_test_stream(
"redirect2",
StreamType::RedirectedOutput("out2".to_string()),
true,
),
);
muxbox.streams = streams;
let close_buttons = muxbox.get_tab_close_buttons();
let expected = vec![false, false, true, true, true];
assert_eq!(
close_buttons, expected,
"Mixed streams should have correct close button pattern"
);
assert_eq!(
close_buttons.len(),
5,
"Should have close button info for all 5 streams"
);
}
}