#[cfg(test)]
mod tests {
use super::super::bridge::*;
use super::super::command::*;
use super::super::executor::{CommandResult, CommandStatus, UnifiedCommandExecutor};
use super::super::output::{OutputProcessor, ProcessOutput, ProcessedOutput};
use super::super::process::ProcessManager;
use super::super::{ExecutionContext, ExecutionResult};
use anyhow::Result;
use async_trait::async_trait;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
fn create_test_bridge(_should_succeed: bool, _output: &str) -> LegacyExecutorBridge {
let resource_monitor = Arc::new(super::super::executor::ResourceMonitor);
let process_manager = Arc::new(ProcessManager::new());
let output_processor = Arc::new(OutputProcessor::new());
let observability = Arc::new(super::super::bridge::NoOpObservability);
let unified_executor = Arc::new(UnifiedCommandExecutor::new(
process_manager,
output_processor,
observability,
resource_monitor,
));
LegacyExecutorBridge::new(unified_executor)
}
#[tokio::test]
async fn test_legacy_context_conversion() {
let legacy_context = ExecutionContext {
working_directory: PathBuf::from("/test"),
env_vars: HashMap::from([("KEY".to_string(), "VALUE".to_string())]),
capture_output: true,
timeout_seconds: Some(30),
stdin: Some("input".to_string()),
capture_streaming: false,
streaming_config: None,
};
let unified_context = LegacyExecutorBridge::to_unified_context(&legacy_context);
assert_eq!(unified_context.working_dir, PathBuf::from("/test"));
assert_eq!(
unified_context.env_vars.get("KEY"),
Some(&"VALUE".to_string())
);
assert!(unified_context.capture_output);
assert_eq!(unified_context.timeout, Some(Duration::from_secs(30)));
assert_eq!(unified_context.stdin, Some("input".to_string()));
}
#[tokio::test]
async fn test_unified_result_conversion() {
let unified_result = CommandResult {
command_id: "test".to_string(),
command_spec: CommandSpec::Shell {
command: "test".to_string(),
shell: None,
working_dir: None,
env: None,
},
status: CommandStatus::Success,
output: ProcessedOutput {
content: ProcessOutput::new()
.with_stdout("stdout content".to_string())
.with_stderr("stderr content".to_string()),
format: OutputFormat::PlainText,
processing_duration: Duration::from_secs(0),
warnings: Vec::new(),
},
execution_time: Duration::from_secs(1),
resource_usage: super::super::executor::ResourceUsage::default(),
exit_code: Some(0),
error: None,
validation_result: None,
metadata: super::super::executor::ExecutionMetadata::new(),
};
let legacy_result = LegacyExecutorBridge::from_unified_result(unified_result);
assert!(legacy_result.success);
assert_eq!(legacy_result.stdout, "stdout content");
assert_eq!(legacy_result.stderr, "stderr content");
assert_eq!(legacy_result.exit_code, Some(0));
}
#[tokio::test]
async fn test_unified_result_conversion_failure() {
let unified_result = CommandResult {
command_id: "test".to_string(),
command_spec: CommandSpec::Shell {
command: "test".to_string(),
shell: None,
working_dir: None,
env: None,
},
status: CommandStatus::Failed {
reason: super::super::executor::FailureReason::NonZeroExit(1),
retryable: false,
},
output: ProcessedOutput {
content: ProcessOutput::new()
.with_stdout("stdout".to_string())
.with_stderr("error message".to_string()),
format: OutputFormat::PlainText,
processing_duration: Duration::from_secs(0),
warnings: Vec::new(),
},
execution_time: Duration::from_secs(1),
resource_usage: super::super::executor::ResourceUsage::default(),
exit_code: Some(1),
error: None,
validation_result: None,
metadata: super::super::executor::ExecutionMetadata::new(),
};
let legacy_result = LegacyExecutorBridge::from_unified_result(unified_result);
assert!(!legacy_result.success);
assert_eq!(legacy_result.stderr, "error message");
assert_eq!(legacy_result.exit_code, Some(1));
}
#[test]
fn test_no_op_observability() {
let _observability = super::super::bridge::NoOpObservability;
assert!(std::mem::size_of::<super::super::bridge::NoOpObservability>() == 0);
}
#[tokio::test]
async fn test_no_op_observability_methods() {
let observability = super::super::bridge::NoOpObservability;
let context = super::super::executor::ExecutionContextInternal {
id: uuid::Uuid::new_v4(),
request: CommandRequest {
spec: CommandSpec::Shell {
command: "test".to_string(),
shell: None,
working_dir: None,
env: None,
},
execution_config: ExecutionConfig::default(),
context: super::super::command::ExecutionContext::default(),
metadata: CommandMetadata::new("test"),
},
resource_limits: None,
};
use super::super::executor::ObservabilityCollector;
observability.record_command_start(&context).await;
let result: Result<CommandResult> = Ok(CommandResult {
command_id: "test".to_string(),
command_spec: CommandSpec::Shell {
command: "test".to_string(),
shell: None,
working_dir: None,
env: None,
},
status: CommandStatus::Success,
output: ProcessedOutput {
content: ProcessOutput::empty(),
format: OutputFormat::PlainText,
processing_duration: Duration::from_secs(0),
warnings: Vec::new(),
},
execution_time: Duration::from_secs(1),
resource_usage: super::super::executor::ResourceUsage::default(),
exit_code: Some(0),
error: None,
validation_result: None,
metadata: super::super::executor::ExecutionMetadata::new(),
});
observability.record_command_complete(&result).await;
}
#[test]
fn test_create_legacy_executor() {
struct MockRunner;
#[async_trait]
impl super::super::runner::CommandRunner for MockRunner {
async fn run_command(
&self,
_cmd: &str,
_args: &[String],
) -> Result<std::process::Output> {
Ok(std::process::Command::new("echo")
.arg("test")
.output()
.unwrap())
}
async fn run_with_context(
&self,
_cmd: &str,
_args: &[String],
_context: &ExecutionContext,
) -> Result<ExecutionResult> {
Ok(ExecutionResult {
success: true,
stdout: "test output".to_string(),
stderr: String::new(),
exit_code: Some(0),
metadata: HashMap::new(),
})
}
}
let runner = MockRunner;
let _executor = create_legacy_executor(runner);
}
#[tokio::test]
async fn test_command_request_creation_for_claude() {
let _bridge = create_test_bridge(true, "test output");
let _command = "test command";
let _project_path = Path::new("/test/project");
let _env_vars = HashMap::from([
("KEY1".to_string(), "VALUE1".to_string()),
("KEY2".to_string(), "VALUE2".to_string()),
]);
assert!(std::mem::size_of::<LegacyExecutorBridge>() > 0);
}
#[tokio::test]
async fn test_shell_command_detection() {
let _context = ExecutionContext {
working_directory: PathBuf::from("/test"),
env_vars: HashMap::new(),
capture_output: true,
timeout_seconds: None,
stdin: None,
capture_streaming: false,
streaming_config: None,
};
let is_claude = "claude" == "claude";
assert!(is_claude);
let is_not_claude = "echo" == "claude";
assert!(!is_not_claude);
}
#[test]
fn test_capture_output_mode_conversion() {
let capture_true = if true {
CaptureOutputMode::Both
} else {
CaptureOutputMode::None
};
assert!(matches!(capture_true, CaptureOutputMode::Both));
let capture_false = if false {
CaptureOutputMode::Both
} else {
CaptureOutputMode::None
};
assert!(matches!(capture_false, CaptureOutputMode::None));
}
#[test]
fn test_command_metadata_creation() {
let metadata = CommandMetadata::new("test_type");
assert_eq!(metadata.tags.get("type"), Some(&"test_type".to_string()));
assert!(!metadata.command_id.is_empty());
}
}