Skip to content

Commit a31d350

Browse files
committed
Adição do terminate e kill
1 parent 3135447 commit a31d350

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

src/stdlib/process.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use std::process::{Child, ExitStatus};
2+
use std::io;
3+
4+
pub struct Processo {
5+
processo: Child,
6+
}
7+
8+
impl Processo {
9+
#[cfg(windows)]
10+
pub fn terminate(&mut self) -> io::Result<()> {
11+
// No Windows, .kill() já usa TerminateProcess, que é o comportamento
12+
// esperado para terminate() e kill() do Python nessa plataforma.
13+
self.processo.kill()
14+
}
15+
16+
#[cfg(not(windows))]
17+
pub fn terminate(&mut self) -> io::Result<()> {
18+
// Em sistemas POSIX (Linux, macOS), precisamos enviar SIGTERM manualmente.
19+
// O .kill() padrão do Rust enviaria SIGKILL, que é muito agressivo.
20+
21+
// 1. Pega o PID (Process ID) do processo filho.
22+
let pid = Pid::from_raw(self.processo.id() as i32);
23+
24+
// 2. Envia o sinal SIGTERM para o PID.
25+
match signal::kill(pid, Signal::SIGTERM) {
26+
Ok(_) => Ok(()),
27+
Err(e) => {
28+
// 3. Converte o erro da crate 'nix' para um erro padrão 'std::io::Error'.
29+
Err(io::Error::new(io::ErrorKind::Other, e))
30+
}
31+
}
32+
33+
}
34+
#[cfg(test)]
35+
mod tests {
36+
use super::*; // Importa tudo do módulo pai (Processo, etc.)
37+
use std::thread;
38+
use std::time::Duration;
39+
40+
#[test]
41+
fn test_process_creation_and_wait_success() {
42+
// Testa o caso mais básico: criar um processo que termina com sucesso.
43+
// O comando `sleep 0.1` é rápido e deve sair com código 0.
44+
let mut processo = Processo::new("sleep", &["0.1"]).expect("Falha ao criar processo 'sleep'");
45+
46+
let exit_code = processo.wait().expect("Falha ao esperar pelo processo");
47+
48+
// Assert: Verificamos se o código de saída é 0 (sucesso).
49+
assert_eq!(exit_code, 0);
50+
}
51+
52+
#[test]
53+
fn test_process_creation_fails_for_invalid_command() {
54+
// Testa se a criação falha quando o comando não existe.
55+
let resultado = Processo::new("comando_que_definitivamente_nao_existe_123", &[]);
56+
57+
// Assert: Verificamos que o resultado é um erro.
58+
assert!(resultado.is_err());
59+
}
60+
61+
#[test]
62+
fn test_terminate_long_running_process() {
63+
// 1. SETUP: Inicia um processo que demoraria muito para terminar sozinho.
64+
let mut processo = Processo::new("sleep", &["30"]).expect("Falha ao criar processo 'sleep 30'");
65+
// Dá um tempinho para o SO realmente iniciar o processo.
66+
thread::sleep(Duration::from_millis(100));
67+
68+
// 2. ACTION: Chama o método que queremos testar.
69+
processo.terminate().expect("Falha ao enviar sinal de terminate");
70+
71+
// 3. ASSERT: Verifica o resultado.
72+
let exit_code = processo.wait().expect("Falha ao esperar pelo processo terminado");
73+
74+
#[cfg(not(windows))]
75+
{
76+
// Em Linux/macOS, um processo terminado por sinal não tem um código de saída.
77+
// Nossa função wait() converte isso para -1. Esta é a verificação correta!
78+
assert_eq!(exit_code, -1, "Em POSIX, o código de saída de um processo terminado por sinal deve ser -1 (na nossa implementação)");
79+
}
80+
#[cfg(windows)]
81+
{
82+
// No Windows, TerminateProcess força um código de saída, que geralmente é 1.
83+
assert_eq!(exit_code, 1, "No Windows, o código de saída de um processo terminado geralmente é 1");
84+
}
85+
}
86+
87+
#[test]
88+
fn test_kill_long_running_process() {
89+
// O teste para kill() é quase idêntico ao de terminate(),
90+
// pois ambos resultam em um encerramento anormal.
91+
92+
// 1. SETUP
93+
let mut processo = Processo::new("sleep", &["30"]).expect("Falha ao criar processo 'sleep 30'");
94+
thread::sleep(Duration::from_millis(100));
95+
96+
// 2. ACTION
97+
processo.kill().expect("Falha ao enviar sinal de kill");
98+
99+
// 3. ASSERT
100+
let exit_code = processo.wait().expect("Falha ao esperar pelo processo morto");
101+
102+
#[cfg(not(windows))]
103+
{
104+
// SIGKILL também resulta em um código de saída "None", que mapeamos para -1.
105+
assert_eq!(exit_code, -1, "Em POSIX, o código de saída de um processo morto por sinal deve ser -1");
106+
}
107+
#[cfg(windows)]
108+
{
109+
// O comportamento é o mesmo de terminate() no Windows.
110+
assert_eq!(exit_code, 1, "No Windows, o código de saída de um processo morto geralmente é 1");
111+
}
112+
}
113+
}
114+
115+
}

0 commit comments

Comments
 (0)