summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2015-02-21 14:33:27 -0800
committerCarl Lerche <me@carllerche.com>2015-02-21 14:33:27 -0800
commit60ccee778b2adca488706c586bd61c5affa90de3 (patch)
treed8738241a4e5fa8fe02331f33ab190b980d507fd /test
parentb2454c9d793dfeb946d5e12f51ad571d32fa9987 (diff)
downloadnix-60ccee778b2adca488706c586bd61c5affa90de3.zip
Cleanup readv & writev + tests
Diffstat (limited to 'test')
-rw-r--r--test/sys/mod.rs1
-rw-r--r--test/sys/test_termios.rs21
-rw-r--r--test/sys/test_uio.rs89
-rw-r--r--test/test.rs31
-rw-r--r--test/test_stat.rs31
-rw-r--r--test/test_unistd.rs65
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"));
+ }
+ }
+}