use std::iter::{Iterator, range};
use std::ptr;
use libc;
use super::{CStr, CStrBuf, OwnedCString};
use super::{from_static_bytes, libc_free, parse_c_multistring};
pub fn check_c_str(c_str: &CStr, expected: &[u8]) {
let buf = c_str.as_ptr();
let len = expected.len();
for i in range(0, len) {
let byte = unsafe { *buf.offset(i as isize) as u8 };
assert_eq!(byte, expected[i]);
}
let term = unsafe { *buf.offset(len as isize) as u8 };
assert_eq!(term, 0);
}
unsafe fn bytes_dup_raw(s: &[u8]) -> *const libc::c_char {
let len = s.len();
let dup = libc::malloc((len + 1) as libc::size_t) as *mut u8;
ptr::copy_nonoverlapping_memory(dup, s.as_ptr(), len);
*dup.offset(len as isize) = 0;
dup as *const libc::c_char
}
fn bytes_dup(s: &[u8]) -> OwnedCString {
unsafe {
OwnedCString::new(bytes_dup_raw(s), libc_free)
}
}
fn str_dup(s: &str) -> OwnedCString {
bytes_dup(s.as_bytes())
}
#[test]
fn test_parse_c_multistring() {
unsafe {
let input = b"zero\0one\0\0";
let ptr = input.as_ptr();
let expected = ["zero", "one"];
let mut it = expected.iter();
let result = parse_c_multistring(ptr as *const libc::c_char, None,
|cbytes| {
assert_eq!(cbytes, it.next().unwrap().as_bytes());
});
assert_eq!(result, 2);
assert!(it.next().is_none());
}
}
#[test]
fn test_c_str_macro() {
let c_str = c_str!("hello");
check_c_str(c_str, b"hello");
}
#[test]
fn test_owned_c_string_deref() {
let c_str = str_dup("hello");
check_c_str(&*c_str, b"hello");
}
#[test]
fn test_owned_c_string_as_ptr() {
let c_str = str_dup("hello");
let len = unsafe { libc::strlen(c_str.as_ptr()) };
assert_eq!(len, 5);
}
#[test]
fn test_iterator() {
let c_string = str_dup("");
let mut iter = c_string.iter();
assert_eq!(iter.next(), None);
let c_string = str_dup("hello");
let mut iter = c_string.iter();
assert_eq!(iter.next(), Some('h' as libc::c_char));
assert_eq!(iter.next(), Some('e' as libc::c_char));
assert_eq!(iter.next(), Some('l' as libc::c_char));
assert_eq!(iter.next(), Some('l' as libc::c_char));
assert_eq!(iter.next(), Some('o' as libc::c_char));
assert_eq!(iter.next(), None);
}
#[test]
fn test_parse_as_bytes() {
let c_str = str_dup("hello");
let bytes = unsafe { super::parse_as_bytes(c_str.ptr, &c_str) };
assert_eq!(bytes, b"hello");
let c_str = str_dup("");
let bytes = unsafe { super::parse_as_bytes(c_str.ptr, &c_str) };
assert_eq!(bytes, b"");
let c_str = bytes_dup(b"foo\xFF");
let bytes = unsafe { super::parse_as_bytes(c_str.ptr, &c_str) };
assert_eq!(bytes, b"foo\xFF");
}
#[test]
fn test_parse_as_utf8() {
let c_str = str_dup("hello");
let res = unsafe { super::parse_as_utf8(c_str.ptr, &c_str) };
assert_eq!(res, Ok("hello"));
let c_str = str_dup("");
let res = unsafe { super::parse_as_utf8(c_str.ptr, &c_str) };
assert_eq!(res, Ok(""));
let c_str = bytes_dup(b"foo\xFF");
let res = unsafe { super::parse_as_utf8(c_str.ptr, &c_str) };
assert!(res.is_err());
}
#[test]
fn test_c_str_buf_from_bytes() {
let c_str = CStrBuf::from_bytes(b"").unwrap();
check_c_str(&*c_str, b"");
let c_str = CStrBuf::from_bytes(b"foo\xFF").unwrap();
check_c_str(&*c_str, b"foo\xFF");
let c_str = CStrBuf::from_bytes(b"Mary had a little \xD0\x0D, Little \xD0\x0D").unwrap();
check_c_str(&*c_str, b"Mary had a little \xD0\x0D, Little \xD0\x0D");
let res = CStrBuf::from_bytes(b"got\0nul");
let err = res.err().unwrap();
assert_eq!(err.position, 3);
}
#[test]
fn test_c_str_buf_from_str() {
let c_str = CStrBuf::from_str("").unwrap();
check_c_str(&*c_str, b"");
let c_str = CStrBuf::from_str("hello").unwrap();
check_c_str(&*c_str, b"hello");
let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
check_c_str(&*c_str, b"Mary had a little lamb, Little lamb");
let res = CStrBuf::from_str("got\0nul");
let err = res.err().unwrap();
assert_eq!(err.position, 3);
}
#[test]
fn test_c_str_buf_from_vec() {
let c_str = CStrBuf::from_vec(b"".to_vec()).unwrap();
check_c_str(&*c_str, b"");
let c_str = CStrBuf::from_vec(b"hello".to_vec()).unwrap();
check_c_str(&*c_str, b"hello");
let c_str = CStrBuf::from_vec(b"Mary had a little lamb, Little lamb".to_vec()).unwrap();
check_c_str(&*c_str, b"Mary had a little lamb, Little lamb");
let res = CStrBuf::from_vec(b"got\0nul".to_vec());
let err = res.err().unwrap();
assert_eq!(err.nul_error().position, 3);
let vec = err.into_bytes();
assert_eq!(vec.as_slice(), b"got\0nul");
}
#[test]
fn test_c_str_buf_into_vec() {
let c_str = CStrBuf::from_str("").unwrap();
let vec = c_str.into_vec();
assert_eq!(vec.as_slice(), b"");
let c_str = CStrBuf::from_str("hello").unwrap();
let vec = c_str.into_vec();
assert_eq!(vec.as_slice(), b"hello");
let c_str = CStrBuf::from_bytes(b"foo\xFF").unwrap();
let vec = c_str.into_vec();
assert_eq!(vec.as_slice(), b"foo\xFF");
let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
let vec = c_str.into_vec();
assert_eq!(vec.as_slice(), b"Mary had a little lamb, Little lamb");
let c_str = CStrBuf::from_bytes(b"Mary had a little \xD0\x0D, Little \xD0\x0D").unwrap();
let vec = c_str.into_vec();
assert_eq!(vec.as_slice(), b"Mary had a little \xD0\x0D, Little \xD0\x0D");
}
#[test]
fn test_c_str_is_empty() {
let c_str = CStrBuf::from_str("").unwrap();
assert!(c_str.is_empty());
}
#[test]
fn test_owned_c_string_parse_as_bytes() {
let c_str = str_dup("hello");
assert_eq!(c_str.parse_as_bytes(), b"hello");
let c_str = str_dup("");
assert_eq!(c_str.parse_as_bytes(), b"");
let c_str = bytes_dup(b"foo\xFF");
assert_eq!(c_str.parse_as_bytes(), b"foo\xFF");
}
#[test]
fn test_owned_c_string_parse_as_utf8() {
let c_str = str_dup("hello");
assert_eq!(c_str.parse_as_utf8(), Ok("hello"));
let c_str = str_dup("");
assert_eq!(c_str.parse_as_utf8(), Ok(""));
let c_str = bytes_dup(b"foo\xFF");
assert!(c_str.parse_as_utf8().is_err());
}
#[test]
fn test_c_str_debug() {
let c_str = c_str!("hello");
let msg = format!("{:?}", c_str);
assert_eq!(msg, "\"hello\"");
let c_str = c_str!("");
let msg = format!("{:?}", c_str);
assert_eq!(msg, "\"\"");
let c_str = from_static_bytes(b"foo\xFF\0");
let msg = format!("{:?}", c_str);
assert_eq!(msg, r#""foo\xff""#);
}
#[test]
fn test_owned_c_string_debug() {
let c_str = str_dup("hello");
let msg = format!("{:?}", c_str);
assert_eq!(msg, "\"hello\"");
let c_str = str_dup("");
let msg = format!("{:?}", c_str);
assert_eq!(msg, "\"\"");
let c_str = bytes_dup(b"foo\xFF");
let msg = format!("{:?}", c_str);
assert_eq!(msg, r#""foo\xff""#);
}
#[test]
#[should_fail]
fn test_parse_null_as_bytes_fail() {
unsafe {
let p: *const libc::c_char = ptr::null();
let _ = super::parse_as_bytes(p, &p);
};
}
#[test]
#[should_fail]
fn test_parse_null_as_utf8_fail() {
unsafe {
let p: *const libc::c_char = ptr::null();
let _ = super::parse_as_utf8(p, &p);
};
}
#[test]
#[should_fail]
fn test_c_string_new_fail() {
let _c_str: OwnedCString = unsafe {
OwnedCString::new(ptr::null(), libc_free)
};
}
#[test]
#[should_fail]
fn test_from_static_bytes_fail() {
let _c_str = super::from_static_bytes(b"no nul");
}
#[test]
#[should_fail]
fn test_from_static_str_fail() {
let _c_str = super::from_static_str("no nul");
}
#[test]
#[should_fail]
fn test_from_raw_ptr_fail() {
let p: *const libc::c_char = ptr::null();
let _c_str = unsafe { super::from_raw_ptr(p, &p) };
}