Skip to content

Commit ddd6227

Browse files
Merge pull request #11 from anauehara/marina2
Novo código do método popen
2 parents 06b5536 + 43fb9d7 commit ddd6227

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

src/stdlib/subprocess/process.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,56 @@ impl Processo {
168168

169169
}
170170

171+
use std::process::{ChildStdin, ChildStdout, ChildStderr};
172+
173+
/// Representa um processo em execução com acesso a stdin, stdout e stderr.
174+
pub struct PopenProcess {
175+
pub child: Child,
176+
pub stdin: Option<ChildStdin>,
177+
pub stdout: Option<ChildStdout>,
178+
pub stderr: Option<ChildStderr>,
179+
}
180+
181+
/// Executa um comando e retorna um processo com streams abertos (estilo popen)
182+
pub fn popen_command(
183+
command: Vec<String>,
184+
options: RunOptions,
185+
) -> Result<PopenProcess, SubprocessError> {
186+
if command.is_empty() {
187+
return Err(SubprocessError::InvalidArguments("Command cannot be empty".to_string()));
188+
}
189+
190+
let program = &command[0];
191+
let args = &command[1..];
192+
193+
let mut cmd = Command::new(program);
194+
cmd.args(args);
195+
cmd.stdin(Stdio::piped());
196+
197+
// Redireciona stdout/stderr para pipes conforme solicitado
198+
if options.capture_output {
199+
cmd.stdout(Stdio::piped());
200+
cmd.stderr(Stdio::piped());
201+
}
202+
203+
match cmd.spawn() {
204+
Ok(mut child) => {
205+
let stdin = child.stdin.take();
206+
let stdout = if options.capture_output { child.stdout.take() } else { None };
207+
let stderr = if options.capture_output { child.stderr.take() } else { None };
208+
209+
Ok(PopenProcess {
210+
child,
211+
stdin,
212+
stdout,
213+
stderr,
214+
})
215+
}
216+
Err(e) => Err(SubprocessError::from_io_error(e, program)),
217+
}
218+
}
219+
220+
171221

172222
#[cfg(test)]
173223
mod tests {
@@ -649,4 +699,51 @@ mod tests {
649699
let exit_code = processo.wait().expect("Falha ao esperar pelo processo");
650700
assert_eq!(exit_code, 0);
651701
}
702+
703+
use std::io::{Read, Write};
704+
705+
#[test]
706+
fn test_popen_cat_stdin_stdout() {
707+
// Comando que apenas reflete a entrada
708+
let mut process = popen_command(
709+
vec!["cat".to_string()],
710+
RunOptions { shell: false, capture_output: true }
711+
).expect("Falha ao iniciar processo");
712+
713+
let input = "Mensagem via stdin\nOutra linha\n";
714+
715+
// Escreve no stdin do processo
716+
if let Some(stdin) = process.stdin.as_mut() {
717+
stdin.write_all(input.as_bytes()).expect("Falha ao escrever no stdin");
718+
}
719+
720+
// Fecha stdin para que o processo finalize (cat só sai quando stdin fecha)
721+
drop(process.stdin.take());
722+
723+
// Espera a saída do processo
724+
let output = process.child.wait_with_output().expect("Falha ao esperar processo");
725+
726+
// Verifica se a saída é igual à entrada
727+
let stdout = String::from_utf8_lossy(&output.stdout);
728+
assert_eq!(stdout, input);
729+
730+
// stderr deve estar vazio
731+
assert!(output.stderr.is_empty());
732+
assert_eq!(output.status.code().unwrap_or(-1), 0);
733+
}
734+
735+
#[test]
736+
fn test_popen_error_output() {
737+
let mut process = popen_command(
738+
vec!["ls".to_string(), "/naoexiste".to_string()],
739+
RunOptions { shell: false, capture_output: true }
740+
).expect("Falha ao iniciar processo");
741+
742+
let output = process.child.wait_with_output().unwrap();
743+
744+
assert_ne!(output.status.code().unwrap_or(-1), 0);
745+
let stderr = String::from_utf8_lossy(&output.stderr);
746+
assert!(stderr.contains("No such file") || stderr.contains("não existe"));
747+
}
748+
652749
}

0 commit comments

Comments
 (0)