#![cfg(feature = "mock")]
use std::time::Duration;
use rust_expect::mock::{MockBuilder, MockTransport, Scenario, simple_mock};
use rust_expect::{ControlChar, Pattern, PatternSet, Session, SessionConfig};
fn config_with_timeout(timeout: Duration) -> SessionConfig {
let mut config = SessionConfig::default();
config.timeout.default = timeout;
config
}
#[tokio::test]
async fn expect_literal_pattern() {
let transport = simple_mock("Hello, World!\nPrompt> ");
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let result = session.expect("World").await;
assert!(result.is_ok(), "Expected to match 'World'");
let m = result.unwrap();
assert!(m.matched.contains("World"), "Match should contain 'World'");
}
#[tokio::test]
async fn expect_regex_pattern() {
let transport = simple_mock("User123 logged in at 2024-01-01\n");
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let pattern = Pattern::regex(r"User\d+ logged in").unwrap();
let result = session.expect(pattern).await;
assert!(result.is_ok(), "Expected to match regex pattern");
}
#[tokio::test]
async fn expect_timeout() {
let transport = MockBuilder::new()
.output("Partial output without the expected pattern")
.delay_ms(2000) .build();
let config = config_with_timeout(Duration::from_millis(100));
let mut session = Session::new(transport, config);
let result = session.expect("never_gonna_match").await;
assert!(result.is_err(), "Expected timeout error");
if let Err(e) = result {
let err_str = e.to_string().to_lowercase();
assert!(
err_str.contains("timeout") || err_str.contains("timed out"),
"Error should mention timeout: {e}"
);
}
}
#[tokio::test]
async fn expect_eof() {
let transport = MockBuilder::new().output("Some output\n").eof().build();
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let result = session.expect("output").await;
assert!(result.is_ok());
let result = session.expect("more").await;
assert!(result.is_err());
}
#[tokio::test]
async fn expect_multiple_patterns() {
let transport = simple_mock("Status: SUCCESS\n");
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let mut patterns = PatternSet::new();
patterns
.add(Pattern::literal("SUCCESS"))
.add(Pattern::literal("FAILURE"))
.add(Pattern::literal("PENDING"));
let result = session.expect_any(&patterns).await;
assert!(result.is_ok());
let m = result.unwrap();
assert!(m.matched.contains("SUCCESS"));
}
#[tokio::test]
async fn send_and_expect() {
let scenario = Scenario::new("interactive")
.initial_output("Enter name: ")
.expect_respond("John", "Hello, John!\n> ");
let transport = MockTransport::from_scenario(&scenario);
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let result = session.expect("Enter name:").await;
assert!(result.is_ok());
let send_result = session.send_line("John").await;
assert!(send_result.is_ok());
let result = session.expect("Hello, John").await;
assert!(result.is_ok());
}
#[tokio::test]
async fn buffer_operations() {
let transport = simple_mock("First line\nSecond line\n");
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let _ = session.expect("First").await;
let buffer = session.buffer();
assert!(
buffer.contains("line") || buffer.contains("Second"),
"Buffer: {buffer}"
);
session.clear_buffer();
assert!(
session.buffer().is_empty() || session.buffer().len() < buffer.len(),
"Buffer should be cleared or smaller"
);
}
#[tokio::test]
async fn send_control_chars() {
let transport = simple_mock("Ready\n");
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
assert!(session.send_control(ControlChar::CtrlC).await.is_ok());
assert!(session.send_control(ControlChar::CtrlD).await.is_ok());
assert!(session.send_control(ControlChar::CtrlZ).await.is_ok());
}
#[tokio::test]
async fn pattern_context() {
let transport = simple_mock("prefix[TARGET]suffix\n");
let config = config_with_timeout(Duration::from_secs(1));
let mut session = Session::new(transport, config);
let result = session.expect("TARGET").await;
assert!(result.is_ok());
let m = result.unwrap();
assert!(m.before.contains("prefix"), "Before: {}", m.before);
}
#[tokio::test]
async fn session_id_unique() {
let transport1 = simple_mock("Session 1\n");
let transport2 = simple_mock("Session 2\n");
let config = SessionConfig::default();
let session1 = Session::new(transport1, config.clone());
let session2 = Session::new(transport2, config);
assert_ne!(session1.id(), session2.id(), "Session IDs should be unique");
}
#[tokio::test]
async fn pattern_specific_timeout() {
let transport = MockBuilder::new()
.delay_ms(500) .output("Eventually appears\n")
.build();
let config = config_with_timeout(Duration::from_millis(100)); let mut session = Session::new(transport, config);
let short_result = session
.expect_timeout("Eventually", Duration::from_millis(50))
.await;
let _ = short_result;
}