diff options
author | Carl Lerche <me@carllerche.com> | 2015-02-21 14:33:27 -0800 |
---|---|---|
committer | Carl Lerche <me@carllerche.com> | 2015-02-21 14:33:27 -0800 |
commit | 60ccee778b2adca488706c586bd61c5affa90de3 (patch) | |
tree | d8738241a4e5fa8fe02331f33ab190b980d507fd /test | |
parent | b2454c9d793dfeb946d5e12f51ad571d32fa9987 (diff) | |
download | nix-60ccee778b2adca488706c586bd61c5affa90de3.zip |
Cleanup readv & writev + tests
Diffstat (limited to 'test')
-rw-r--r-- | test/sys/mod.rs | 1 | ||||
-rw-r--r-- | test/sys/test_termios.rs | 21 | ||||
-rw-r--r-- | test/sys/test_uio.rs | 89 | ||||
-rw-r--r-- | test/test.rs | 31 | ||||
-rw-r--r-- | test/test_stat.rs | 31 | ||||
-rw-r--r-- | test/test_unistd.rs | 65 |
6 files changed, 238 insertions, 0 deletions
diff --git a/test/sys/mod.rs b/test/sys/mod.rs new file mode 100644 index 00000000..5b368f36 --- /dev/null +++ b/test/sys/mod.rs @@ -0,0 +1 @@ +mod test_termios; diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs new file mode 100644 index 00000000..24ce3434 --- /dev/null +++ b/test/sys/test_termios.rs @@ -0,0 +1,21 @@ +use nix::errno::Errno; +use nix::sys::termios; +use nix::{NixError, unistd}; + +#[test] +fn test_tcgetattr() { + for fd in 0..5 { + let termios = termios::tcgetattr(fd); + match unistd::isatty(fd) { + // If `fd` is a TTY, tcgetattr must succeed. + Ok(true) => assert!(termios.is_ok()), + // If it's an invalid file descriptor, tcgetattr should also return + // the same error + Err(NixError::Sys(Errno::EBADF)) => { + assert!(termios.err() == Some(NixError::Sys(Errno::EBADF))); + }, + // Otherwise it should return any error + _ => assert!(termios.is_err()) + } + } +} diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs new file mode 100644 index 00000000..3f28c329 --- /dev/null +++ b/test/sys/test_uio.rs @@ -0,0 +1,89 @@ +use nix::sys::uio::*; + +#[test] +fn test_writev() { + let mut to_write = Vec::with_capacity(16 * 128); + for _ in 0..16 { + let s: String = thread_rng().gen_ascii_chars().take(128).collect(); + let b = s.as_bytes(); + to_write.extend(b.iter().map(|x| x.clone())); + } + // Allocate and fill iovecs + let mut iovecs = Vec::new(); + let mut consumed = 0; + while consumed < to_write.len() { + let left = to_write.len() - consumed; + let slice_len = if left < 64 { left } else { thread_rng().gen_range(64, min(256, left)) }; + let b = &to_write[consumed..consumed+slice_len]; + iovecs.push(IoVec::from_slice(b)); + consumed += slice_len; + } + let pipe_res = pipe(); + assert!(pipe_res.is_ok()); + let (reader, writer) = pipe_res.ok().unwrap(); + // FileDesc will close its filedesc (reader). + let mut read_buf: Vec<u8> = repeat(0u8).take(128 * 16).collect(); + // Blocking io, should write all data. + let write_res = writev(writer, iovecs.as_slice()); + // Successful write + assert!(write_res.is_ok()); + let written = write_res.ok().unwrap(); + // Check whether we written all data + assert_eq!(to_write.len(), written); + let read_res = read(reader, read_buf.as_mut_slice()); + // Successful read + assert!(read_res.is_ok()); + let read = read_res.ok().unwrap() as usize; + // Check we have read as much as we written + assert_eq!(read, written); + // Check equality of written and read data + assert_eq!(to_write.as_slice(), read_buf.as_slice()); + let close_res = close(writer); + assert!(close_res.is_ok()); + let close_res = close(reader); + assert!(close_res.is_ok()); +} + +#[test] +fn test_readv() { + let s:String = thread_rng().gen_ascii_chars().take(128).collect(); + let to_write = s.as_bytes().to_vec(); + let mut storage = Vec::new(); + let mut allocated = 0; + while allocated < to_write.len() { + let left = to_write.len() - allocated; + let vec_len = if left < 64 { left } else { thread_rng().gen_range(64, min(256, left)) }; + let v: Vec<u8> = repeat(0u8).take(vec_len).collect(); + storage.push(v); + allocated += vec_len; + } + let mut iovecs = Vec::with_capacity(storage.len()); + for v in storage.iter_mut() { + iovecs.push(IoVec::from_mut_slice(v.as_mut_slice())); + } + let pipe_res = pipe(); + assert!(pipe_res.is_ok()); + let (reader, writer) = pipe_res.ok().unwrap(); + // Blocking io, should write all data. + let write_res = write(writer, to_write.as_slice()); + // Successful write + assert!(write_res.is_ok()); + let read_res = readv(reader, iovecs.as_mut_slice()); + assert!(read_res.is_ok()); + let read = read_res.ok().unwrap(); + // Check whether we've read all data + assert_eq!(to_write.len(), read); + // Cccumulate data from iovecs + let mut read_buf = Vec::with_capacity(to_write.len()); + for iovec in iovecs.iter() { + read_buf.extend(iovec.as_slice().iter().map(|x| x.clone())); + } + // Check whether iovecs contain all written data + assert_eq!(read_buf.len(), to_write.len()); + // Check equality of written and read data + assert_eq!(read_buf.as_slice(), to_write.as_slice()); + let close_res = close(reader); + assert!(close_res.is_ok()); + let close_res = close(writer); + assert!(close_res.is_ok()); +} diff --git a/test/test.rs b/test/test.rs new file mode 100644 index 00000000..1148adcf --- /dev/null +++ b/test/test.rs @@ -0,0 +1,31 @@ +#![feature(core, libc, std_misc)] + +extern crate nix; +extern crate libc; +extern crate rand; + +mod sys; +mod test_stat; +mod test_unistd; + +use nix::NixPath; + +#[test] +fn test_nix_path() { + fn cstr_to_bytes(cstr: &*const libc::c_char, len: usize) -> &[u8] { + unsafe { + let cstr = cstr as *const _ as *const *const u8; + std::slice::from_raw_parts(*cstr, len) + } + } + + let bytes = b"abcd"; + let ok = bytes.with_nix_path(|cstr| { + assert_eq!(b"abcd\0", cstr_to_bytes(&cstr, 5)); + }); + assert!(ok.is_ok()); + + let bytes = b"ab\0cd"; + let err = bytes.with_nix_path(|_| {}); + assert!(err.is_err()); +} diff --git a/test/test_stat.rs b/test/test_stat.rs new file mode 100644 index 00000000..ac4a8f08 --- /dev/null +++ b/test/test_stat.rs @@ -0,0 +1,31 @@ +use nix::sys::stat::stat; + +#[test] +fn test_stat() { + use nix::fcntl::open; + use nix::unistd::{close, unlink}; + use nix::fcntl::O_CREAT; + use nix::sys::stat::S_IWUSR; + + let filename = b"target/foo.txt"; + let fd_res = open(filename, O_CREAT, S_IWUSR).unwrap(); + close(fd_res).unwrap(); //.ok().unwrap()); // close right here. We use the file only for the stat test + let stat_result = stat(filename); + + match stat_result { + Ok(stats) => { + assert!(stats.st_dev > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_ino > 0); // inode is positive integer, exact number machine dependent + assert!(stats.st_mode > 0); // must be positive integer + assert!(stats.st_nlink == 1); // there links created, must be 1 + assert!(stats.st_uid > 0); // must be positive integer + assert!(stats.st_gid > 0); // must be positive integer + assert!(stats.st_rdev == 0); // no special device + assert!(stats.st_size == 0); // size is 0 because we did not write anything to the file + assert!(stats.st_blksize > 0); // must be positive integer, exact number machine dependent + assert!(stats.st_blocks == 0); // no blocks allocated because file size is 0 + } + Err(_) => panic!("stat call failed") // if stats system call fails, something is seriously wrong on that machine + } + unlink(filename).unwrap(); +} diff --git a/test/test_unistd.rs b/test/test_unistd.rs new file mode 100644 index 00000000..c648cdeb --- /dev/null +++ b/test/test_unistd.rs @@ -0,0 +1,65 @@ +use nix::unistd::*; +use nix::unistd::Fork::*; +use nix::sys::wait::*; +use std::ffi::CString; + +#[test] +fn test_fork_and_waitpid() { + let pid = fork(); + match pid { + Ok(Child) => {} // ignore child here + Ok(Parent(child_pid)) => { + // assert that child was created and pid > 0 + assert!(child_pid > 0); + let wait_status = waitpid(child_pid, None); + match wait_status { + // assert that waitpid returned correct status and the pid is the one of the child + Ok(WaitStatus::Exited(pid_t)) => assert!(pid_t == child_pid), + + // panic, must never happen + Ok(WaitStatus::StillAlive) => panic!("Child still alive, should never happen"), + + // panic, waitpid should never fail + Err(_) => panic!("Error: waitpid Failed") + } + + }, + // panic, fork should never fail unless there is a serious problem with the OS + Err(_) => panic!("Error: Fork Failed") + } +} + +#[test] +fn test_execve() { + // The `exec`d process will write to `writer`, and we'll read that + // data from `reader`. + let (reader, writer) = pipe().unwrap(); + + match fork().unwrap() { + Child => { + // Close stdout. + close(1).unwrap(); + // Make `writer` be the stdout of the new process. + dup(writer).unwrap(); + // exec! + execve(&CString::new(b"/bin/sh").unwrap(), + &[CString::new(b"").unwrap(), + CString::new(b"-c").unwrap(), + CString::new(b"echo nix!!! && env").unwrap()], + &[CString::new(b"foo=bar").unwrap(), + CString::new(b"baz=quux").unwrap()]).unwrap(); + }, + Parent(child_pid) => { + // Wait for the child to exit. + waitpid(child_pid, None).unwrap(); + // Read 1024 bytes. + let mut buf = [0u8; 1024]; + read(reader, &mut buf).unwrap(); + // It should contain the things we printed using `/bin/sh`. + let string = String::from_utf8_lossy(&buf); + assert!(string.contains("nix!!!")); + assert!(string.contains("foo=bar")); + assert!(string.contains("baz=quux")); + } + } +} |