#![allow(clippy::uninlined_format_args)]
mod common;
use common::pty::{PtyConfig, log_pty_result, sequences, spawn_pty};
use std::time::Duration;
fn ensure_demo_showcase_built() -> bool {
let binary = std::path::Path::new("target/debug/demo_showcase");
if binary.exists() {
return true;
}
eprintln!("Building demo_showcase...");
let status = std::process::Command::new("cargo")
.args(["build", "--bin", "demo_showcase"])
.status();
match status {
Ok(s) if s.success() => true,
_ => {
eprintln!("Failed to build demo_showcase");
false
}
}
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_tour_mode_terminal_lifecycle() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "tour_mode_terminal_lifecycle");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should exit with code 0"
);
assert!(
result.contains_sequence(sequences::ALT_SCREEN_ENTER),
"Should enter alternate screen"
);
assert!(
result.contains_sequence(sequences::ALT_SCREEN_LEAVE),
"Should leave alternate screen on exit"
);
assert!(
result.contains_sequence(sequences::CURSOR_HIDE),
"Should hide cursor"
);
assert!(
result.contains_sequence(sequences::CURSOR_SHOW),
"Should show cursor on exit"
);
let has_mouse = result.contains_sequence(sequences::MOUSE_BUTTON_ENABLE)
|| result.contains_sequence(sequences::MOUSE_MOTION_ENABLE)
|| result.contains_sequence(sequences::MOUSE_ALL_ENABLE);
assert!(has_mouse, "Should enable some form of mouse tracking");
assert!(
result.contains_sequence(sequences::MOUSE_SGR_ENABLE),
"Should enable SGR mouse format"
);
let has_bracketed_paste = result.contains_sequence(sequences::BRACKETED_PASTE_ENABLE);
eprintln!("Bracketed paste enabled: {has_bracketed_paste}");
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_tour_mode_hyperlink_format() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "tour_mode_hyperlink_format");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should exit with code 0"
);
let hyperlink_count = result.count_sequence(sequences::OSC8_PREFIX);
eprintln!("Found {hyperlink_count} OSC 8 hyperlink sequences");
if hyperlink_count > 0 {
eprintln!("Hyperlinks are being emitted in this configuration");
} else {
eprintln!("No hyperlinks emitted (capability may be disabled)");
}
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_no_alt_screen_flag() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.arg("--no-alt-screen")
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "no_alt_screen_flag");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should exit with code 0"
);
assert!(
!result.contains_sequence(sequences::ALT_SCREEN_ENTER),
"Should NOT enter alternate screen with --no-alt-screen"
);
assert!(
!result.contains_sequence(sequences::ALT_SCREEN_LEAVE),
"Should NOT have alternate screen leave sequence"
);
assert!(
result.contains_sequence(sequences::CURSOR_HIDE),
"Should still hide cursor"
);
assert!(
result.contains_sequence(sequences::CURSOR_SHOW),
"Should still show cursor on exit"
);
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_no_mouse_flag() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.arg("--no-mouse")
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "no_mouse_flag");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should exit with code 0"
);
assert!(
!result.contains_sequence(sequences::MOUSE_BUTTON_ENABLE),
"Should NOT enable button mouse tracking with --no-mouse"
);
assert!(
!result.contains_sequence(sequences::MOUSE_MOTION_ENABLE),
"Should NOT enable motion mouse tracking with --no-mouse"
);
assert!(
!result.contains_sequence(sequences::MOUSE_SGR_ENABLE),
"Should NOT enable SGR mouse format with --no-mouse"
);
assert!(
result.contains_sequence(sequences::ALT_SCREEN_ENTER),
"Should still enter alternate screen"
);
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_no_hyperlinks_preset() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.arg("--cap-preset")
.arg("no_hyperlinks")
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "no_hyperlinks_preset");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should exit with code 0"
);
let hyperlink_count = result.count_sequence(sequences::OSC8_PREFIX);
eprintln!("Found {hyperlink_count} OSC 8 hyperlink sequences (expected 0)");
assert_eq!(
hyperlink_count, 0,
"Should NOT emit OSC 8 hyperlinks with --cap-preset no_hyperlinks"
);
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_threaded_mode_parity() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.arg("--threaded")
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "threaded_mode_parity");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase --threaded should exit with code 0"
);
assert!(
result.contains_sequence(sequences::ALT_SCREEN_ENTER),
"Threaded mode should enter alternate screen"
);
assert!(
result.contains_sequence(sequences::ALT_SCREEN_LEAVE),
"Threaded mode should leave alternate screen"
);
assert!(
result.contains_sequence(sequences::CURSOR_HIDE),
"Threaded mode should hide cursor"
);
assert!(
result.contains_sequence(sequences::CURSOR_SHOW),
"Threaded mode should show cursor on exit"
);
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_minimal_terminal_size() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.timeout(Duration::from_secs(60))
.size(40, 12);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "minimal_terminal_size");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should exit with code 0 even at 40x12"
);
assert!(
result.contains_sequence(sequences::ALT_SCREEN_ENTER),
"Should enter alternate screen at minimal size"
);
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_very_small_terminal_behavior() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.timeout(Duration::from_secs(30))
.size(30, 10);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "very_small_terminal");
eprintln!("Exit code: {:?}", result.exit_code);
eprintln!("Output bytes: {}", result.output.len());
let exited_gracefully = result.exit_code.is_some();
let produced_output = !result.output.is_empty();
assert!(
exited_gracefully || produced_output,
"Should either exit gracefully or produce output at small terminal size"
);
if result.exit_code == Some(1) {
let output_str = String::from_utf8_lossy(&result.output);
eprintln!("Error output: {}", output_str);
}
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_synchronized_output_enabled() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.env("TERM", "xterm-kitty")
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "synchronized_output_enabled");
assert_eq!(result.exit_code, Some(0));
let has_sync_begin = result.contains_sequence(sequences::SYNC_OUTPUT_BEGIN);
let has_sync_end = result.contains_sequence(sequences::SYNC_OUTPUT_END);
eprintln!("Sync output begin: {has_sync_begin}, end: {has_sync_end}");
if has_sync_begin {
assert!(has_sync_end, "If sync output begins, it should also end");
}
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_focus_events_optional() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.timeout(Duration::from_secs(60))
.size(80, 24);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "focus_events_optional");
assert_eq!(result.exit_code, Some(0));
let has_focus_enable = result.contains_sequence(sequences::FOCUS_ENABLE);
let has_focus_disable = result.contains_sequence(sequences::FOCUS_DISABLE);
eprintln!("Focus enable: {has_focus_enable}, disable: {has_focus_disable}");
if has_focus_enable {
assert!(
has_focus_disable,
"If focus events are enabled, they should be disabled on exit"
);
}
}
#[test]
#[cfg_attr(
not(feature = "pty-tests"),
ignore = "PTY tests require --features pty-tests"
)]
fn test_large_terminal_size() {
if !ensure_demo_showcase_built() {
eprintln!("Skipping test: demo_showcase not available");
return;
}
let config = PtyConfig::demo_showcase_tour()
.timeout(Duration::from_secs(60))
.size(200, 60);
let result = spawn_pty(&config).expect("Failed to spawn PTY");
log_pty_result(&result, "large_terminal_size");
assert_eq!(
result.exit_code,
Some(0),
"demo_showcase should handle large terminals"
);
assert!(result.contains_sequence(sequences::ALT_SCREEN_ENTER));
assert!(result.contains_sequence(sequences::ALT_SCREEN_LEAVE));
}