use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
use crate::error::Result;
use async_trait::async_trait;
#[derive(Debug, Clone)]
pub struct GenericCommand {
command: String,
args: Vec<String>,
pub executor: CommandExecutor,
}
impl GenericCommand {
#[must_use]
pub fn new(command: impl Into<String>) -> Self {
Self {
command: command.into(),
args: Vec::new(),
executor: CommandExecutor::new(),
}
}
#[must_use]
pub fn arg(mut self, arg: impl Into<String>) -> Self {
self.args.push(arg.into());
self
}
#[must_use]
pub fn args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.args.extend(args.into_iter().map(Into::into));
self
}
fn build_args(&self) -> Vec<String> {
let mut args = vec![self.command.clone()];
args.extend(self.args.clone());
args.extend(self.executor.raw_args.clone());
args
}
}
#[async_trait]
impl DockerCommand for GenericCommand {
type Output = CommandOutput;
fn get_executor(&self) -> &CommandExecutor {
&self.executor
}
fn get_executor_mut(&mut self) -> &mut CommandExecutor {
&mut self.executor
}
fn build_command_args(&self) -> Vec<String> {
self.build_args()
}
async fn execute(&self) -> Result<Self::Output> {
let args = self.build_args();
self.execute_command(args).await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generic_command_basic() {
let cmd = GenericCommand::new("scan");
let args = cmd.build_args();
assert_eq!(args, vec!["scan"]);
}
#[test]
fn test_generic_command_with_arg() {
let cmd = GenericCommand::new("scan").arg("alpine:latest");
let args = cmd.build_args();
assert_eq!(args, vec!["scan", "alpine:latest"]);
}
#[test]
fn test_generic_command_with_multiple_args() {
let cmd = GenericCommand::new("scan")
.arg("--severity")
.arg("high")
.arg("alpine:latest");
let args = cmd.build_args();
assert_eq!(args, vec!["scan", "--severity", "high", "alpine:latest"]);
}
#[test]
fn test_generic_command_with_args_iterator() {
let cmd = GenericCommand::new("scout").args(["cves", "--format", "json", "alpine:latest"]);
let args = cmd.build_args();
assert_eq!(
args,
vec!["scout", "cves", "--format", "json", "alpine:latest"]
);
}
#[test]
fn test_generic_command_complex() {
let cmd = GenericCommand::new("trust")
.arg("inspect")
.args(["--pretty", "alpine:latest"]);
let args = cmd.build_args();
assert_eq!(args, vec!["trust", "inspect", "--pretty", "alpine:latest"]);
}
#[test]
fn test_generic_command_subcommand_with_spaces() {
let cmd = GenericCommand::new("container").args(["ls", "-a"]);
let args = cmd.build_args();
assert_eq!(args, vec!["container", "ls", "-a"]);
}
}