use crate::state::FileDescriptorTable;
use std::fs::File;
use std::os::fd::AsRawFd;
use std::sync::Mutex;
static FILE_LOCK: Mutex<()> = Mutex::new(());
#[test]
fn test_fd_table_creation() {
let fd_table = FileDescriptorTable::new();
assert!(!fd_table.is_open(0));
assert!(!fd_table.is_open(1));
assert!(!fd_table.is_open(2));
}
#[test]
fn test_fd_table_open_file() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_open.txt";
std::fs::write(temp_file, "test content").unwrap();
let result = fd_table.open_fd(3, temp_file, true, false, false, false, false);
assert!(result.is_ok());
assert!(fd_table.is_open(3));
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_open_file_for_writing() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_write.txt";
let result = fd_table.open_fd(4, temp_file, false, true, false, true, false);
assert!(result.is_ok());
assert!(fd_table.is_open(4));
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_invalid_fd_number() {
let mut fd_table = FileDescriptorTable::new();
let result = fd_table.open_fd(-1, "/tmp/test.txt", true, false, false, false, false);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Invalid file descriptor"));
let result = fd_table.open_fd(1025, "/tmp/test.txt", true, false, false, false, false);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Invalid file descriptor"));
}
#[test]
fn test_fd_table_duplicate_fd() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_dup.txt";
std::fs::write(temp_file, "test content").unwrap();
fd_table
.open_fd(3, temp_file, true, false, false, false, false)
.unwrap();
assert!(fd_table.is_open(3));
let result = fd_table.duplicate_fd(3, 4);
assert!(result.is_ok());
assert!(fd_table.is_open(4));
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_duplicate_to_self() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_dup_self.txt";
std::fs::write(temp_file, "test content").unwrap();
fd_table
.open_fd(3, temp_file, true, false, false, false, false)
.unwrap();
let result = fd_table.duplicate_fd(3, 3);
assert!(result.is_ok());
assert!(fd_table.is_open(3));
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_duplicate_closed_fd() {
let mut fd_table = FileDescriptorTable::new();
let result = fd_table.duplicate_fd(3, 4);
assert!(result.is_err());
assert!(result.unwrap_err().contains("not open"));
}
#[test]
fn test_fd_table_close_fd() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_close.txt";
std::fs::write(temp_file, "test content").unwrap();
fd_table
.open_fd(3, temp_file, true, false, false, false, false)
.unwrap();
assert!(fd_table.is_open(3));
let result = fd_table.close_fd(3);
assert!(result.is_ok());
assert!(fd_table.is_closed(3));
assert!(!fd_table.is_open(3));
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_save_and_restore() {
let mut fd_table = FileDescriptorTable::new();
let result = fd_table.save_fd(0);
assert!(result.is_ok());
let result = fd_table.restore_fd(0);
assert!(result.is_ok());
}
#[test]
fn test_fd_table_save_all_and_restore_all() {
let _lock = FILE_LOCK.lock().unwrap();
let mut fd_table = FileDescriptorTable::new();
use std::time::{SystemTime, UNIX_EPOCH};
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let temp_file1 = format!("/tmp/rush_test_fd_save1_{}.txt", timestamp);
let temp_file2 = format!("/tmp/rush_test_fd_save2_{}.txt", timestamp);
std::fs::write(&temp_file1, "test content 1").unwrap();
std::fs::write(&temp_file2, "test content 2").unwrap();
let f1 = File::open(&temp_file1).unwrap();
let f2 = File::open(&temp_file2).unwrap();
unsafe {
libc::dup2(f1.as_raw_fd(), 50);
libc::dup2(f2.as_raw_fd(), 51);
}
fd_table
.open_fd(50, &temp_file1, true, false, false, false, false)
.unwrap();
fd_table
.open_fd(51, &temp_file2, true, false, false, false, false)
.unwrap();
let result = fd_table.save_all_fds();
assert!(result.is_ok());
let result = fd_table.restore_all_fds();
assert!(result.is_ok());
unsafe {
libc::close(50);
libc::close(51);
}
let _ = std::fs::remove_file(&temp_file1);
let _ = std::fs::remove_file(&temp_file2);
}
#[test]
fn test_fd_table_clear() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_clear.txt";
std::fs::write(temp_file, "test content").unwrap();
fd_table
.open_fd(50, temp_file, true, false, false, false, false)
.unwrap();
assert!(fd_table.is_open(50));
fd_table.clear();
assert!(!fd_table.is_open(3));
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_get_stdio() {
let mut fd_table = FileDescriptorTable::new();
let temp_file = "/tmp/rush_test_fd_stdio.txt";
std::fs::write(temp_file, "test content").unwrap();
fd_table
.open_fd(3, temp_file, true, false, false, false, false)
.unwrap();
let stdio = fd_table.get_stdio(3);
assert!(stdio.is_some());
let stdio = fd_table.get_stdio(5);
assert!(stdio.is_none());
let _ = std::fs::remove_file(temp_file);
}
#[test]
fn test_fd_table_multiple_operations() {
let mut fd_table = FileDescriptorTable::new();
let temp_file1 = "/tmp/rush_test_fd_multi1.txt";
let temp_file2 = "/tmp/rush_test_fd_multi2.txt";
std::fs::write(temp_file1, "test content 1").unwrap();
std::fs::write(temp_file2, "test content 2").unwrap();
fd_table
.open_fd(3, temp_file1, true, false, false, false, false)
.unwrap();
assert!(fd_table.is_open(3));
fd_table.duplicate_fd(3, 4).unwrap();
assert!(fd_table.is_open(4));
fd_table
.open_fd(5, temp_file2, true, false, false, false, false)
.unwrap();
assert!(fd_table.is_open(5));
fd_table.close_fd(4).unwrap();
assert!(fd_table.is_closed(4));
assert!(!fd_table.is_open(4));
assert!(fd_table.is_open(3));
assert!(fd_table.is_open(5));
let _ = std::fs::remove_file(temp_file1);
let _ = std::fs::remove_file(temp_file2);
}
#[test]
fn test_shell_state_has_fd_table() {
use crate::state::ShellState;
let state = ShellState::new();
let fd_table = state.fd_table.borrow();
assert!(!fd_table.is_open(3));
}
#[test]
fn test_shell_state_fd_table_operations() {
use crate::state::ShellState;
let state = ShellState::new();
let temp_file = "/tmp/rush_test_state_fd.txt";
std::fs::write(temp_file, "test content").unwrap();
{
let mut fd_table = state.fd_table.borrow_mut();
fd_table
.open_fd(3, temp_file, true, false, false, false, false)
.unwrap();
}
{
let fd_table = state.fd_table.borrow();
assert!(fd_table.is_open(3));
}
let _ = std::fs::remove_file(temp_file);
}