#[cfg(test)]
mod tests {
use crate::model::common::{ChoiceExecutionSource, Stream, StreamSource, StreamType};
use crate::model::muxbox::MuxBox;
use crate::tests::test_utils::TestDataFactory;
use indexmap::IndexMap;
use std::time::SystemTime;
#[test]
fn test_redirected_tab_close_button_functionality() {
let mut muxbox = TestDataFactory::create_test_muxbox("test_box");
let mut streams = IndexMap::new();
let content_stream = Stream {
id: "content".to_string(),
stream_type: StreamType::Content,
label: "Content".to_string(),
content: vec!["Original content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
};
streams.insert("content".to_string(), content_stream);
let redirect_stream = Stream {
id: "redirect_output_1".to_string(),
stream_type: StreamType::RedirectedOutput("choice_deploy".to_string()),
label: "→Deploy".to_string(),
content: vec![
"Deployment output line 1".to_string(),
"Deployment output line 2".to_string(),
],
choices: None,
source: Some(StreamSource::ChoiceExecution(ChoiceExecutionSource {
choice_id: "choice_deploy".to_string(),
thread_id: None,
process_id: None,
execution_type: "thread".to_string(),
started_at: SystemTime::now(),
muxbox_id: "test_box".to_string(),
timeout_seconds: None,
})),
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
};
streams.insert("redirect_output_1".to_string(), redirect_stream);
muxbox.streams = streams;
assert_eq!(muxbox.streams.len(), 2, "Muxbox should have 2 streams");
let close_buttons = muxbox.get_tab_close_buttons();
assert_eq!(
close_buttons,
vec![false, true], "Close buttons should be [false, true]"
);
let stream_ids = muxbox.get_tab_stream_ids();
assert_eq!(
stream_ids,
vec!["content".to_string(), "redirect_output_1".to_string()],
"Stream IDs should match insertion order"
);
let redirect_stream = muxbox.streams.get("redirect_output_1").unwrap();
assert!(
redirect_stream.is_closeable(),
"Redirected output stream should be closeable"
);
let content_stream = muxbox.streams.get("content").unwrap();
assert!(
!content_stream.is_closeable(),
"Content stream should not be closeable"
);
let removed_source = muxbox.remove_stream("redirect_output_1");
assert!(
removed_source.is_some(),
"Should successfully remove redirected stream"
);
assert_eq!(
muxbox.streams.len(),
1,
"Should have 1 stream after removal"
);
assert!(
!muxbox.streams.contains_key("redirect_output_1"),
"Redirected stream should be removed"
);
assert!(
muxbox.streams.contains_key("content"),
"Content stream should remain"
);
let updated_close_buttons = muxbox.get_tab_close_buttons();
assert_eq!(
updated_close_buttons,
vec![false], "Only content stream should remain (not closeable)"
);
}
#[test]
fn test_multiple_redirected_streams_close_functionality() {
let mut muxbox = TestDataFactory::create_test_muxbox("multi_redirect_box");
let mut streams = IndexMap::new();
streams.insert(
"content".to_string(),
Stream {
id: "content".to_string(),
stream_type: StreamType::Content,
label: "Content".to_string(),
content: vec!["Base content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
);
streams.insert(
"redirect1".to_string(),
Stream {
id: "redirect1".to_string(),
stream_type: StreamType::RedirectedOutput("deploy".to_string()),
label: "→Deploy".to_string(),
content: vec!["Deploy output".to_string()],
choices: None,
source: Some(StreamSource::ChoiceExecution(ChoiceExecutionSource {
choice_id: "deploy".to_string(),
thread_id: None,
process_id: None,
execution_type: "thread".to_string(),
started_at: SystemTime::now(),
muxbox_id: "multi_redirect_box".to_string(),
timeout_seconds: None,
})),
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
);
streams.insert(
"redirect2".to_string(),
Stream {
id: "redirect2".to_string(),
stream_type: StreamType::RedirectedOutput("monitor".to_string()),
label: "→Monitor".to_string(),
content: vec!["Monitor output".to_string()],
choices: None,
source: Some(StreamSource::ChoiceExecution(ChoiceExecutionSource {
choice_id: "monitor".to_string(),
thread_id: None,
process_id: None,
execution_type: "thread".to_string(),
started_at: SystemTime::now(),
muxbox_id: "multi_redirect_box".to_string(),
timeout_seconds: None,
})),
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
);
muxbox.streams = streams;
assert_eq!(muxbox.streams.len(), 3, "Should have 3 streams initially");
let close_buttons = muxbox.get_tab_close_buttons();
assert_eq!(
close_buttons,
vec![false, true, true], "Should have close buttons for redirected streams only"
);
let removed = muxbox.remove_stream("redirect1");
assert!(removed.is_some(), "Should remove first redirected stream");
assert_eq!(
muxbox.streams.len(),
2,
"Should have 2 streams after first removal"
);
let updated_close_buttons = muxbox.get_tab_close_buttons();
assert_eq!(
updated_close_buttons,
vec![false, true], "Should have correct close buttons after first removal"
);
let removed2 = muxbox.remove_stream("redirect2");
assert!(removed2.is_some(), "Should remove second redirected stream");
assert_eq!(
muxbox.streams.len(),
1,
"Should have 1 stream after all removals"
);
let final_close_buttons = muxbox.get_tab_close_buttons();
assert_eq!(
final_close_buttons,
vec![false], "Only content stream should remain (not closeable)"
);
}
#[test]
fn test_active_stream_switching_on_close() {
let mut muxbox = TestDataFactory::create_test_muxbox("active_switch_box");
let mut streams = IndexMap::new();
streams.insert(
"content".to_string(),
Stream {
id: "content".to_string(),
stream_type: StreamType::Content,
label: "Content".to_string(),
content: vec!["Base content".to_string()],
choices: None,
source: None,
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
);
streams.insert(
"redirect_active".to_string(),
Stream {
id: "redirect_active".to_string(),
stream_type: StreamType::RedirectedOutput("deploy".to_string()),
label: "→Deploy".to_string(),
content: vec!["Deploy output".to_string()],
choices: None,
source: Some(StreamSource::ChoiceExecution(ChoiceExecutionSource {
choice_id: "deploy".to_string(),
thread_id: None,
process_id: None,
execution_type: "thread".to_string(),
started_at: SystemTime::now(),
muxbox_id: "active_switch_box".to_string(),
timeout_seconds: None,
})),
content_hash: 0,
last_updated: SystemTime::now(),
created_at: SystemTime::now(),
},
);
muxbox.streams = streams;
muxbox.selected_stream_id = Some("redirect_active".to_string());
let active_stream = muxbox.get_selected_stream();
assert!(active_stream.is_some(), "Should have an active stream");
assert_eq!(
active_stream.unwrap().id,
"redirect_active",
"Redirected stream should be active initially"
);
let removed = muxbox.remove_stream("redirect_active");
assert!(removed.is_some(), "Should remove active redirected stream");
let new_active_stream = muxbox.get_selected_stream();
assert!(
new_active_stream.is_some(),
"Should have a new active stream"
);
assert_eq!(
new_active_stream.unwrap().id,
"content",
"Content stream should become active after removing active redirected stream"
);
let content_stream = muxbox.streams.get("content").unwrap();
assert!(
content_stream.stream_type == crate::model::common::StreamType::Content,
"Content stream should have active=true after switching"
);
}
}